Что вам нужно, это range_difference
функция. Я думал, что Boost.Range предоставит что-то вроде этого, но я ничего не нашел в их документе (ну, я не очень тщательно искал ...), поэтому я свернул свой.
Следующая функция возвращает пару диапазона, содержащую результат разницы между диапазоном, обозначенным (first1, last1), и диапазоном, обозначенным (first2, last2). Предварительным условием является то, что first1 должен быть расположен до или в той же позиции, что и first2.
template <typename InputIterator>
std::pair<
std::pair<InputIterator, InputIterator>,
std::pair<InputIterator, InputIterator> >
range_difference(InputIterator first1, InputIterator last1,
InputIterator first2, InputIterator last2)
{
typedef std::pair<InputIterator, InputIterator> Range;
InputIterator it;
// first1 must be <= first2
for (it = first1 ; it != last1 && it != first2 ; ++it);
Range left_range = std::make_pair(first1, it); // Left range
if (it == last1)
return std::make_pair(left_range, std::make_pair(first2, first2));
// it == first2
while (it != last1 && it != last2) ++it;
return std::make_pair(left_range, std::make_pair(it, last1)); // Right range
}
Результат разницы может состоять из двух частей, если range2 полностью включен в range1. В итоге вы получаете левый диапазон и правый диапазон:
|_____________________|__________________|________________________|
first1 first2 last2 last1
В этом случае функция возвращает (first1, first2), (last2, last1).
В этой другой конфигурации
|_____________________| |________________________|
first1 last1 first2 last2
функция возвращает (first1, last1), (first2, first2). Есть много других возможных конфигураций. Однако важно знать, что в случае, когда правый диапазон пуст, он будет позиционироваться на max (first2, last1) . Вы увидите, как это необходимо в примере.
Наконец, если first1 и first2 находятся в одной и той же позиции, возвращаемый левый диапазон будет пустым, т.е. (First1, first1).
Теперь, как мы можем использовать эту функцию для решения вашей проблемы? Что ж, это довольно просто для диапазона «деактивировать», но немного сложнее для «активировать»:
typedef std::vector<Activable>::iterator Iterator;
Iterator old_beg, old_end, new_beg, new_end; // Old and new ranges
typedef std::pair<Iterator, Iterator> Range;
typedef std::pair<Range, Range> SplitRange;
SplitRange deactivate = range_difference(old_beg, old_end, new_beg, new_end);
// Left range
for (Iterator it = deactivate.first.first;
it != deactivate.first.second;
++it)
it->deactivate();
// Right range
for (Iterator it = deactivate.second.first;
it != deactivate.second.second;
++it)
it->deactivate();
SplitRange activate =
range_difference(new_beg, new_end, new_beg, deactivate.second.first);
// Note the use of the previously returned right range -------^
for (Iterator it = activate.second.first;
it != activate.second.second;
++it)
it->activate();
И вот, пожалуйста. Возможно, это решение немного излишне для вашей проблемы, но я думаю, что функция range_difference
может быть полезна во многих местах.