Iterator for all combinations of 2 ranges - c++

Is it possible to use the boost::iterators library to create iterators that show the combined results of 2 ranges? Note that for usage, we need the output to be iterators. Nor do we expect to first manually create a vector of all combinations. (Note: We compile with C++17)
A contrived example:
auto v = std::vector<int>({1,2,3});
auto s = std::set<double>({0.5, 1.5});
auto range = combineElements(v.begin(), v.end(), s.begin(), s.end(), [](int i, double d){ return std::pair{i, d}; });
for (auto [i, d] : range)
std::cout << std::to_string(i) << ',' <<std::to_string(d) << ";";
// Expected output: 1,0.5;1,1.5;2,0.5;2,1.5;3,0.5;3,1.5;
I've checked the documentation of boost::iterators and found:
Zip: This combined the nth element of the first range, with the nth of the second. However, doesn't combine nth with mth element.
Generator: The generator that needs to be provided could do manual bookkeeping keeping 6 iterators: begin, end, and current for both ranges. However, it doesn't have a way to stop it.
Function input: Similar to Generator, we could put those iterators in the state and create an end-state for the end-iterator using the end-iterators. However, the state ain't provided to the generator to calculate the value of the iterator.
Permutation: Works on a single range
Transform: Works on a single range
Am I correct to conclude that in this situation the only option is to write customer iterator by hand?

Am I correct to conclude that in this situation the only option is to write customer iterator by hand?
Pretty much yes. You might want to decompose it into an iterator adaptor that repeats each element N times, and one that repeats the whole range M times, which would allow you to zip the pair of those.
template <class Iterator>
class repeat_iterator
: public boost::iterator::iterator_adaptor< repeat_iterator<Iterator>, Iterator >
{
typedef boost::iterator::iterator_adaptor< repeat_iterator<Iterator>, Iterator > super_t;
friend class boost::iterator::iterator_core_access;
size_t len = 1;
size_t curr = 0;
public:
repeat_iterator() {}
explicit repeat_iterator(Iterator x, size_t len, curr = 0)
: super_t(x), len(len), curr(curr) {}
private:
void increment() {
if (++curr == len) {
curr = 0;
++base_reference();
}
}
void decrement() {
if (curr-- == 0) {
curr = len - 1;
--base_reference();
}
}
void advance(typename super_t::difference_type n)
{
n += curr;
base_reference() += n / len;
curr = n % len;
}
template <class OtherIterator>
typename super_t::difference_type
distance_to(unstride_iterator<OtherIterator> const& y) const
{
return ((base() - y.base()) * len) + (curr - y.curr);
}
};
template <class Iterator>
class cycle_iterator
: public boost::iterator::iterator_adaptor< cycle_iterator<Iterator>, Iterator >
{
typedef boost::iterator::iterator_adaptor< cycle_iterator<Iterator>, Iterator > super_t;
friend class boost::iterator::iterator_core_access;
Iterator first;
Iterator last;
public:
cycle_iterator() {}
explicit cycle_iterator(Iterator first, Iterator last)
: super_t(first), first(first), last(last) {}
private:
void increment() {
if (++base_reference() == last) {
base_reference() = first;
}
}
void decrement() {
if (base_reference() == first) {
base_reference() = last - 1;
}
}
void advance(typename super_t::difference_type n)
{
n += std::distance(first, base_reference());
n %= std::distance(first, last);
base_reference() = first + n;
}
};

Related

STL: apply function to result of adjacent_difference without extra container

What is the best way to apply some operation (find a min for example) on std::adjacent_difference results without creating extra container?
Edit: manual loop is obvious way but not STL enough.
One way would be to implement output_iterator but looks a bit heavy:
template<typename T>
class find_min_oit {
T min = std::numeric_limits<T>::max();
public:
using iterator_category = std::output_iterator_tag;
find_min_oit& operator++() {
return *this;
}
find_min_oit& operator++(int) {
return *this;
}
find_min_oit& operator*() {
return *this;
}
find_min_oit& operator=(T const& value){
if (value < min){
min = value;
}
return *this;
}
T result() const {
return min;
}
};
void find_min(){
vector<int> arr{1,2,3,6,15};
auto res = std::adjacent_difference(arr.begin(), arr.end(), find_min_oit<int>());
std::cout << res.result() << std::endl;
}
You can use boost::function_output_iterator to define the iterator.
void find_min(){
vector<int> arr{1,2,3,6,15};
int result = std::numeric_limits<int>::max();
auto oit = boost::make_function_output_iterator([&result](int value) { result = std::min(value, result); });
std::adjacent_difference(arr.begin(), arr.end(), oit);
std::cout << result << std::endl;
}
You can use std::adjacent_find.
int find_min(){
vector<int> arr{1,2,3,6,15};
int min = std::numeric_limits<int>::max();
std::adjacent_find(arr.begin(), arr.end(), [&](auto a, auto b){
if ((a - b) < min)
min = a-b;
return false;
});
return min;
}
Just go for a manual loop, unfortunately, the standard algorithms are not made to be combined without a cost... You can look at the range v3 library that allows you to combine algorithms in a less-costly way.
template <class InputIt>
auto find_adjacent_min_v3(InputIt first, InputIt last) {
auto min = std::numeric_limits<typename InputIt::value_type>::max();
for (auto it = first++; first < last; ++first, ++it) {
if (*it - *first < min) {
min = *it - *first;
}
}
return min;
}
For the sake of the exercise, here is a version using the standard std::accumulate with a custom "accumulator":
template <class InputIt>
auto find_adjacent_min(InputIt first, InputIt last) {
auto max = std::numeric_limits<typename InputIt::value_type>::max();
return std::accumulate(
std::next(first), last, std::make_pair(*first, max),
[](auto p, auto x) {
auto diff = (x - p.first) < p.second ?
x - p.first : p.second;
return std::make_pair(x, diff);
}).second;
}
You're 80% of the way to answering your own question: just add another template parameter say typename On_Assignment, rename find_min_oit to something more generic and derived from On_Assignment so you can inject data members, then allow operator= to be supplied by On_Assignment. You then just need a few lines to write struct with an operator= to produce variations in handling of the values adjacent_difference will supply. Alternatively, pass the custom behaviour to the constructor and save it in a std::function for use from operator=: you can then pass in a lambda.
If it is acceptable that the input data is changed, you might try something like this:
std::min_element(x.begin() + 1, std::adjacent_difference(x.begin(), x.end(), x.begin());
CPP reference states explicitly that input and output begins are allowed to be equal.

Problems with constant iterators

I'm trying write a tempate function which takes a sequence (by 2 iterators) and calculates the number of permutations of this sequence, in which there are no consecutive identical elements.
Thats what i did
template<class Iterator>
size_t count_perm(Iterator p, Iterator q)
{
if (p == q)
return 1;
size_t count = 0;
while(std::next_permutation(p, q)){
if(std::adjacent_find(p,q) != q)
++count;
}
}
/*Example
std::array<int, 3> a1 = {1,2,3};
size_t c1 = count_perm(a1.begin(), a1.end()); // 6
std::array<int, 5> a2 = {1,2,3,4,4};
size_t c2 = count_perm(a2.begin(), a2.end()); // 36*/
This code not working if i pass const iterators. What should I change to make it work with const iterators?
This code not working if i pass const iterators. What should I change to make it work with const iterators?
You can't: std::next_permutation() modify the values so is incompatible with const iterators.
-- EDIT --
The OP ask
How can i implement this function in right way?
I suggest you to follows the suggestion from Jarod42: works over a copy.
I propose something as follows
template <class Container>
size_t count_perm (Container c) // note: c is a copy
{
if ( c.cbegin() == c.cend() )
return 1;
size_t count = 0U;
std::sort(c.begin(), c.end());
if (std::adjacent_find(c.cbegin(), c.cend()) != c.cend()))
{
std::size_t ui = c.size();
for ( count = ui ; --ui > 1 ; count *= ui )
;
// count now is c.size() ! (factorial of)
}
else
{
while (std::next_permutation(c.begin(), c.end()))
if (std::adjacent_find(c.cbegin(), c.cend()) != c.cend())
++count;
}
return count; // remember this return!
}
Fixed your templated function for you (still requires non-const iterators):
template<class Iterator> size_t count_perm(Iterator p, Iterator q)
{
if (p == q || std::all_of(p, q, [&](auto &el) {return el == *p; })))
return 0;
size_t count = 1;
std::sort(p, q);
while (std::next_permutation(p, q))
if (std::adjacent_find(p, q) == q)
++count;
return count;
}
you should return count
when no adjacent elements are found, std::adjacent_find returns end, so you should == q not != q
Your example produces 6 and 37. Should it be 36 instead of 37?
Solved this exercise as follows, it works with const iterators:
template<class Iterator>
size_t count_permutations(Iterator p, Iterator q)
{
using T = typename std::iterator_traits<Iterator>::value_type;
if (p == q)
return 1;
std::vector<T> v(p,q);
std::sort(v.begin(), v.end());
size_t count = 0;
do{
if(std::adjacent_find(v.begin(),v.end()) == v.end()) {
++count;
}
} while(std::next_permutation(v.begin(), v.end()));
return count;
}
Problem was to use std::type_traits<Iterator>::value_type instead Iterator::value_type (that not working with const iters and simple pointers (like int*))

Is there an efficient algorithm for merging numeric ranges?

I am given series of ranges and I need to iterate each number in any of the ranges exactly once. The ranges may overlap and contain the same numbers.
The numbers in the range are
using Number = uint32_t;
Ranges are of this form
struct Range {
Number first;
Number last;
Number interval;
};
Just to clarify the representation of Range.
Range range = {
2, //first
14, //last
3 //interval
};
//is equivalent to...
std::vector<Number> list = {2, 5, 8, 11, 14};
I have a few Ranges and I need to efficiently iterate all of the numbers in any order only once.
How do I efficiently iterate a set of ranges?
Also, Is there there a more efficient algorithm if interval is always 1?
For each range, remember the "current" value (going from first to last with the step size). Put that along with the range in a priority queue, sorted after the current value.
Take the top out, if its current value is different from the last, then use it. Then, insert the next step if there is another.
Assumes positive step size.
template<typename Iterator, typename Operation>
void iterate_ranges (Iterator from, Iterator to, Operation op) {
using R = typename std::iterator_traits<Iterator>::value_type;
using N = typename std::decay<decltype(std::declval<R>().first)>::type;
using P = std::pair<N, R>;
auto compare = [](P const & left, P const & right) {
return left.first > right.first;};
std::priority_queue<P, std::vector<P>, decltype(compare)> queue(compare);
auto push = [& queue] (P p) {
if (p.first < p.second.last) queue.push(p); };
auto next = [](P const & p) -> P {
assert(p.second.step > 0);
return {p.first + p.second.step, p.second}; };
auto init = [&push] (R const & r) {
push({r.first, r}); };
std::for_each(from, to, init);
if (queue.empty()) return;
N last = queue.top().first;
push(next(queue.top()));
queue.pop();
op(last);
while (! queue.empty()) {
P current = queue.top();
queue.pop();
if (current.first != last) {
op(current.first);
last = current.first;
}
push(next(current));
}
}
Memory requirement: linear in the number of ranges. Time requirement: sum of all step counts within each range.
Small example:
struct Range {
int first;
int last;
int step; // a better name ...
};
int main() {
Range ranges [] = {
{1, 10, 2},
{2, 50, 5}};
auto print = [](auto n) { std::cout << n << std::endl; };
iterate_ranges(std::begin(ranges), std::end(ranges), print);
}
To get all numbers in a vector, use a lambda with a reference to a vector and push back each one.
Is there there a more efficient algorithm if interval is always 1?
You could add that as a special case, but I don't think it will be necessary. If you only got ~50 ranges, then above push won't be that expensive. Though, with all optimisation: profile first!
If the sequences are very long you might like to just take each result in order, without storing the list, discarding duplicates as you go.
#include <vector>
// algorithm to interpolate integer ranges/arithmetic_sequences
template<typename ASqs, typename Action>
void arithmetic_sequence_union(ASqs arithmetic_sequences, Action action)
{
using ASq = ASqs::value_type;
using T = ASq::value_type;
std::vector<ASq> remaining_asqs(begin(arithmetic_sequences), end(arithmetic_sequences));
while (remaining_asqs.size()) {
// get next value
T current_value = **std::min_element(begin(remaining_asqs), end(remaining_asqs),
[](auto seq1, auto seq2) { return *seq1 < *seq2; }
);
// walk past this value and any duplicates, dropping any completed arithmetic_sequence iterators
for (size_t seq_index = 0; seq_index < remaining_asqs.size(); )
{
ASq &asq = remaining_asqs[seq_index];
if (current_value == *asq // do we have the next value in this sequence?
&& !++asq) { // consume it; was it the last value in this sequence?
remaining_asqs.erase(begin(remaining_asqs) + seq_index);//drop the empty sequence
}
else {
++seq_index;
}
}
action(current_value);
}
}
This wants the range presented in a "generator"-type object. Would probably look very like the implementation of checked a iterator, but iterators don't expose the notion of knowing they are at the end of the sequence so we might have to roll our own simple generator.
template <typename ValueType, typename DifferenceType>
class arithmetic_sequence {
public:
using value_type = ValueType;
using difference_type = DifferenceType;
arithmetic_sequence(value_type start, difference_type stride, value_type size) :
start_(start), stride_(stride), size_(size) {}
arithmetic_sequence() = default;
operator bool() { return size_ > 0; }
value_type operator*() const { return start_; }
arithmetic_sequence &operator++() { --size_; start_ += stride_; return *this;}
private:
value_type start_;
difference_type stride_;
value_type size_;
};
Test example:
#include "sequence_union.h"
#include "arithmetic_sequence.h"
#include <cstddef>
#include <array>
#include <algorithm>
#include <iostream>
using Number = uint32_t;
struct Range {
Number first;
Number last;
Number interval;
};
using Range_seq = arithmetic_sequence<Number, Number>;
Range_seq range2seq(Range range)
{
return Range_seq(range.first, range.interval, (range.last - range.first) / range.interval + 1 );
}
int main() {
std::array<Range, 2> ranges = { { { 2,14,3 },{ 2,18,2 } } };
std::array<Range_seq, 2> arithmetic_sequences;
std::transform(begin(ranges), end(ranges), begin(arithmetic_sequences), range2seq);
std::vector<size_t> results;
arithmetic_sequence_union(
arithmetic_sequences,
[&results](auto item) {std::cout << item << "; "; }
);
return 0;
}
// output: 2; 4; 5; 6; 8; 10; 11; 12; 14; 16; 18;

How to iterate through a list but stop at size-1

This code:
for (std::list<point>::const_iterator it = controlPoints->begin();
it != controlPoints->end();
++it) {
...
}
Corresponds to:
for (int i = 0; i < controlPoints->size; i++) {
...
}
Meaning, it would iterate through all elements of the list if I got one element for each time it looped.
What would correspond to:
for (int i = 0; i < controlPoints->size-1; i++) {
...
}
I mean, how can I loop size-1 times using iterators?
The obvious way would be to get an iterator to the end and decrement it:
auto stop = controlPoints.end();
--stop;
for (std::list<point>::const_iterator it = controlPoints->begin();
it != stop;
++it) {
...
}
You could use std::advance or std::next if you preferred, but for this case a simple decrement is fine.
controlPoints->end() is also an iterator.
You could do this:
std::list<point>::const_iterator it = controlPoints->begin();
std::list<point>::const_iterator stop = controlPoints->end();
if ( it != stop) for ( --stop; it != stop; ++it) {
...
}
More verbose but it's safe to use whether the list has 0, 1 or more elements.
The key here is that iterators can be incremented and (for bidirectional iterators) decremented to advance / recede the position, so it's the equivalent of doing:
int it = 0;
int stop = list.size();
if (it != stop) for( --stop; it < stop; ++it ) {
...
}
In C++11 you should seek to use the ranged based for loop as often as you can. for(;;) loops are complex and error prone at the point you write them.
Using for(:) loops requires complexity away from the point you write them, but because you can write that infrastructure once and reuse it the bugs in it can be ironed out, instead of being dispursed throughout the code.
To start with, here is a simple range_t:
template<class It>
struct range_t {
It b, e;
It begin() const { return b; }
It end() const { return e; }
std::size_t size() const { return std::distance(begin(), end()); }
using iterator_tag = typename std::iterator_traits<It>::iterator_category;
private:
static It safe_advance( It in, It bound, std::ptrdiff_t n, std::random_access_iterator_tag ) const {
if (n == 0) return in;
if (n < 0) n = (std::min)( n, -std::distance( bound, in ) );
if (n > 0) n = (std::max)( n, std::distance( in, bound ) );
return std::advance( in, n );
}
static It safe_advance( It in, It bound, std::ptrdiff_t n, ... ) const {
if (n == 0) return in;
while (n < 0 && in != bound) {
in = std::prev(in); --n;
}
while (n > 0 && in != bound) {
in = std::next(in); ++n;
}
return in;
}
public:
range_t without_back( std::size_t n = 1 ) const {
return {begin(), safe_advance( end(), begin(), -(std::ptrdiff_t)n, iterator_tag{} };
}
range_t without_front( std::size_t n = 1 ) const {
return {begin(), safe_advance( end(), begin(), n, iterator_tag{} };
}
bool empty() const { return begin() == end(); }
decltype(auto) front() const { return *begin(); }
decltype(auto) back() const { return *std::prev(end()); }
};
template<class It>
range_t<It> range( It b, It e ) { return {b,e}; }
// rvalues blocked:
template<class C, class It = decltype( std::begin(std::declval<C&>()) )>
range_t<It> range( C& c ) { return range( std::begin(c), std::end(c) ); }
it stores a range of iterators and is itself iterable.
Then:
auto r = range(*controlPoints).without_back();
is a range object that is the controlPoints without the last element.
Using ranged-based for you can do this:
for (auto& x : range(*controlPoints).without_back()) {
}
note that the above code carefully handles being fed an empty array.
We can also write a similar adapter that lets you iterator over the iterators. I usually do this by writing an index_iterator that stores an Index and passes ++ and == etc to it. Except when you * it simply returns a copy of the Index.
This is useful to create an iterator over integers, but also lets you create an iterator over iterators.
Then create a range of indexes to the iterators in your container, and you get syntax that looks like:
for (auto it : iterators_into( *controlPoints) ) {
}
giving you range-based loops that also gives you iterators if you need them.

Is there a standard cyclic iterator in C++

Based on the following question: Check if one string is a rotation of other string
I was thinking of making a cyclic iterator type that takes a range, and would be able to solve the above problem like so:
std::string s1 = "abc" ;
std::string s2 = "bca" ;
std::size_t n = 2; // number of cycles
cyclic_iterator it(s2.begin(),s2.end(),n);
cyclic_iterator end;
if (std::search(it, end, s1.begin(),s1.end()) != end)
{
std::cout << "s1 is a rotation of s2" << std::endl;
}
My question, Is there already something like this available? I've checked Boost and STL and neither have an exact implementation.
I've got a simple hand-written (derived from a std::forward_iterator_tag specialised version of std::iterator) one but would rather use an already made/tested implementation.
There is nothing like this in the standard. Cycles don't play well with C++ iterators because a sequence representing the entire cycle would have first == last and hence be the empty sequence.
Possibly you could introduce some state into the iterator, a Boolean flag to represent "not done yet." The flag participates in comparison. Set it true before iterating and to false upon increment/decrement.
But it might just be better to manually write the algorithms you need. Once you've managed to represent the whole cycle, representing an empty sequence might have become impossible.
EDIT: Now I notice that you specified the number of cycles. That makes a big difference.
template< class I >
class cyclic_iterator
/* : public iterator< bidirectional, yadda yadda > */ {
I it, beg, end;
int cnt;
cyclic_iterator( int c, I f, I l )
: it( f ), beg( f ), end( l ), cnt( c ) {}
public:
cyclic_iterator() : it(), beg(), end(), cnt() {}
cyclic_iterator &operator++() {
++ it;
if ( it == end ) {
++ cnt;
it = beg;
}
} // etc for --, post-operations
friend bool operator==
( cyclic_iterator const &lhs, cyclic_iterator const &rhs )
{ return lhs.it == rhs.it && lhs.cnt == rhs.cnt; } // etc for !=
friend pair< cyclic_iterator, cyclic_iterator > cycle_range
( int c, I f, I l ) {//factory function, better style outside this scope
return make_pair( cyclic_iterator( 0, f, l ),
cyclic_iterator( c, f, l ) );
}
};
This should provide some ideas/solutions: 2 renditions, the second is a little lighter in weight. Both tested using a subrange of a vector and a list ...
#include <vector>
template <typename T, typename Container = std::vector<T>, typename Iterator = Container::iterator>
class RingIterator : public std::iterator <std::bidirectional_iterator_tag, T, ptrdiff_t>
{
Container& data;
Iterator cursor;
Iterator begin;
Iterator end;
public:
RingIterator (Container& v) : data(v), cursor(v.begin()), begin(v.begin()), end(v.end()) {}
RingIterator (Container& v, const Iterator& i) : data(v), cursor(i), begin(v.begin()), end(v.end()) {}
RingIterator (Container& v, const Iterator& i, const Iterator& j) : data(v), cursor(i), begin(i), end(j) {}
RingIterator (Container& v, size_t i) : data(v), cursor(v.begin() + i % v.size()), begin(v.begin()), end(v.end()) {}
bool operator == (const RingIterator& x) const
{
return cursor == x.cursor;
}
bool operator != (const RingIterator& x) const
{
return ! (*this == x);
}
reference operator*() const
{
return *cursor;
}
RingIterator& operator++()
{
++cursor;
if (cursor == end)
cursor = begin;
return *this;
}
RingIterator operator++(int)
{
RingIterator ring = *this;
++*this;
return ring;
}
RingIterator& operator--()
{
if (cursor == begin)
cursor = end;
--cursor;
return *this;
}
RingIterator operator--(int)
{
RingIterator ring = *this;
--*this;
return ring;
}
RingIterator insert (const T& x)
{
return RingIterator (data, data.insert (cursor, x));
}
RingIterator erase()
{
return RingIterator (data, data.erase (cursor));
}
};
template <typename T, typename Iterator>
class CyclicIterator : public std::iterator <std::bidirectional_iterator_tag, T, ptrdiff_t>
{
Iterator cursor;
Iterator begin;
Iterator end;
public:
CyclicIterator (const Iterator& i, const Iterator& j) : cursor(i), begin(i), end(j) {}
bool operator == (const CyclicIterator& x) const
{
return cursor == x.cursor;
}
bool operator != (const CyclicIterator& x) const
{
return ! (*this == x);
}
reference operator*() const
{
return *cursor;
}
CyclicIterator& operator++()
{
++cursor;
if (cursor == end)
cursor = begin;
return *this;
}
CyclicIterator operator++(int)
{
CyclicIterator ring = *this;
++*this;
return ring;
}
CyclicIterator& operator--()
{
if (cursor == begin)
cursor = end;
--cursor;
return *this;
}
CyclicIterator operator--(int)
{
CyclicIterator ring = *this;
--*this;
return ring;
}
};
#include <iostream>
#include <iomanip>
#include <list>
enum { CycleSize = 9, ContainerSize };
template <typename cyclicIterator>
void test (cyclicIterator& iterator, size_t mn)
{
int m = mn;
while (m--)
for (int n = mn; n--; ++iterator)
std::cout << std::setw(3) << *iterator << ' ';
--iterator;
m = mn;
while (m--)
for (int n = mn; n--; --iterator)
std::cout << std::setw(3) << *iterator << ' ';
}
template <typename containers>
void load (containers& container)
{
while (container.size() < ContainerSize)
container.push_back (container.size());
}
void main (void)
{
typedef std::vector<int> vContainer;
typedef vContainer::iterator vIterator;
typedef std::list<int> lContainer;
typedef lContainer::iterator lIterator;
vContainer v; load (v);
vIterator vbegin = v.begin() + 1;
RingIterator <int, vContainer, vIterator> vring (v, vbegin, v.end());
CyclicIterator <int, vIterator> vcycle (vbegin, v.end());
lContainer l; load (l);
lIterator lbegin = l.begin(); ++lbegin;
RingIterator <int, lContainer, lIterator> lring (l, lbegin, l.end());
CyclicIterator <int, lIterator> lcycle (lbegin, l.end());
test (vring, CycleSize);
test (vcycle, CycleSize);
test (lring, CycleSize);
test (lcycle, CycleSize);
}
The CGAL library defines Circulators. They are used like this.
template<class Circulator, class T>
bool contains(Circulator c, Circulator d, const T& value) {
if (c != 0) {
do {
if (*c == value)
return true;
} while (++c != d);
}
return false;
}
Note that they look like iterators at first glance but note that the logic (and the structure of the loop) is different than for iterators). if(not empty) do{..}while() instead of while(){...}.
Eric Niebler's ranges-v3 library (on which the upcoming C++20 ranges is based) has ranges::view::cycle. This adapts its source range into an endlessly repeating infinite range. However we require a single repeat which may be easily achieved using ranges::view::concat.
#include <ranges/v3/all.hpp>
int main() {
std::string s1 = "abc";
std::string s2 = "bca";
auto s2s2 = ranges::view::concat(s2, s2);
auto i = std::search(s2s2.begin(), s2s2.end(), s1.begin(), s1.end());
if (i != s2s2.end() && s1.size() == s2.size()) {
std::cout << "s1 is a rotation of s2\n";
}
}
You’re maybe looking for Boost’s Circular Buffer. But if you’ve already checked Boost, it might not be the one you want.
On the other hand, the very idea of cyclic iterator is not compatible to STL container ideology. You should not want cyclic iterator, as the user of this iterator may be surprized by its unusual behavior. Usually in STL you are iterating from the beginning to the end of container. Infinite loop in that case. Because the end is not reachable.
After all, obviously, you are not going to do more than 2 cycles to solve your task. No reason to have special iterator with confusing behavior. That is better to iterate usual linear container twice or may be even less then twice.