I trying to implement an unserialization method that take an input iterator and perform a series of chunk reads (using std::copy and std::copy_n). Something like this (just an example):
template <class InputIt>
InputIt unserialize(InputIt it)
{
std::copy_n(it, sizeof(header_type), reinterpret_cast<char*>(&header));
std::copy_n(it, header.payload_size, std::back_inserter(payload));
it = optional.unserialize(it);
return it;
}
How do I advance input iterator in this case so each following call to std::copy_n continue read from it and I can finally return it?
I want to be generic to iterator categories (especially RandomAccessIterator and InputIterator) for performance reasons and hope it is possible to use std::copy methods without need to rewrite these. Stuff like bound checking and such will be done by iterator adapter or checked before unserialization call if size is known.
What do not work nor acceptable:
Using std::copy_n<InputIt&>(it, ...) may work for some categories but not for all and it's too unreliable.
Using std::advance after each call leads to rereading same block again for some iterators. Not preferable and may be impossible for some sources.
UPDATE Making iterator reference adapter doesn't help as random access iterator version of copy_n return pointer to past the last element copied while input iterator version return pointer to the last element copied. So I guess own version of copy_n works best with additional iterator adapter for bound checking.
For random access iterator this form can be used - and it is fine:
template <class InputIt, class N, class OutputIt>
InputIt copy_n_advance_input(InputIt it, N dist, OutputIt outIt)
{
std::copy_n(it, dist, outIt);
return std::next(it, dist);
}
Unfortunately - problems are when we want to deal with one pass input iterator - like here (got 'd' - not 'c'):
std::string s = "abcd";
std::istringstream ss{s};
auto e = copy_n_advance_input(std::istream_iterator<char>(ss),
2,
std::ostream_iterator<char>(std::cout, ","));
std::cout << "\n" << *e << "\n";
So it seems it is needed, as usual in STL, two forms:
template <class InputIt, class N, class OutputIt>
InputIt copy_n_advance_input_impl(InputIt it, N dist, OutputIt outIt,
std::input_iterator_tag)
{
while (dist-- > 0)
{
*outIt = *it;
++outIt;
++it;
}
return it;
}
template <class InputIt, class N, class OutputIt>
InputIt copy_n_advance_input_impl(InputIt it, N dist, OutputIt outIt,
std::random_access_iterator_tag)
{
std::copy_n(it, dist, outIt);
return std::next(it, dist);
}
template <class InputIt, class N, class OutputIt>
InputIt copy_n_advance_input(InputIt it, N dist, OutputIt outIt)
{
return copy_n_advance_input_impl(it, dist, outIt, typename std::iterator_traits<InputIt>::iterator_category {});
}
Note, the proposed version for std::input_iterator_tag is not as efficient as in STL (at least for gcc) - it does extra iteration for input - this iteration is not necessary to perform copy - but it is needed to return beginning of "after copy" range (stl_algo.h):
754 template<typename _InputIterator, typename _Size, typename _OutputIterator>
755 _OutputIterator
756 __copy_n(_InputIterator __first, _Size __n,
757 _OutputIterator __result, input_iterator_tag)
758 {
759 if (__n > 0)
760 {
761 while (true)
762 {
763 *__result = *__first;
764 ++__result;
765 if (--__n > 0)
766 ++__first;
767 else
768 break;
769 }
770 }
771 return __result;
772 }
Last note - it is wiser to use, for random-access-iterators (like std::vector::iterator) the version that just calls std algorithms - because they can be even more optimized - e.g. for contiguous memory iterator over POD types - that can be just memcpy'ied. Or some specialization for std::vector<bool> or std::deque<T> exist, that uses their internal structure to perform copy in most efficient way.
You could create an iterator adapter that always works through a reference to the supplied iterator. Here's the basic skeleton of such an adapter:
#include <iterator>
template<typename InputIterator>
struct IteratorReference
{
InputIterator& it;
IteratorReference(InputIterator& it)
: it(it)
{}
// {copy, move, destructor} == default
// iterator methods (TODO: add the rest)
IteratorReference& operator++()
{ ++it; return this; }
typename InputIterator::reference operator*()
{ return *it; }
// Convert back to original iterator
operator InputIterator() const
{ return it; }
};
template<typename InputIterator>
IteratorReference<InputIterator> make_iterator_reference(InputIterator it)
{
return it;
}
To use it, simply create and use a wrapper in place of the original iterator:
#include <algorithm>
#include <vector>
struct Header
{
std::size_t payload_size;
};
template <class InputIt>
InputIt unserialize(InputIt it, Header& header, std::vector<char>& payload)
{
auto i_ref = make_iterator_reference(it);
std::copy_n(i_ref, sizeof header, reinterpret_cast<char*>(&header));
std::copy_n(i_ref, header.payload_size, std::back_inserter(payload));
i_ref = optional.unserialize(i_ref);
return i_ref;
}
I know this is an old question, but...
Recently I've run into similar issue, and I feel pretty sad when I see there isn't any good solution for this problem...
Nevertheless, I've tried to write an iterator wrapper like what Toby Speight said, and I've extended it a bit.
This wrapper is only used for InputIterator, because other kind of iterators supported by std::copy and std::copy_n are multipass iterators, and it's possible to directly use std::next and std::advance on them instead of using this wrapper.
template<typename Iterator>
struct Wrapper {
using traits = std::iterator_traits<Iterator>;
using difference_type = typename Traits::difference_type;
using reference = typename Traits::reference;
//...
reference operator*() const { return *(*(this->current)); }
//need implement operator++(int) too, in the similar way
Wrapper& operator++() {
if(this->indicator != 0) {
++(*(this->current));
--this->indicator;
}
return *this;
}
//need to implement operator!= too, in the similar way
bool operator==(const Wrapper& other) const {
return *(this->current) == *(other.current) or this->indicator == other.indicator;
}
Iterator* current;
difference_type indicator;
};
template<typename Iterator>
struct Range {
using category = typename std::iterator_traits<Iterator>::iterator_category;
//...
using difference_type = typename std::iterator_traits<Iterator>::difference_type;
constexpr bool isForwardOrAbove() {
return std::is_base_of_v<std::forward_iterator_tag, category>;
}
using iterator = std::conditional_t<isForwardOrAbove(), Iterator, Wrapper<Iterator>>;
std::pair<iterator, iterator> splitSubRange(difference_type n) {
if constexpr (isForwardOrAbove()) {
//forward iterators are multi-pass iterators, so using std::advance on one iterator will not invalidate its copies
auto oldBegin = this->begin;
std::advance(this->begin, n);
return {oldBegin, std::next(oldBegin, n)};
}
else {
//non-forward-iterator
return {{&(this->begin), n}, {&(this->end), 0}};
}
}
Iterator begin;
Iterator end;
}
To use them, firstly you need a Range object which holds iterators, and use the splitSubRange method to obtain plain iterators, or, if they are only InputIterators, iterator wrappers.
template<typename InputIterator>
InputIterator unserialize(InputIterator begin, InputIterator end) {
auto range = Range<InputIterator>{begin, end};
auto [begin, end] = range.splitSubRange(sizeof(header_type));
//before having "used" the iterator obtained from range, you shouldn't use range again.
std::copy(begin, end, header.begin());
//after having "used" the iterator, you can use the range object to obtain the next sub-range
auto [begin2, dummy] = range.splitSubRange(sizeof(header_type_2));
std::copy_n(begin2, sizeof(header_type_2), header2.begin());
...
return range.begin;
}
Related
I need to create a function which receives the iterator from the begin and the end of one container. Then it should show the content in the console.
My problem is that i dont know how to declare the iterator so that it can work with any type of container
This is what I did:
template <class T>
void print(typename iterator<T> &beg, typename iterator<T> &end) {
while (beg != end) {
cout << *beg << endl;
beg++;
}
}
The std::iterator class is really just a convenience; there's nothing in the standard that requires all iterators to inherit from it. Additionally, std::iterator doesn't have virtual methods, so it's not nearly the same thing as taking an Iterator<T> in, say, Java, where invoking the next() method would call the appropriate next(). You want to take a general type T, not just an std::iterator, so that the compiler will resolve to the correct overloads of operator++ and operator* at compile-time.
template <typename T>
void print(T iter, const T& end) {
// Taking the first argument by value ensures that
// we don't modify the caller's variables
while (iter != end) {
cout << *iter << endl;
++iter;
}
}
This will work for any forward iterators, which is what you're dealing with 99% of the time.
I need to create a function which receives the iterator from the begin
and the end of one container.
Look how standard functions do it, for example std::find:
template< class InputIt, class T >
InputIt find( InputIt first, InputIt last, const T& value );
Observations:
InputIt does not need to inherit from the (now obsolete) std::iterator class or any other class. Among other advantages, this allows the function to be used with an array.
The same iterator type is used for start and end.
The iterators are passed by value.
The template parameter does not specify the iterators' value type.
Just do it exactly like that in your own code and you'll be fine:
#include <iostream>
#include <vector>
template <class Iterator> // not T
void print(Iterator beg, Iterator end) {
while (beg != end) {
std::cout << *beg << '\n';
beg++;
}
}
int main() {
std::vector<int> const vec = { 1, 2, 3 };
int const array[] = { 1, 2, 3 };
using std::begin;
using std::end;
print(begin(vec), end(vec));
print(begin(array), end(array));
}
Consider an STL container C that is forward-iteratable. I need to access every step element, starting from idx. If C is a vector (i.e. has a random-access iterator) I can just use index arithmetic:
template <class Container>
void go(const Container& C) {
for(size_t i = idx; i<C.size(); i+=step) {
/* do something with C[i] */
}
}
However, if C does not support that, e.g. C is a list, one needs to rewrite the above solution. A quick attempt would be:
template <class Container>
void go(const Container& C) {
size_t max = C.size();
size_t i = idx;
for(auto it = std::next(C.begin(),idx); i < max; i+=step, it+=step) {
/* do something with *it */
}
}
Not much longer and it works... except that most likely it will trigger the undefined behavior. Both std::next and it+=step can potentially step way beyond the C.end() before i < max check is performed.
The solution I am currently using (not shown) is really bloated when compared to the initial for. I have separate check for the first iteration and those that follows. A lot of boilerplate code...
So, my question is, can the above pattern be written in a safe, and succinct way? Imagine you want to nest these loops 2 or 3 times. You don't want the whole page of code for that!
The code should be reasonably short
The code should have no overhead. Doing std::next(C.begin(), i) in each iteration over i is unnecessairly long, if you can just std::advance(it, step) instead.
The code should benefit from the case when it is indeed a random-access iterator when std::advance can be performed in constant time.
C is constant. I do not insert, erase or modify C within the loop.
You might use helper functions:
template <typename IT>
IT secure_next(IT it, std::size_t step, IT end, std::input_iterator_tag)
{
while (it != end && step--) {
++it;
}
return it;
}
template <typename IT>
IT secure_next(IT it, std::size_t step, IT end, std::random_access_iterator_tag)
{
return end - it < step ? end : it + step;
}
template <typename IT>
IT secure_next(IT it, std::size_t step, IT end)
{
return secure_next(it, step, end, typename std::iterator_traits<IT>::iterator_category{});
}
And then:
for (auto it = secure_next(C.begin(), idx, C.end());
it != C.end();
it = secure_next(it, step, C.end()) {
/* do something with *it */
}
Alternatively, with range-v3, you could do something like:
for (const auto& e : C | ranges::view::drop(idx) | ranges::view::stride(step)) {
/* do something with e */
}
The comment in the question about the requirements inspired me to implement this in terms of k * step instead of some other mechanism controlling the number of iterations over the container.
template <class Container>
void go(const Container& C)
{
const size_t sz = C.size();
if(idx >= sz) return;
size_t k_max = (sz - idx) / step + 1;
size_t k = 0
for(auto it = std::advance(C.begin(), idx); k < k_max && (std::advance(it, step), true); ++k) {
/* do something with *it */
}
}
One option is to adapt the iterator so that it is safe to advance past the end. Then you can use stock std::next(), std::advance(), pass it to functions expecting an iterator, and so on. Then the strided iteration can look almost exactly like you want:
template<class Container, class Size>
void iterate(const Container& c, Size idx, Size step)
{
if (unlikely(idx < 0 || step <= 0))
return;
bounded_iterator it{begin(c), c};
for (std::advance(it, idx); it != end(c); std::advance(it, step))
test(*it);
}
This is not dissimilar from the secure_next() suggestion. It is a little more flexible, but also more work. The range-v3 solution looks even nicer but may or may not be an option for you.
Boost.Iterator has facilities for adapting iterators like this, and it's also straightforward to do it directly. This is how an incomplete sketch might look for iterators not supporting random access:
template<class Iterator, class Sentinel, class Size>
class bounded_iterator
{
public:
using difference_type = typename std::iterator_traits<Iterator>::difference_type;
using value_type = typename std::iterator_traits<Iterator>::value_type;
using pointer = typename std::iterator_traits<Iterator>::pointer;
using reference = typename std::iterator_traits<Iterator>::reference;
using iterator_category = typename std::iterator_traits<Iterator>::iterator_category;
template<class Container>
constexpr explicit bounded_iterator(Iterator begin, const Container& c)
: begin_{begin}, end_{end(c)}
{
}
constexpr auto& operator++()
{
if (begin_ != end_)
++begin_;
return *this;
}
constexpr reference operator*() const
{
return *begin_;
}
friend constexpr bool operator!=(const bounded_iterator& i, Sentinel s)
{
return i.begin_ != s;
}
// and the rest...
private:
Iterator begin_;
Sentinel end_;
};
template<class Iterator, class Container>
bounded_iterator(Iterator, const Container&) -> bounded_iterator<Iterator, decltype(end(std::declval<const Container&>())), typename size_type<Container>::type>;
And for random access iterators:
template<RandomAccessIterator Iterator, class Sentinel, class Size>
class bounded_iterator<Iterator, Sentinel, Size>
{
public:
using difference_type = typename std::iterator_traits<Iterator>::difference_type;
using value_type = typename std::iterator_traits<Iterator>::value_type;
using pointer = typename std::iterator_traits<Iterator>::pointer;
using reference = typename std::iterator_traits<Iterator>::reference;
using iterator_category = typename std::iterator_traits<Iterator>::iterator_category;
template<class Container>
constexpr explicit bounded_iterator(Iterator begin, const Container& c)
: begin_{begin}, size_{std::size(c)}, index_{0}
{
}
constexpr auto& operator+=(difference_type n)
{
index_ += n;
return *this;
}
constexpr reference operator*() const
{
return begin_[index_];
}
friend constexpr bool operator!=(const bounded_iterator& i, Sentinel)
{
return i.index_ < i.size_;
}
// and the rest...
private:
const Iterator begin_;
const Size size_;
Size index_;
};
As an aside, it seems GCC produces slightly better code with this form than with my attempts at something like secure_next(). Can its optimizer reason better about indices than pointer arithmetic?
This example is shared also via gist and godbolt.
I want to fill a container by consequtive values of iterators to elements of another container (often occured real life problem), say:
std::container1< T > c1{/* initialized */};
assert(!c1.empty());
std::continer2< typename std::container1< T >::iterator > c2;
auto it = std::begin(c1), const end = std::end(c1);
do { c2.push_back(it); } while (++it != end);
There is attractive std::iota algorithm in STL, but it is range-based and for std::back_inserter(c2) there is no way to achieve desired currently. However in the next versions of STL I can expect the iota algorithm of the form:
template< typename ForwardIterator, typename EndSentinel, typename T >
void
iota(ForwardIterator first, EndSentinel last, T value)
{
for (; first != last; ++first) {
*first = value;
++value;
}
}
How to implement EndSentinel and operator != (ForwardIterator, EndSentinel) to make above iota stop after exactly c1.size() step of the for loop in iota(std::back_inserter(c1), something(c1, c1.size()), std::begin(c1))?
There is no sentinel for std::back_insert_iterator (or any OutputIterator) and also no equality operator, because an output iterator is an "unlimited sequence": You can append elements to the end of a container or write to a file until you run out of memory or disk space.
However, it makes sense to have an output iterator with a sentinel if you need to call an algorithm which expects an "output sentinel" (because not expecting one may be unsafe if the output is a "limited sequence", such as a pre-allocated std::vector). Such an algorithm could look like:
template<typename InIter, typename InSentinel, typename OutIter, typename OutSentinel>
OutIter modernAlgorithm(InIter first, InSentinel last, OutIter outFirst, OutSentinel outLast);
In this case, all you need is a trivial sentinel, which compares unequal to everything. See also this answer.
template<typename T>
struct TrivialSentinel
{
bool operator==(const T&) { return false; }
bool operator!=(const T&) { return true; }
friend bool operator==(const T&, TrivialSentinel&) { return false; }
friend bool operator!=(const T&, TrivialSentinel&) { return true; }
};
modernAlgorithm(v.begin(), v.end(), std::back_inserter(r), TrivialSentinel<decltype(std::back_inserter(r))>());
(This may seem odd, but it does make sense if you consider that even if you repeat the same operation *out = expr on the same value of out, the output will be in a different state each time, so in a certain sense, no two output iterators are ever necessarily equivalent...)
However, older algorithms often don't allow the iterator and sentinel to have different types:
template<typename InIter, typename OutIter>
OutIter olderAlgorithm(InIter first, InIter last, OutIter outFirst, OutIter outLast);
In this case, you can write a sub class or wrapper of std::back_insert_iterator, which has a default constructor and always compares unequal to itself.
This is easy in C++20, where std::back_insert_iterator has a default constructor:
// C++20
template<typename C>
struct BackInsertIteratorWithSentinel : public std::back_insert_iterator<C>
{
BackInsertIteratorWithSentinel() {} // C++20 only
BackInsertIteratorWithSentinel(C& c) : std::back_insert_iterator<C>(c) {}
bool operator==(const BackInsertIteratorWithSentinel&) { return false; }
bool operator!=(const BackInsertIteratorWithSentinel&) { return true; }
};
template<typename C>
BackInsertIteratorWithSentinel<C> BackInserterWithSentinel(C& c)
{
return BackInsertIteratorWithSentinel<C>(c);
}
template<typename C>
BackInsertIteratorWithSentinel<C> BackInserterWithSentinel()
{
return BackInsertIteratorWithSentinel<C>();
}
olderAlgorithm(v.begin(), v.end(), BackInserterWithSentinel(r), BackInserterWithSentinel<std::vector<int> >());
Note that even in C++20, std::back_insert_iterator does not have an equality operator.
If you have to support older versions of C++, then you may have to implement your own std::back_insert_iterator from scratch, or use boost::optional or in-place construction to work around the lack of a default constructor.
Full test program for C++20
I dont think you can do it - or maybe I dont understand your question, but..
according to http://en.cppreference.com/w/cpp/algorithm/iota, this algorithm works on existing range of elements - so it does not make sense to use it with: std::back_inserter as first iterator which basicly is used to insert elements.
I want to fill a container by consequtive values of iterators to elements of another container
a different solution which uses generate_n:
live
std::vector<int> src = {0,1,2,3};
std::vector<std::vector<int>::iterator> dst;
std::generate_n(std::back_inserter(dst), src.size(), [it=src.begin()]() mutable {return it++;});
Your question includes an iota implementation which is different than the one in the standard I believe. Here is the standard version I know http://en.cppreference.com/w/cpp/algorithm/iota.
Your iota (which I will rename it as miota in my code) allows different type of iterators for begin and end.
What you want in the algorithm is; end sentinel needs to be different from begin (the inserter) until all values are processed. For processing values you only take one object and you use increment and copy-construction on that object.
Therefore, your end sentinel should know about the value processing and when finished the end sentinel should become equal to the inserter somehow.
I did it via holding begin/end iterators of the original container in a class called IotaHelper. This uses shared_ptr for sharing state with the sentinel class which is called IotaEndSentinel.
When you increment the value inside miota, it actually increments the begin iterator of the IotaHelper. When you check equality with the inserter and the sentinel it actually checks the iterator equality inside the IotaHelper.
All code with a basic example is here:
#include <iterator>
#include <numeric>
#include <vector>
#include <iostream>
#include <utility>
#include <memory>
template< typename ForwardIterator, typename EndSentinel, typename T >
void miota(ForwardIterator first, EndSentinel last, T value)
{
for (; first != last; ++first) {
*first = value;
++value;
}
}
template<typename Container>
struct IotaHelper
{
using Iterator = typename Container::iterator;
using IteratorPair = std::pair<Iterator, Iterator>;
IotaHelper(Iterator begin, Iterator end)
:
pair(std::make_shared<IteratorPair>(begin, end))
{ }
operator Iterator()
{
return pair->first;
}
IotaHelper& operator++()
{
++pair->first;
return *this;
}
std::shared_ptr<IteratorPair> pair;
};
template<typename Container>
struct IotaEndSentinel
{
using Helper = IotaHelper<Container>;
using Iterator = typename Helper::Iterator;
IotaEndSentinel(const Helper& helper)
:
helper(helper)
{}
template<typename C>
friend bool operator!=(const std::back_insert_iterator<C>& bii,
const IotaEndSentinel& sentinel)
{
return sentinel.helper.pair->first != sentinel.helper.pair->second;
}
Helper helper;
};
int main()
{
using Container0 = std::vector<int>;
using Container1 = std::vector<Container0::iterator>;
Container0 c0 = {1, 2, 3, 4, 5};
Container1 c1;
IotaHelper<Container0> iotaHelper(c0.begin(), c0.end());
miota(std::back_inserter(c1),
IotaEndSentinel<Container0>(iotaHelper),
iotaHelper);
std::cout << "Result: ";
for (auto iter : c1)
{
std::cout << *iter << ", ";
}
std::cout << std::endl;
}
I have tried to do this because it was fun. But please don't use this method for hacking output iterators like back_insert_iterator and make a generic method for yourself for different containers.
template<typename SourceContainer, typename IteratorContainer>
void FillIterators(SourceContainer& sc, IteratorContainer& ic)
{
for (auto iter = sc.begin(); iter != sc.end(); ++iter)
{
ic.insert(ic.end(), iter);
}
}
EDIT:
After using heap-allocation that code was smelling to me. Instead of trying to reason about the "value and the process" we can reason about the "iterators and the process".
We can build an iterator-wrapper which contains the process iterator and the insert iterator together.
When the algorithm needs to dereference the wrapper, it will return the insert iterator.
When the algorithm needs to compare to other "wrapper or sentinel", wrapper will compare the process iterator.
In the end we can use such iterator for both std::iota and your miota.
Complete example is here:
#include <iterator>
#include <numeric>
#include <vector>
#include <iostream>
#include <utility>
#include <memory>
template< typename ForwardIterator, typename EndSentinel, typename T >
void miota(ForwardIterator first, EndSentinel last, T value)
{
for (; first != last; ++first) {
*first = value;
++value;
}
}
template<typename InsertIterator, typename Iterator>
struct InsertWrapper
{
InsertWrapper(const InsertIterator& inserter, const Iterator& iter)
:
inserter(inserter),
iter(iter)
{ }
bool operator!=(const InsertWrapper& other) const
{
//only compare process iterators
return iter != other.iter;
}
bool operator!=(const Iterator& sentinel) const
{
//compare process iterator against the sentinel
return iter != sentinel;
}
InsertIterator& operator*()
{
//return inserter for dereference
return inserter;
}
InsertWrapper& operator++()
{
//iterate inserter as the process progresses
++inserter;
++iter;
return *this;
}
InsertIterator inserter;
Iterator iter;
};
template<typename InsertIterator, typename Iterator>
InsertWrapper<InsertIterator, Iterator> WrapInserter(const InsertIterator& inserter,
const Iterator& iter)
{
return InsertWrapper<InsertIterator, Iterator>(inserter, iter);
}
int main()
{
using Container0 = std::vector<int>;
using Container1 = std::vector<Container0::iterator>;
Container0 c0 = {1, 2, 3, 4, 5};
Container1 c1;
//use wrapper as usual iterator begin/end
std::iota(WrapInserter(std::back_inserter(c1), c0.begin()),
WrapInserter(std::back_inserter(c1), c0.end()),
c0.begin());
std::cout << "std::iota result: ";
for (auto iter : c1)
{
std::cout << *iter << ", ";
}
std::cout << std::endl;
c1.clear();
miota(WrapInserter(std::back_inserter(c1), c0.begin()),
c0.end(), //end iterator as sentinel
c0.begin());
std::cout << "miota result: ";
for (auto iter : c1)
{
std::cout << *iter << ", ";
}
std::cout << std::endl;
}
I currently have this code up and running:
string word="test,";
string::iterator it = word.begin();
for (; it != word.end(); it++)
{
if (!isalpha(*it)) {
break;
}
else {
*it = toupper(*it);
}
}
word.erase(it, word.end());
// word should now be: TEST
I would like to make it more compact and readable it by:
Composing existing standard C++ algorithms (*)
Perform the loop only once
(*) I'm assuming that combining existing algorithms makes my code more readable...
An alternative solution
In addition to defining a custom transform_until algorithm, as suggested by jrok, it might be possible to define a custom iterator adaptor that would iterate using the underlying iterator but redefine operator*() by modifying the underlying reference before returning it.
Something like that:
template <typename Iterator, typename UnaryFunction = typename Iterator::value_type (*)(typename Iterator::value_type)>
class sidefx_iterator: public std::iterator<
typename std::forward_iterator_tag,
typename std::iterator_traits<Iterator>::value_type,
typename std::iterator_traits<Iterator>::difference_type,
typename std::iterator_traits<Iterator>::pointer,
typename std::iterator_traits<Iterator>::reference >
{
public:
explicit sidefx_iterator(Iterator x, UnaryFunction fx) : current_(x), fx_(fx) {}
typename Iterator::reference operator*() const { *current_ = fx_(*current_); return *current_; }
typename Iterator::pointer operator->() const { return current_.operator->(); }
Iterator& operator++() { return ++current_; }
Iterator& operator++(int) { return current_++; }
bool operator==(const sidefx_iterator<Iterator>& other) const { return current_ == other.current_; }
bool operator==(const Iterator& other) const { return current_ == other; }
bool operator!=(const sidefx_iterator<Iterator>& other) const { return current_ != other.current_; }
bool operator!=(const Iterator& other) const { return current_ != other; }
operator Iterator() const { return current_; }
private:
Iterator current_;
UnaryFunction fx_;
};
Of course this is still very raw, but it should give the idea.
With the above adaptor, I could then write the following:
word.erase(std::find_if(it, it_end, std::not1(std::ref(::isalpha))), word.end());
with the following defined in advance (which could be simplified by some template-magic):
using TransformIterator = sidefx_iterator<typename std::string::iterator>;
TransformIterator it(word.begin(), reinterpret_cast<typename std::string::value_type(*)(typename std::string::value_type)>(static_cast<int(*)(int)>(std::toupper)));
TransformIterator it_end(word.end(), nullptr);
If the standard would include such an adaptor I would use it, because it would mean that it was flawless, but since this is not the case I'll probably keep my loop as it is.
Such an adaptor would allow to reuse existing algorithms and mixing them in different ways not possible today, but it might have downsides as well, which I'm likely overlooking at the moment...
I don't think there's a clean way to do this with a single standard algorithm. None that I know of takes a predicate (you need one to decide when to break early) and allows to modify the elements of the source sequence.
You can write your own generic algorithm if you really want to do it "standard" way. Let's call it, hmm, transform_until:
#include <cctype>
#include <string>
#include <iostream>
template<typename InputIt, typename OutputIt,
typename UnaryPredicate, typename UnaryOperation>
OutputIt transform_until(InputIt first, InputIt last, OutputIt out,
UnaryPredicate p, UnaryOperation op)
{
while (first != last && !p(*first)) {
*out = op(*first);
++first;
++out;
}
return first;
}
int main()
{
std::string word = "test,";
auto it =
transform_until(word.begin(), word.end(), word.begin(),
[](char c) { return !::isalpha(static_cast<unsigned char>(c)); },
[](char c) { return ::toupper(static_cast<unsigned char>(c)); });
word.erase(it, word.end());
std::cout << word << '.';
}
It's debatable whether this is any better than what you have :) Sometimes a plain for loop is best.
After better understanding your question, I have got an idea that might work, but requires Boost.
You could use a transform_iterator which calls toupper on all characters and use that as the inputiterator to find_if or remove_if. I am not familiar enough with Boost to provide an example though.
As #jrok points out, the transform_iterator will only transform the value during iteration and not actually modify the original container. To get around this, instead of operating on the same sequence, you would want to copy to a new one, using something like remove_copy_if. This copies as long as the predicate is NOT true, so std::not1 would be needed. This would replace the remove_if case.
Use std::copy to copy until the iterator returned by std::find_if to get the other case to work.
Finally, if your output string is empty, it will need a std::inserter type of iterator for the output.
(Inspired by a comment from nakiya)
Many STL algorithms take a range as a pair of iterators. For instance, for_each(begin, end, &foo);. Obviously, if distance(begin, end) >= N, and begin is a random-access iterator, then for_each(begin, begin+N, &foo); applies foo only to the first N elements.
Now is there a clean, generic alternative if either of these two conditions is not met?
There is no generic full solution without changing the iterator type.
Proof: suppose that the iterator type is only an InputIterator, so begin actually refers to (for example) a stream, and end is a special-case marker iterator, which will compare equal to the "real" iterator once the real iterator has read EOF.
Then any use of begin to try to work out a new value of end to pass to the algorithm, will "consume" the original value of begin, since that's how InputIterators work.
What you could do is write an iterator wrapper class, such that the iterator counts how many times it has been incremented, and compares equal to an "end" iterator once it has been incremented N times. N could be a template parameter, or a constructor parameter to one or other of the iterators.
Something like this. I've tested it compiles and works for me. Still to do - I'm currently only handling one of your two situations, "not a random-access iterator". I don't also handle the other, "distance < N".
#include <iterator>
template <typename It>
class FiniteIterator : public std::iterator<
typename std::iterator_traits<It>::iterator_category,
typename std::iterator_traits<It>::value_type> {
typedef typename std::iterator_traits<It>::difference_type diff_type;
typedef typename std::iterator_traits<It>::value_type val_type;
It it;
diff_type count;
public:
FiniteIterator(It it) : it(it), count(0) {}
FiniteIterator(diff_type count, It it = It()) : it(it), count(count) {}
FiniteIterator &operator++() {
++it;
++count;
return *this;
}
FiniteIterator &operator--() {
--it;
--count;
return *this;
}
val_type &operator*() const {
return *it;
}
It operator->() const {
return it;
}
bool operator==(const FiniteIterator &rhs) const {
return count == rhs.count;
}
bool operator!=(const FiniteIterator &rhs) const {
return !(*this == rhs);
}
FiniteIterator operator++(int) {
FiniteIterator cp = *this;
++*this;
return cp;
}
FiniteIterator operator--(int) {
FiniteIterator cp = *this;
--*this;
return cp;
}
};
Note that the second constructor only takes an iterator because the underlying type might not be default constructible (if it's only an InputIterator). In the case where the caller is creating an "end" iterator it doesn't use it, because it won't be valid once the other copy is incremented.
If the underlying iterator type is RandomAccess, then this wrapper isn't needed/wanted. So I provide a helper template function, that does the type deduction the same way back_inserter does for back_insert_iterator. However, in the case where its parameter type is an iterator of random-access category, the helper shouldn't return FiniteIterator<T>, but just T:
template <typename Iterator, typename Category>
struct finite_traits2 {
typedef FiniteIterator<Iterator> ret_type;
static ret_type plus(Iterator it, typename std::iterator_traits<Iterator>::difference_type d) {
return ret_type(d, it);
}
};
template <typename Iterator>
struct finite_traits2<Iterator, std::random_access_iterator_tag> {
typedef Iterator ret_type;
static ret_type plus(Iterator it, typename std::iterator_traits<Iterator>::difference_type d) {
return it + d;
}
};
template <typename Iterator>
struct finite_traits {
typedef typename std::iterator_traits<Iterator>::iterator_category itcat;
typedef typename finite_traits2<Iterator, itcat>::ret_type ret_type;
static ret_type plus(Iterator it, typename std::iterator_traits<Iterator>::difference_type d) {
return finite_traits2<Iterator, itcat>::plus(it, d);
}
};
template <typename Iterator, typename Distance>
typename finite_traits<Iterator>::ret_type finite_iterator(Iterator it, Distance d) {
return finite_traits<Iterator>::plus(it, d);
}
template <typename Iterator>
typename finite_traits<Iterator>::ret_type finite_iterator(Iterator it) {
return finite_traits<Iterator>::plus(it, 0);
}
Example usage (and minimal test):
#include <iostream>
#include <typeinfo>
#include <list>
struct MyIterator : std::iterator<std::bidirectional_iterator_tag, int> {
difference_type count;
};
int main() {
std::cout << typeid(MyIterator::iterator_category).name() << "\n";
std::cout << typeid(FiniteIterator<MyIterator>::iterator_category).name() << "\n";
std::cout << typeid(MyIterator::difference_type).name() << "\n";
std::cout << typeid(FiniteIterator<MyIterator>::difference_type).name() << "\n";
int a[] = {1, 2, 3, 4, 5};
std::copy(finite_iterator(a), finite_iterator(a,4), std::ostream_iterator<int>(std::cout, " "));
std::cout << "\n";
std::list<int> al(finite_iterator(a), finite_iterator(a,4));
std::cout << al.size() << "\n";
std::copy(finite_iterator(al.begin()), finite_iterator(al.begin(),3), std::ostream_iterator<int>(std::cout, " "));
std::cout << "\n";
}
Caution: finite_iterator(x, 1) == finite_iterator(++x, 0) is false, even for a forward iterator or better. Finite iterators are only comparable if they are created from the same starting point.
Also, this still isn't complete. For example std::reverse doesn't work, because for the purposes of accessing the referand, finite_iterator(x, 1) is "pointing at" x.
Currently the following happens to work:
std::list<int>::iterator e = al.begin();
std::advance(e,3);
std::reverse(finite_iterator(al.begin()), finite_iterator(e,3));
So I'm not far off, but that's not a good interface. I would need to think more about the case of Bidirectional iterators.
There is already fill_n and generate_n, there is no foreach_n (or for_n would probably be more appropriate) but it is easy enough to write one.
template< typename FwdIter, typename Op, typename SizeType >
void for_n( FwdIter begin, SizeType n, Op op )
{
while( n-- )
{
op(*begin);
++begin;
}
}
You could do op(*begin++) but although it is less typing it may generate more code to copy the iterator. size_type is numeric so doing post-increment is no less efficient and here is a case where it is useful.
I believe you could create a wrapper iterator type similar to boost::counting_iterator which would keep together both an increment and the underlying iterator, and would compare equal to an "end" iterator as soon as the increment exceeds the maximum value.