Related
I'm making an attempt to learn and implement C++20 coroutines, and I'm experiencing a bug.
Generator class:
template<class ReturnType = void>
class enumerable
{
public:
class promise_type;
using handle_type = std::coroutine_handle<promise_type>;
class promise_type
{
public:
ReturnType current_value{};
auto get_return_object()
{
return enumerable{ handle_type::from_promise(*this) };
}
auto initial_suspend()
{
return std::suspend_always{};
}
auto final_suspend() noexcept
{
return std::suspend_always();
}
void unhandled_exception()
{
// TODO:
}
void return_void()
{
}
auto yield_value(ReturnType& value) noexcept
{
current_value = std::move(value);
return std::suspend_always{};
}
auto yield_value(ReturnType&& value) noexcept
{
return yield_value(value);
}
};
class iterator
{
using iterator_category = std::forward_iterator_tag;
using difference_type = std::ptrdiff_t;
using value_type = ReturnType;
using pointer = ReturnType*;
using reference = ReturnType&;
private:
handle_type handle;
public:
iterator(handle_type handle)
: handle(handle)
{
}
reference operator*() const
{
return this->handle.promise().current_value;
}
pointer operator->()
{
return &this->handle.promise().current_value;
}
iterator& operator++()
{
this->handle.resume();
return *this;
}
friend bool operator==(const iterator& it, std::default_sentinel_t s) noexcept
{
return !it.handle || it.handle.done();
}
friend bool operator!=(const iterator& it, std::default_sentinel_t s) noexcept
{
return !(it == s);
}
friend bool operator==(std::default_sentinel_t s, const iterator& it) noexcept
{
return (it == s);
}
friend bool operator!=(std::default_sentinel_t s, const iterator& it) noexcept
{
return it != s;
}
};
handle_type handle;
enumerable() = delete;
enumerable(handle_type h)
: handle(h)
{
std::cout << "enumerable constructed: " << this << " : " << this->handle.address() << '\n';
};
iterator begin()
{
this->handle.resume();
return iterator(this->handle);
}
std::default_sentinel_t end()
{
return {};
}
//Filters a sequence of values based on a predicate.
template<class Predicate>
enumerable<ReturnType> where(Predicate&& pred)
{
std::cout << "where: " << this << " : " << this->handle.address() << '\n';
for (auto& i : *this)
{
if(pred(i))
co_yield i;
}
}
~enumerable()
{
std::cout << "enumerable destructed: " << this << " : " << this->handle.address() << '\n';
}
};
Test code:
enumerable<int> numbers()
{
co_yield 1;
co_yield 2;
co_yield 3;
co_yield 4;
}
enumerable<int> filtered_numbers()
{
return numbers().where([](int i) { return true; });
}
// Crashes
int main()
{
for (auto& i : filtered_numbers())
{
std::cout << "value: " << i << '\n';
}
return 0;
}
Output:
enumerable constructed: 000000FF0550F560:000002959E3B5290
enumerable constructed: 000000FF0550F5D8:000002959E3B6470
destructed: 000000FF0550F560 : 000002959E3B5290
where: 000000FF0550F560 : 000000FF0550F640
//Works, despite "this" inside "where" still being destructed before use, can be observed with the couts.
int main()
{
for(auto i : numbers().where([](int i) { return true; }))
{
std::cout << "value: " << i << '\n';
}
return 0;
}
Output:
enumerable constructed: 000000C9EDD2FD78:000001DADD1A61D0
enumerable constructed: 000000C9EDD2FD28:000001DADD1A73B0
destructed: 000000C9EDD2FD78 : 000001DADD1A61D0
where: 000000C9EDD2FD78 : 000001DADD1A61D0
value: 1
value: 2
value: 3
value: 4
destructed: 000000C9EDD2FD28 : 000001DADD1A73B0
Could somebody explain what is happening here? I'd like to come up with a workaround if possible, the crash does not happen if we return "std::suspend_never" in our promise_type's "initial_suspend", but suspending in initial_suspend isn't ideal behavior for a generator.
This:
return numbers().where([](int i) { return true; });
Creates a temporary (numbers()), then stores a reference to that temporary in a coroutine (the *this used in the loop), and then the temporary goes away.
That's bad. If you want to do chaining of coroutines, each step in that chain needs to be an object on someone's stack. where could be a non-member function that takes an enumerable by value. That would allow the where coroutine to preserve the existence of the enumerable.
//Filters a sequence of values based on a predicate.
template<class Predicate>
enumerable<ReturnType> where(Predicate pred)&
{
std::cout << "where: " << this << " : " << this->handle.address() << '\n';
for (auto& i : *this)
{
if(pred(i))
co_yield i;
}
}
//Captures *this as well as above.
template<class Predicate>
enumerable<ReturnType> where(Predicate pred)&&
{
auto self=std::move(*this);
std::cout << "where: " << this << " : " << this->handle.address() << '\n';
for (auto& i : self)
{
if(pred(i))
co_yield i;
}
}
two changes.
I take Predicate by value, to avoid dangling reference problem.
I have a && overload that copies *this (well, moves from) and stores it within the coroutine.
This still doesn't work.
The first thing that happens is that our coroutine is suspended before any code is run. So the copy of auto self=std::move(*this) happens on the first time we try to get a value.
We can work around this in a few ways. One of them is to bounce to a free function and let it copy the enumerable<int>:
template<class Predicate>
friend enumerable<ReturnType> where( enumerable<ReturnType> self, Predicate pred ) {
for (auto& i: self)
if (pred(i))
co_yield i;
}
//Filters a sequence of values based on a predicate.
template<class Predicate>
enumerable<ReturnType> where(Predicate pred)&
{
return where( *this, std::move(pred) );
}
template<class Predicate>
enumerable<ReturnType> where(Predicate pred)&&
{
return where( std::move(*this), std::move(pred) );
}
a second way is to modify enumerable<ReturnType> to support a setup phase.
struct init_done {};
auto initial_suspend() {
return std::suspend_never{};
}
auto yield_value(init_done) noexcept {
return std::suspend_always{};
}
and modify enumerable<int> returning functions to first co_yield init_done{}; after their setup is finished.
We'd do this on the first line of the numbers() coroutine, and after we copy *this into the local variable self in the where() coroutine.
This is probably simplest:
template<class F>
friend
enumerable<ReturnType> where2(enumerable<ReturnType> self, F f )
{
for (auto i : self.where(std::move(f)))
co_yield i;
}
template<class F>
enumerable<ReturnType> where(F f)&&
{
return where2(std::move(*this), std::move(f));
}
template<class F>
enumerable<ReturnType> where(F f)&
{
for (auto i : *this)
{
if (f(i))
co_yield i;
}
}
Is there a way to use for-range loop syntax to process two sequential elements in an array?
Example...
func( std::vector< vec2 > &points )
{
std::vector< float > distances;
for( int i = 0; i < (int)points.size() - 1; i++ )
{
auto from = points.at( i );
auto to = points.at( i + 1 );
distances.push_back( magnitude( to - from ) );
}
}
Is there a way to use for-range loop syntax to process two sequential elements in an array?
Not out of the box.
However, you can roll your own wrapper class and an iterator class to get what you need.
The begin() and end() member functions of the wrapper class must return an iterator which evaluates to a std::pair when it is dereferenced with the * operator.
Here's a demonstrative program:
#include <iostream>
#include <vector>
struct VectorWrapper;
struct MyIterator
{
MyIterator(VectorWrapper const& wrapper, size_t index) : wrapper_(wrapper), index_(index) {}
std::pair<float, float> operator*();
MyIterator& operator++()
{
++index_;
return *this;
}
bool operator==(MyIterator const& rhs) const
{
return (this->index_ == rhs.index_);
}
bool operator!=(MyIterator const& rhs) const
{
return (this->index_ != rhs.index_);
}
VectorWrapper const& wrapper_;
size_t index_;
};
struct VectorWrapper
{
explicit VectorWrapper(std::vector<float>& distances) : distances_(distances) {}
MyIterator begin() const
{
return MyIterator(*this, 0);
}
MyIterator end() const
{
return MyIterator(*this, distances_.size()-1);
}
std::vector<float>& distances_;
};
std::pair<float, float> MyIterator::operator*()
{
return std::make_pair(wrapper_.distances_[index_], wrapper_.distances_[index_+1]);
}
int main()
{
std::vector<float> dist = {1, 2, 3, 4, 5, 6};
VectorWrapper wrapper(dist);
for ( auto item : wrapper )
{
std::cout << item.first << ", " << item.second << std::endl;
}
}
and its output:
1, 2
2, 3
3, 4
4, 5
5, 6
In c++17 with a bit of library help, you can get this to work:
for (auto&&[ from, to ] : adjacent_overlapped_zip( points ) ) {
distances.push_back( magnitude( to-from) );
}
where adjacent_overlapped_zip returns a range of adpted iterators over pairs or tuples of points.
template<class It>
struct range {
It b; It e;
It begin() const{ return b; }
It end() const{ return e; }
bool empty() const{ return begin()==end(); }
range without_front( std::size_t n = 1 ) const {
return {std::next(begin(), n), end()};
}
range without_back( std::size_t n = 1 ) const {
return {begin(), std::prev(end(), n)};
}
};
template<class It>
range(It b, It e)->range<It>;
template<class It>
struct adjacent_iterator:It {
auto operator*()const {
return std::make_pair( It::operator*(), std::next(*this).It::operator*() );
}
using It::It;
explicit adjacent_iterator(It it):It(it) {}
};
template<class It>
explicit adjacent_iterator( It ) -> adjacent_iterator<It>;
// TODO: support pointers
template<class C>
auto adjacent_overlapped_zip( C& c ) {
using std::begin; using std::end;
range r( begin(c), end(c) );
if (!r.empty()) {
r = r.without_back();
range retval( adjacent_iterator(r.begin()), adjacent_iterator(r.end()) );
return retval;
} else {
return {};
}
}
or something like that. The above code probably contains typos and other errors.
I'd also be tempted by:
for (auto&&[ from, to ] : transform( [](auto it){ return std::make_pair( *it, *std::next(it)); }, range( iterators_of( points ) ).without_back() ) )
distances.push_back( magnitude( to-from) );
}
with a slightly fancier set of primitives. Ranges-v3 would make this even nicer.
In raw c++11, no you are out of luck.
This question already has answers here:
How can I print a list of elements separated by commas?
(34 answers)
Closed 2 years ago.
I'm trying to print a comma separated list of a single detail from a std::vector<MyClass>. So far the simplest and cleverest way I have seen to do this is to use
std::ostringstream ss;
std::copy(vec.begin(), vec.end() - 1, std::ostream_iterator<std::string>(ss, ", "))
ss << vec.back();
That worked fine when I was printing a vector of strings. However, now I am trying to print a single detail about MyClass. I know in Python I could do something like
(x.specific_detail for x in vec)
to get a generator expression for the thing that I am interested in. I'm wondering if I can do something similar here or if I am stuck doing
for (auto it = vec.begin(); it != vec.end(); ++it) {
// Do stuff here
}
One way of solving this I have seen is:
std::string separator;
for (auto x : vec) {
ss << separator << x.specific_detail;
separator = ",";
}
A fairly easy and reusable way:
#include <vector>
#include <iostream>
template<class Stream, class T, class A>
Stream& printem(Stream&os, std::vector<T, A> const& v)
{
auto emit = [&os, need_comma = false](T const& x) mutable
{
if (need_comma) os << ", ";
os << x;
need_comma = true;
};
for(T const& x : v) emit(x);
return os;
}
int main()
{
auto v = std::vector<int> { 1, 2, 3, 4 , 5 };
printem(std::cout, v) << std::endl;
}
And another way which defines an extendable protocol for printing containers:
#include <vector>
#include <iostream>
template<class Container>
struct container_printer;
// specialise for a class of container
template<class T, class A>
struct container_printer<std::vector<T, A>>
{
using container_type = std::vector<T, A>;
container_printer(container_type const& c) : c(c) {}
std::ostream& operator()(std::ostream& os) const
{
const char* sep = "";
for (const T& x : c) {
os << sep << x;
sep = ", ";
}
return os;
}
friend std::ostream& operator<<(std::ostream& os, container_printer const& cp)
{
return cp(os);
}
container_type c;
};
template<class Container>
auto print_container(Container&& c)
{
using container_type = typename std::decay<Container>::type;
return container_printer<container_type>(c);
}
int main()
{
auto v = std::vector<int> { 1, 2, 3, 4 , 5 };
std::cout << print_container(v) << std::endl;
}
...of course we can go further...
#include <vector>
#include <iostream>
template<class...Stuff>
struct container_printer;
// specialise for a class of container
template<class T, class A, class Separator, class Gap, class Prefix, class Postfix>
struct container_printer<std::vector<T, A>, Separator, Gap, Prefix, Postfix>
{
using container_type = std::vector<T, A>;
container_printer(container_type const& c, Separator sep, Gap gap, Prefix prefix, Postfix postfix)
: c(c)
, separator(sep)
, gap(gap)
, prefix(prefix)
, postfix(postfix) {}
std::ostream& operator()(std::ostream& os) const
{
Separator sep = gap;
os << prefix;
for (const T& x : c) {
os << sep << x;
sep = separator;
}
return os << gap << postfix;
}
friend std::ostream& operator<<(std::ostream& os, container_printer const& cp)
{
return cp(os);
}
container_type c;
Separator separator;
Gap gap;
Prefix prefix;
Postfix postfix;
};
template<class Container, class Sep = char, class Gap = Sep, class Prefix = char, class Postfix = char>
auto print_container(Container&& c, Sep sep = ',', Gap gap = ' ', Prefix prefix = '[', Postfix postfix = ']')
{
using container_type = typename std::decay<Container>::type;
return container_printer<container_type, Sep, Gap, Prefix, Postfix>(c, sep, gap, prefix, postfix);
}
int main()
{
auto v = std::vector<int> { 1, 2, 3, 4 , 5 };
// json-style
std::cout << print_container(v) << std::endl;
// custom
std::cout << print_container(v, " : ", " ", "(", ")") << std::endl;
// custom
std::cout << print_container(v, "-", "", ">>>", "<<<") << std::endl;
}
expected output:
[ 1,2,3,4,5 ]
( 1 : 2 : 3 : 4 : 5 )
>>>1-2-3-4-5<<<
Here's an example using std::transform:
#include <vector>
#include <string>
#include <iterator>
#include <algorithm>
#include <iostream>
int main()
{
std::vector<std::string> strs = {"Testing", "One", "Two", "Three"};
if (!strs.empty())
{
std::copy(std::begin(strs), std::prev(std::end(strs)), std::ostream_iterator<std::string>(std::cout, ", "));
std::cout << strs.back();
}
std::cout << '\n';
if (!strs.empty())
{
std::transform(std::begin(strs), std::prev(std::end(strs)), std::ostream_iterator<size_t>(std::cout, ", "),
[](const std::string& str) { return str.size(); });
std::cout << strs.back().size();
}
std::cout << '\n';
}
Output:
Testing, One, Two, Three
7, 3, 3, 5
Here is a tiny simple range library:
template<class It>
struct range_t {
It b, e;
It begin() const { return b; }
It end() const { return e; }
bool empty() const { return begin()==end(); }
std::size_t size() const { return std::distance( begin(), end() ); }
range_t without_front( std::size_t n = 1 ) const {
n = (std::min)(size(), n);
return {std::next(b, n), e};
}
range_t without_back( std::size_t n = 1 ) const {
n = (std::min)(size(), n);
return {b, std::prev(e, n)};
}
range_t only_front( std::size_t n = 1 ) const {
n = (std::min)(size(), n);
return {b, std::next(b, n)};
}
range_t only_back( std::size_t n = 1 ) const {
n = (std::min)(size(), n);
return {std::prev(end(), n), end()};
}
};
template<class It>
range_t<It> range(It s, It f) { return {s,f}; }
template<class C>
auto range(C&& c) {
using std::begin; using std::end;
return range( begin(c), end(c) );
}
now we are ready.
auto r = range(vec);
for (auto& front: r.only_front()) {
std::cout << front.x;
}
for (auto& rest: r.without_front()) {
std::cout << "," << rest.x;
}
Live example.
Now you can get fancier. boost transform iterators, together with boost range, let you do something similar to a list comprehension in python. Or Rangesv3 library for C++2a.
Writing a transform input iterator isn't amazingly hard, it is just a bunch of boilerplate. Simply look at the axioms of input iterator, write a type that stores an arbitrary iterator and forwards most methods to it.
It also stores some function. On * and ->, call the function on the dereferenced iterator.
template<class It, class F>
struct transform_iterator_t {
using reference=std::result_of_t<F const&(typename std::iterator_traits<It>::reference)>;
using value_type=reference;
using difference_type=std::ptrdiff_t;
using pointer=value_type*;
using iterator_category=std::input_iterator_tag;
using self=transform_iterator_t;
It it;
F f;
friend bool operator!=( self const& lhs, self const& rhs ) {
return lhs.it != rhs.it;
}
friend bool operator==( self const& lhs, self const& rhs ) {
return !(lhs!=rhs);
}
self& operator++() {
++it;
return *this;
}
self operator++(int) {
auto r = *this;
++*this;
return r;
}
reference operator*() const {
return f(*it);
}
pointer operator->() const {
// dangerous
return std::addressof( **this );
}
};
template<class F>
auto iterator_transformer( F&& f ) {
return [f=std::forward<F>(f)](auto it){
return transform_iterator_t<decltype(it), std::decay_t<decltype(f)>>{
std::move(it), f
};
};
}
template<class F>
auto range_transfromer( F&& f ) {
auto t = iterator_transformer(std::forward<F>(f));
return [t=std::move(t)](auto&&...args){
auto tmp = range( decltype(args)(args)... );
return range( t(tmp.begin()), t(tmp.end()) );
};
}
Live example of transformer.
And if we add -- we can even use ostream iterator.
Note that std::prev requires a bidirectional iterator, which requires forward iterator concept, which requires that the transform iterator return an actual reference, which is a pain.
You can use the exact code you already have, just change the type you pass to std::ostream_iterator to restrict its output:
class MyClassDetail {
const MyClass &m_cls;
public:
MyClassDetail(const MyClass &src) : m_cls(src) {}
friend std::ostream& operator<<(std::ostream &out, const MyClassDetail &in) {
return out << in.m_cls.specific_detail;
}
};
std::copy(vec.begin(), vec.end()-1, std::ostream_iterator<MyClassDetail>(ss, ", "));
ss << MyClassDetail(vec.back());
Live demo
Here's what was ultimately used
// assume std::vector<MyClass> vec
std::ostringstream ss;
std::for_each(vec.begin(), vec.end() - 1,
[&ss] (MyClass &item) {
ss << item.specific_detail << ", ";
}
);
ss << vec.back().specific_detail;
You can simply the exact same code, but define a operator<< overload:
ostream &operator<<(ostream& out)
{
out << m_detail;
}
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
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.