views:

225

answers:

2

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.

+3  A: 

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 ) );
    }
};
Potatoswatter
I think for cyclic iterators, `last` would be inequal to any other iterator, since it’s a (pseudo-)infinite sequence …
Konrad Rudolph
@Konrad: then everything in `<algorithm>` would be useless, and indeed you wouldn't have a compliant iterator at all.
Potatoswatter
@Potatocorn: “everything in `<algorithm>` would be useless.” Yes, that’s the nature of cyclic/infinite sequences. But *other* things work very well with them. A lot of frameworks use them without problem. “you wouldn't have a compliant iterator at all.” What gives you that idea? Nothing in the standard says so. In fact, input iterators *are* pseudo-infinite and have many of the same properties.
Konrad Rudolph
@Konrad: The standard does require iterators to be equal to themselves, so never being equal to anything would be noncompliant. Forward iterator sequences are typically terminated by a singular value, ie `my_fwd_iterator()`. Iterators and sequences go hand-in-hand, so failing to account for the empty sequence is going to be risky.
Potatoswatter
By the way, I don’t want to come over as contrary: I actually agree that the C++ standard library doesn’t support the usage of infinite iterators well. That’s a pity though, since they make a lot of complex logic very tractable. The introduction of ranges in C++0x would have changed that and we’d have seen “lazy” algorithms similar to Haskell’s/Python’s sequences or .NET’s Linq library. Unfortunately, that was scrapped but influential people such as Andrei Alexandrescu continue to support the idea, read <http://stackoverflow.com/questions/838721>
Konrad Rudolph
@Potatoswatter: That’s why I wrote “… inequal to **any other** iterator.” For a compliant, working example, see http://pastie.org/914078
Konrad Rudolph
@Konrad: fine, an iterator is also equal to a copy of itself. Your cyclic iterator exhibits what I'm talking about. No pair [first, last) of cyclic iterators can represent the entire cycle.
Potatoswatter
“Your cyclic iterator exhibits what I'm talking about.” Fine, so what are we arguing about? :-)“No pair [first, last) of cyclic iterators can represent the entire cycle.” Of course not, since a cycle by definition has no end.
Konrad Rudolph
@Konrad: Ranges are what we're arguing about. If you want an infinite sequence, you can use a cyclic iterator. But if you want a finite sequence, you can't predicate a loop on a comparison of cyclic iterators. That makes me question the value of paying any lip service to C++ iterators.
Potatoswatter
@Potatoswatter: The cycle count could be a template value, not necassairly need to be apart of the constructor. But i think it would be better if it were a constructor param.
Hippicoder
A: 

You’re maybe looking for Boost’s Circular Buffer. But if you’ve already checked Boost, it might not be the one you want.

Debilski
A circular buffer is more like a deque with a fixed capacity. It still has a `begin` and an `end`, no wraparound.
Potatoswatter
Yeah, but it’s easier to rotate.
Debilski