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
Qtcpsocket: Reading and Writing
Loop with a Zero Execution Time
How to Brace-Initialize an Std::Array of Std::Pairs
Int *Array = New Int[N]; What Is This Function Actually Doing
What Are Use Cases for Structured Bindings
Eclipse C++:"Program "G++" Not Found in Path"
Is Wchar_T Needed for Unicode Support
Why and How to Use Namespaces in C++
How to Determine the Amount of Linux System Ram in C++
Creating Array of Objects on the Stack and Heap
Difference Between A* Pa = New A; and A* Pa = New A();
How to Simulate a Mouse Movement
Weird Msc 8.0 Error: "The Value of Esp Was Not Properly Saved Across a Function Call..."
Why Can't Templates Be Declared in a Function
Problems Using Member Function as Custom Deleter with Std::Shared_Ptr
Float Bits and Strict Aliasing