Chaining Iterators for C++

Chaining iterators for C++

Came across this question while investigating for a similar problem.

Even if the question is old, now in the time of C++ 11 and boost 1.54 it is pretty easy to do using the Boost.Range library. It features a join-function, which can join two ranges into a single one. Here you might incur performance penalties, as the lowest common range concept (i.e. Single Pass Range or Forward Range etc.) is used as new range's category and during the iteration the iterator might be checked if it needs to jump over to the new range, but your code can be easily written like:

#include <boost/range/join.hpp>

#include <iostream>
#include <vector>
#include <deque>

int main()
{
std::deque<int> deq = {0,1,2,3,4};
std::vector<int> vec = {5,6,7,8,9};

for(auto i : boost::join(deq,vec))
std::cout << "i is: " << i << std::endl;

return 0;
}

iterator over multiple std containers subsequently

Nothing to stop you from rolling your own. Can even make it random access!

struct chain_iterator 
: std::iterator<std::random_access_iterator_tag, int>
{
using it = std::vector<int>::iterator;

std::pair<it, it> v1, v2;
bool first;
it cur;
};

We keep the initial iterator pairs so that we can do random access correctly.

Incrementing is what you'd expect:

chain_iterator& operator++() {
++cur;
if (first && cur == v1.second) {
first = false;
cur = v2.first;
}
return *this;
}

Dereference is trivial:

int& operator*() { return *cur; }

Advance has to do some extra checking:

chain_iterator& operator+=(size_t n) {
if (!first) {
// trivial case
cur += n;
}
else {
size_t d = v1.second - cur;
if (d < n) {
cur += n;
}
else {
first = false;
cur = v2.first + (d - n);
}
}
return *this;
}

I'll leave the rest of the operations as an exercise.

Chaining IEnumerables in C#?

Try SelectMany.

IEnumerable<int> Collapse(IEnumerable<IEnumerable<int>> e){
return e.SelectMany(x => x );
}

The purpose of this function is to flatten a group of IEnumerable<IEnumerable<T>> into an IEnumerable<T>. The returned data will preserve the original order.

How to iterate over few containers in sequence?

With range-v3, you may do

const std::vector<std::string> v1{"A", "B", "C"}, v2{"D", "E", "F"};

for (const auto& s : ranges::view::concat(v1, v2)) {
std::cout << s << std::endl;
}

Demo

C Pre-processing: Chaining defines together

The key piece here is that you want to paste together the token canREG with the token 1 that came from the expansion of COMMS_WD_PORT. Since the tokens pasted with ## are not normally subject to macro expansion, you need double indirection as explained in C: Expand Macro With Token Pasting.

Stealing ouah's example, we can do the following, with an auxiliary CANREG macro to simplify things a little bit:

#define COMMS_WD_PORT 1
#define COMMS_WD_TXRX CAN_TX

#define CAT(x, y) CAT_(x, y)
#define CAT_(x, y) x ## y

#define CANREG CAT(canREG, COMMS_WD_PORT)

#if COMMS_WD_TXRX == CAN_TX
#define COMMS_WD_REG (uint32_t*)CANREG->TIOC
#else
#define COMMS_WD_REG (uint32_t*)CANREG->RIOC
#endif

Now COMMS_WD_REG expands to (uint32_t*)canREG1->TIOC as desired. Try it on godbolt.

How to apply chaining-associativity in C++17

I realized my first suggestion to use std::is_sorted() wouldn't work in the case of two adjacent elements with the same value - they're sorted, but not increasing. But if you want to use standard algorithms and not do it with a hand-written loop, std::adjacent_find() works:

#include <algorithm>
#include <iostream>
#include <vector>

// Version using an explicit binary predicate
template <class It, class F>
bool increasing(const It beg, const It end, F op) {
return std::adjacent_find(beg, end, [&op](const auto &a, const auto &b) {
return !op(a, b);
}) == end;
}

// Version using <
template <class It> bool increasing(const It beg, const It end) {
return std::adjacent_find(beg, end, [](const auto &a, const auto &b) {
return !(a < b);
}) == end;
}

int main() {
std::vector<int> v1{1, 2, 3}, v2{3, 2, 1}, v3{3, 2, 1, 2};

std::cout << std::boolalpha;
std::cout << "v1 increasing: " << increasing(v1.begin(), v1.end()) << '\n';
std::cout << "v2 increasing: "
<< increasing(v2.begin(), v2.end(), std::less<int>()) << '\n';
std::cout << "v3 increasing: " << increasing(v3.begin(), v3.end()) << '\n';
return 0;
}

gives

v1 increasing: true
v2 increasing: false
v3 increasing: false


Related Topics



Leave a reply



Submit