Generalization of two methods - c++

Consider the structure:
struct B {int b1, b2;};
struct A {
std::set<B, compBLess> m_setLess;
std::set<B, compBGreater> m_setGreater;
void onFirst(int val) {
auto i_set = m_setLess.begin();
auto comp = [&](){ return val >= i_set->b1; };
while ( i_set != m_setLess.end() && comp() ) {
sameForBoth(*i_set);
++i_set;
}
}
void onSecond(int val) {
auto i_set = m_setGreater.begin();
auto comp = [&](){ return val <= i_set->b1; };
while ( i_set != m_setGreater.end() && comp() ) {
sameForBoth(*i_set);
++i_set;
}
}
void sameForBoth() {}
};
Is it possible to refactor methods onFirst and onSecond into one laconic without suffering code maintanability? Note, that compBLess/compBGreater can't be used instead of comp.
My take on the problem:
template<typename TSet>
void onBoth(int val){
TSet* set;
if ( std::is_same<TSet, decltype(m_setLess)>::value ) {
set = reinterpret_cast<TSet*>(&m_setLess);
} else {
set = reinterpret_cast<TSet*>(&m_setGreater);
}
auto i_set = set->begin();
std::function<bool()> comp;
if( std::is_same<TSet, decltype(m_setLess)>::value )
comp = std::function<bool()>([&]() { return val >= i_set->b1; });
else
comp = std::function<bool()>([&]() { return val <= i_set->b1; });
while ( i_set != set->end() && comp() ) {
sameForBoth(*i_set);
++i_set;
}
}
But my solution seems too complex. Also I'm not sure that using reinterpret_cast<> in such manner is a good practice.
Is there any other way?

If I understand this correctly, it seems that you want to apply an action on each element that happens to satisfy the comp unary predicate. Therefore, we may scan the elements linearly and apply a function until a given predicate holds.
Since you are working on a range, a possible approach is to design a generic procedure, as in:
template <typename I, typename P, typename F>
// I models InputIterator
// P models UnaryPredicate
// F models UnaryFunction
// Domain<P> == ValueType<I>
// Domain<F> == ValueType<I>
void apply_until(I first, I last, P p, F f) {
while (first != last) {
if (!p(*first)) return;
f(*first);
++first;
}
}
We can use such a generic algorithm to, e.g., print out the values in a range that happen to be strictly less than 3:
int main() {
std::set<int> s1 = {1, 2, 3, 4, 5};
apply_until(s1.begin(), s1.end(), [](int x) { return x < 3;}, [](int x) { std::cout << x << '\n'; });
}
I would keep the distinction between onFirst and onSecond, as they are meant to operate on distinct sets. The code for your use case may reduce to something like:
void onFirst(int val) {
apply_until(m_setLess.begin(), m_setLess.end(), [&](B const& x) { return x.b1 >= val; }, [&](B const& x) { sameForBoth(x); });
}
void onSecond(int val) {
apply_until(m_setGreater.begin(), m_setGreater.end(), [&](B const& x) { return x.b1 <= val; }, [&](B const& x) { sameForBoth(x); });
}

In both functions, we are iterating over a range, from the beginning of the std::set up-to a given iterator which depends on the input value.
In this answer, I'll assume that compBLess and compBGreater are defined like this (the important part is that the b1 field is predominant over b2. And see at the end for a slightly different version)
struct compBLess {
bool operator ()(B const & o1, B const& o2) const {
return std::make_pair(o1.b1,o1.b2) < std::make_pair(o2.b1,o2.b2);
}
};
struct compBGreater {
bool operator ()(B const & o1, B const& o2) const {
return std::make_pair(o1.b1,o1.b2) > std::make_pair(o2.b1,o2.b2);
}
};
Under this assumption, then I think the idiomatic way to do this is to use lowerbound, upperbound methods of std::set to find the end of the iteration , and then use
template<typename Iterator>
void foo(Iterator it, Iterator end) {
std::for_each(it,end,[this](auto & o){ sameForBoth(o); });
}
This will be performance-wise more efficient, because we will do O(log(size_of_set)) comparisons (using lowerbound / upperbound) instead of O(size_of_set) comparisons (using comp in the loop)
The actual implementation of the other methods looks like this:
void onFirst(int val) {
foo(m_setLess.begin(), m_setLess.lowerbound({val,std::numeric_limits<int>::min}));
}
void onSecond(int val) {
foo(m_setGreater.begin(), m_setGreater.upperbound({val-1,std::numeric_limits<int>::max}));
}
Edit: Following #z3dd's comment, Here is the implementation that works for slightly different compBLess and compBGreater (the ordering vs. the b2 field is reversed):
struct compBLess {
bool operator ()(B const & o1, B const& o2) const {
return std::make_pair(o1.b1,-o1.b2) < std::make_pair(o2.b1,-o2.b2);
}
};
struct compBGreater {
bool operator ()(B const & o1, B const& o2) const {
return std::make_pair(o1.b1,-o1.b2) > std::make_pair(o2.b1,-o2.b2);
}
};
void onFirst(int val) {
foo(m_setLess.begin(), m_setLess.lowerbound({val,std::numeric_limits<int>::max}));
}
void onSecond(int val) {
foo(m_setGreater.begin(), m_setGreater.upperbound({val-1,std::numeric_limits<int>::min}));
}
[Note that if compBLess and compBGreater are not implemented like any of the 2 implementations given, then the answer of #Ilio Catallo is the one to use.]

Related

C++ use multiple filter on container with less overhead

i have to filter a container and the copy of each item is expensive. So i came up with this C++ code .. maybe there is better concept that i miss. Please comment. Also important that operations like counting and empty are also fast.
The sample below will create a vector with some items and return a filtered copy and doing some boolean operations.
#include <vector>
#include <functional>
template <class X> struct filterChainT {
/// the list here
const X & list;
/// take store type from access operator
typedef decltype(list[0]) storeType;
/// the test functions
std::function<bool(storeType &) > tests[10];
/// counting the test (don´t use array here)
size_t countTest;
/// ctor with given list
filterChainT(const X & list):list(list),countTest(0) { }
/// add a rule here
filterChainT<X> & apply(const std::function<bool(storeType &) > & fnc)
{
tests[countTest++] = fnc;
return *this;
}
/// downcast to container (will return the filter copy)
operator X() const
{
X ret;
eval([&](const storeType & hit) { ret.push_back(hit); return false; });
return ret;
}
/// just count item after filter
int count() const
{
int count = 0;
eval([&](const storeType hit) { count++; return false; });
return count;
}
bool operator==(int number) const { return count() == number; }
bool operator>(int number) const
{
int count = 0;
return eval([&](const storeType & hit) { return ++count>number; });
}
bool operator<(int number) const
{
int count = 0;
return !eval([&](const storeType & hit) { return ++count>=number; });
}
//// the magic eval functions. Return true if the fnc object abort the loop
template <class FNC> bool eval(const FNC fnc) const
{
for (auto i : list)
{
for (size_t t = 0; t < countTest; t++)
{
if (!tests[t](i))
goto next;
}
if (fnc(i))
return true;
next:;
}
return false;
}
};
struct myFilter : public filterChainT < std::vector<int>> {
myFilter(const std::vector<int> & in) :filterChainT<std::vector<int>>(in){ };
// filter items i%2==0
myFilter & mod()
{
apply([](const int & i) { return i % 2; });
return *this;
}
// filter items smaller than x
myFilter & smaller(int x)
{
apply([=](const int & i) { return i<x; });
return *this;
}
};
int main()
{
std::vector<int> vec;
vec.push_back(1);
vec.push_back(3);
vec.push_back(10);
// apply filter and return result use two filters „mod“ and „smaller“
std::vector<int> ret = myFilter(vec).mod().smaller(5);
// just see if they are less then 2 items in list same filter than above
bool res1 = myFilter(vec).mod().smaller(5) < 2;
// some custom without the helper -> filter all items larger than 3 and put in list
std::vector<int> result=filterChainT < std::vector<int>>(vec).apply([](const int & p) { return p > 3; });
}
regards
Markus
the hint with "expression templates" works very well. Two times faster than my posting. Now the code looks like this. Thank you very much for pointing to the right place.
I use the same concept as the WIKI entry by adding a plus operation to create the filter chain and a final function to reduce the given list with this filter.
template <class T> struct filterNodeBaseT {
template <class X> bool apply(const X& x) const { return static_cast<T const & >(*this).apply(x); }
template <class LST> LST filter(const LST & input) const
{ LST ret;
for (auto i : input)
{ if (this->apply(i))
ret.push_back(i);
}
return ret;
}
template <class LST> int count(const LST & input) const
{ int ret = 0;
for (auto i : input)
{ if (this->apply(i))
ret++;
}
return ret;
}
};
template <class T1, class T2> struct filterCombine : public filterNodeBaseT<filterCombine<T1, T2> > {
const T1 & t1;
const T2 & t2;
filterCombine(const T1 & t1, const T2 & t2) :t1(t1), t2(t2) { }
template <class X> bool apply(const X & x) const { return t1.apply(x) && t2.apply(x); }
};
template <class T1,class T2> filterCombine<T1,T2> operator + (const T1 & t1,const T2 & t2)
{ return filterCombine<T1,T2>(t1,t2); }
struct filterNodeSmaller : public filterNodeBaseT<filterNodeSmaller> {
int limit;
filterNodeSmaller(int limit) :limit(limit) {};
bool apply(const int & x) const { return x < limit; }
};
struct filterNodeLarger: public filterNodeBaseT<filterNodeLarger> {
int limit;
filterNodeLarger(int limit) :limit(limit) {};
bool apply(const int & x) const { return x > limit; }
};
struct filterNodeMod : public filterNodeBaseT<filterNodeMod> {
bool apply(const int & x) const { return x % 2; }
};
struct filterStrlenLarger : public filterNodeBaseT<filterStrlenLarger> {
int limit;
filterStrlenLarger(int limit) :limit(limit) { };
bool apply(const std::string & s) const { return s.length() > limit; }
};
struct filterStrGreater : public filterNodeBaseT<filterStrGreater> {
std::string cmp;
filterStrGreater(const std::string & cmp) :cmp(cmp) { };
bool apply(const std::string & s) const { return s>cmp; }
};
_declspec(noinline) void nodeTest()
{
std::vector<int> intList;
intList.push_back(1); intList.push_back(3); intList.push_back(4);
int count= (filterNodeMod() + filterNodeSmaller(5)+ filterNodeLarger(1)).count(intList);
std::vector<int> resList1= (filterNodeMod() + filterNodeSmaller(5)+filterNodeLarger(1)).filter(intList);
printf("%d\n", count);
std::vector<std::string> strList;
strList.push_back("Hello");
strList.push_back("World");
strList.push_back("!");
count = (filterStrlenLarger(3)+filterStrGreater("Hello")).count(strList);
std::vector<std::string> resList2= (filterStrlenLarger(3) + filterStrGreater("Hello")).filter(strList);
printf("%d\n", count);
}

C++11 for each loop with more than one variable

I would like to translate the following traditional for loop into a C++11 for-each loop without extra looping constructs:
int a[] = { 5, 6, 7, 8, 9, 10 };
int b[] = { 50, 60, 70, 80, 90, 100 };
// Swap a and b array elements
for (int i = 0; i < sizeof(a)/sizeof(a[0]); i++)
{
a[i] ^= b[i]; b[i] ^= a[i]; a[i] ^= b[i];
}
Does there exist any way by which it is possible to provide more than one variable in the C++11 for-each loop like:
for (int i, int j : ...)
There is no built-in way to do this. If you can use Boost, boost::combine will work for iterating two (or more) ranges simultaneously (Does boost offer make_zip_range?, How can I iterate over two vectors simultaneously using BOOST_FOREACH?):
for (boost::tuple<int&, int&> ij : boost::combine(a, b)) {
int& i = boost::get<0>(ij);
int& j = boost::get<1>(ij);
// ...
}
Unfortunately accessing the elements within the tuple elements of the zipped range is highly verbose. C++17 will make this much more readable using structured binding:
for (auto [&i, &j] : boost::combine(a, b)) {
// ...
}
Since you don't need to break out of the loop or return from the enclosing function, you could use boost::range::for_each with the body of your loop as a lambda:
boost::range::for_each(a, b, [](int& i, int& j)
{
// ...
});
zip or combine ranges are common in many range libraries.
Writing one strong enough for a for(:) loop isn't hard however.
First we write a basic range type:
template<class It>
struct range_t {
It b,e;
It begin() const{ return b; }
It end() const{ return e; }
range_t without_front( std::size_t count = 1 ) const {
return {std::next(begin()), end()};
}
bool empty() const { return begin()==end(); }
};
template<class It>
range_t<It> range( It b, It e ) { return {b,e}; }
template<class C>
auto range( C& c ) {
using std::begin; using std::end;
return range( begin(c), end(c) );
};
Then we write an iterator that works with ranges (easier than with iterators):
template<class R1, class R2>
struct double_foreach_iterator {
R1 r1;
R2 r2;
void operator++() { r1 = r1.without_front(); r2 = r2.without_front(); }
bool is_end() const { return r1.empty() || r2.empty(); }
auto operator*()const {
return std::tie( *r1.begin(), *r2.begin() );
}
using self=double_foreach_iterator;
auto cur() const {
return std::make_tuple( r1.begin(), r2.begin() );
}
friend bool operator==( self const& lhs, self const& rhs ) {
if (lhs.is_end() || rhs.is_end())
return lhs.is_end() == rhs.is_end();
return lhs.cur() == rhs.cur();
}
friend bool operator!=( self const& lhs, self const& rhs ) {
return !(lhs==rhs);
}
};
now we double iterate:
template<class A, class B>
auto zip_iterate(
A& a, B& b
) {
auto r1 = range(a);
auto r2 = range(b);
auto r1end = range(r1.end(), r1.end());
auto r2end = range(r2.end(), r2.end());
using it = double_foreach_iterator<decltype(r1), decltype(r2)>;
return range( it{r1, r2}, it{r1end, r2end} );
}
which gives us:
for (auto tup : zip_iterate(a, b)) {
int& i = std::get<0>(tup);
int& j = std::get<1>(tup);
// ...
}
or in C++17:
for (auto&& [i, j] : zip_iterate(a, b)) {
// ...
}
My zip iterate does not assume the two containers are of the same length, and will iterate to the length of the shorter one.
live example.
Just for fun.
The following isn't intended to be a serious answer to the question but just an exercise to try to understand the potentiality of C++11 (so, please, be patient).
The following is an example of a class (a draft of a class) that receive a couple of container (with size() method), with the same size (exception otherwise), and of a custom iterator that return a std::pair of std::reference_wrapper to n-position elements.
With a simple use example that show that it's possible to change the value in the starting containers.
Doesn't work with old C-style arrays but works with std::array. We're talking about C++11 so I suppose we could impose the use of std::array.
#include <array>
#include <vector>
#include <iostream>
#include <functional>
template <typename T1, typename T2>
class pairWrapper
{
public:
using V1 = typename std::remove_reference<decltype((T1().at(0)))>::type;
using V2 = typename std::remove_reference<decltype((T2().at(0)))>::type;
using RW1 = std::reference_wrapper<V1>;
using RW2 = std::reference_wrapper<V2>;
class it
{
public:
it (pairWrapper & pw0, std::size_t p0): pos{p0}, pw{pw0}
{ }
it & operator++ ()
{ ++pos; return *this; }
bool operator!= (const it & it0)
{ return pos != it0.pos; }
std::pair<RW1, RW2> & operator* ()
{
static std::pair<RW1, RW2>
p{std::ref(pw.t1[0]), std::ref(pw.t2[0])};
p.first = std::ref(pw.t1[pos]);
p.second = std::ref(pw.t2[pos]);
return p;
}
private:
std::size_t pos;
pairWrapper & pw;
};
it begin()
{ return it(*this, 0U); }
it end()
{ return it(*this, len); }
pairWrapper (T1 & t10, T2 & t20) : len{t10.size()}, t1{t10}, t2{t20}
{ if ( t20.size() != len ) throw std::logic_error("no same len"); }
private:
const std::size_t len;
T1 & t1;
T2 & t2;
};
template <typename T1, typename T2>
pairWrapper<T1, T2> makePairWrapper (T1 & t1, T2 & t2)
{ return pairWrapper<T1, T2>(t1, t2); }
int main()
{
std::vector<int> v1 { 1, 2, 3, 4 };
std::array<long, 4> v2 { { 11L, 22L, 33L, 44L } };
for ( auto & p : makePairWrapper(v1, v2) )
{
std::cout << '{' << p.first << ", " << p.second << '}' << std::endl;
p.first += 3;
p.second += 55;
}
for ( const auto & i : v1 )
std::cout << '[' << i << ']' << std::endl;
for ( const auto & l : v2 )
std::cout << '[' << l << ']' << std::endl;
return 0;
}
p.s.: sorry for my bad English

Elegantly (iterating) parsing data in chunks?

We have some "iterable" collection of data, for instance: std::vector<Foo> bar.
We wish to process Foo elements from bar until some condition is met in which point we "yield" (think Python) the result of all these processed Foos and wait until the next chunk of parsed information is requested.
So far what we're doing is this:
ParsedChunk foobar( std::vector<Foo> bar, size_t* start_from) {
size_t& i = *start_from;
ParsedChunk result_so_far;
for (;i < bar.size(); i++) {
process_some_foo_and_update_chunk(result_so_far, bar[i]);
if (check_condition(? ? ?) {
return result_so_far;
}
}
}
Any suggestions for doing this better?
As I already pointed out in my comment, this is IMO a very good case for an custom iterator:
The iterator scans through your range, as long as some predicate holds, and
when the predicate isn't true for some element, calls a function with the sub range of elements where the predicate held (plus the one that didn't satisfy the predicate). The result of that function call is then the value you get when you dereference the iterator.
template<typename Fn, typename Predicate, typename Iterator>
struct collector {
using value_type = typename std::result_of<Fn(Iterator, Iterator)>::type;
using pointer = value_type const *;
using reference = value_type const &;
using difference_type = std::ptrdiff_t;
using iterator_category = std::forward_iterator_tag;
value_type cache;
Fn fn;
Predicate predicate;
Iterator pos, from, stop;
collector(Fn&& fn, Predicate&& p, Iterator&& s, Iterator&& e)
: fn(std::forward<Fn>(fn)),
predicate(std::forward<Predicate>(p)),
pos(std::forward<Iterator>(s)),
from(pos),
stop(std::forward<Iterator>(e))
{
next_range();
}
collector & operator++(void) {
next_range();
return *this;
}
reference operator*(void) const {
return cache;
}
void next_range(void) {
from = pos;
if (pos == stop) return;
for (; pos != stop; ++pos) {
if (not predicate(*pos)) {
++pos;
break;
}
}
cache = fn(from, pos);
}
collector end_of_range(void) const {
auto copy = collector{*this};
copy.pos = copy.stop;
copy.from = copy.stop;
return copy;
}
bool operator==(collector const & rhs) const {
return (from == rhs.from) and (pos == rhs.pos) and (stop == rhs.stop);
}
bool operator!=(collector const & rhs) const {
return (from != rhs.from) or (pos != rhs.pos) or (stop != rhs.stop);
}
};
template<typename Fn, typename Predicate, typename Iterator>
auto make_collector_range(Fn&& fn, Predicate&& p, Iterator&& s, Iterator&& e) {
using I = typename std::decay<Iterator>::type;
using P = typename std::decay<Predicate>::type;
using F = typename std::decay<Fn>::type;
using C = collector<F,P,I>;
auto start = C{
std::forward<Fn>(fn), std::forward<Predicate>(p),
std::forward<Iterator>(s), std::forward<Iterator>(e)};
auto stop = start.end_of_range();
return make_pair(std::move(start), std::move(stop));
}
An example usage, calculating the sum of the numbers till 50, but not in one step, but in steps of 15 numbers each:
int main(int, char**) {
vector<int> numbers = vector<int>(50);
generate(begin(numbers), end(numbers),
[i = 0] (void) mutable{
return ++i;
});
copy(begin(numbers), end(numbers), ostream_iterator<int>{cout, " "});
cout << endl;
auto collected = make_collector_range(
[](auto const & from, auto const & to) {
return accumulate(from, to, 0);
},
[](auto const & num) {
return not ((num % 3 == 0) and (num % 5 == 0));
},
begin(numbers), end(numbers));
copy(collected.first, collected.second, ostream_iterator<int>{cout, " "});
cout << endl;
bool passed = accumulate(collected.first, collected.second, 0) == (50*51)/2;
cout << "test " << (passed ? "passed" : "failed") << endl;
return 0;
}
(Live demo here)
(Note: This example uses a fixed "step" width, and predicate and function are unrelated to each other and don't maintain state, but none of this is required by the iterator.)
I hope the intention of the code is clear, if not I can try to provide a more detailed explanation about its workings.

Additional condition in for each

I'm wondering: is there any possibility to add additional condition to for each?
I'm thinking about something like:
int i=0;
for(auto &it : list; i++)
if(it.ID == 25)
return i;
or
for(auto &it : list, int i=0; i++)
if(it.ID == 25)
return i;
You can use std::find_if:
const auto position = std::find_if(list.cbegin(), list.cend(), []((decltype(*list.cbegin()) value)
{
return value.ID == 25;
});
return position - list.cbegin();
(Updated, now independent of container value_type)
No it's not possible. You can use the old "normal" for loop for that:
auto iter = std:begin(list)
for (int i = 0; iter != std::end(list); ++iter, ++i)
{
auto& it = *iter;
// ...
}
Mandatory Reference: Sean Parent's "Seasoning C++" talk:
goal 1: Avoid raw loops
In cases like these, abstract your algorithm!
This will come up more often, so it's worth making it generic:
#include <algorithm>
template <typename C, typename Pred>
size_t index_if(C const& c, Pred&& pred)
{
const auto f(begin(c)), l(end(c));
auto match = std::find_if(f, l, std::forward<Pred>(pred));
return (l==match) ? -1 : std::distance(f, match);
}
Now you can write your query:
int main()
{
struct X { int ID; };
const std::vector<X> v { {1},{2},{3},{25},{4},{5},{6},{42} };
return index_if(v, [](X const& x) { return x.ID == 25; });
}
See it Live on Coliru
PS. You might want a value-based version along with the predicate-based one:
template <typename C, typename V/* = typename C::value_type*/>
size_t index_of(C const& c, V const v)
{
const auto f(begin(c)), l(end(c));
auto match = std::find(f, l, v);
return (l==match) ? -1 : std::distance(f, match);
}

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.