CXXIter 0.2
Loading...
Searching...
No Matches
Alternater.h
1#pragma once
2
3#include <tuple>
4#include <cstdlib>
5#include <optional>
6#include <limits>
7
8#include "../Common.h"
9#include "../util/TraitImpl.h"
10
11namespace CXXIter {
12
13 // ################################################################################################
14 // ALTERNATER
15 // ################################################################################################
16 namespace op {
18 template<typename TChainInput1, typename... TChainInputs>
19 class [[nodiscard(CXXITER_CHAINER_NODISCARD_WARNING)]] Alternater : public IterApi<Alternater<TChainInput1, TChainInputs...>> {
20 friend struct trait::Iterator<Alternater<TChainInput1, TChainInputs...>>;
21 friend struct trait::ExactSizeIterator<Alternater<TChainInput1, TChainInputs...>>;
22 private:
23 static constexpr size_t BATCH_SIZE = 1 + sizeof...(TChainInputs);
24 std::tuple<TChainInput1, TChainInputs...> inputs;
25 std::array<IterValue<typename TChainInput1::Item>, BATCH_SIZE> currentBatch;
26 size_t batchElementIdx = BATCH_SIZE;
27 public:
28 constexpr Alternater(TChainInput1&& input1, TChainInputs&&... inputs) : inputs( std::forward_as_tuple(std::move(input1), std::move(inputs)...) ) {}
29 };
30 }
31 // ------------------------------------------------------------------------------------------------
33 template<typename TChainInput1, typename... TChainInputs>
34 struct trait::Iterator<op::Alternater<TChainInput1, TChainInputs...>> {
35 using ChainInputIterators = std::tuple<Iterator<TChainInput1>, trait::Iterator<TChainInputs>...>;
36 static constexpr size_t INPUT_CNT = 1 + sizeof...(TChainInputs);
37 // CXXIter Interface
38 using Self = op::Alternater<TChainInput1, TChainInputs...>;
39 using Item = typename TChainInput1::Item;
40
41 static constexpr inline IterValue<Item> next(Self& self) {
42 if(self.batchElementIdx == Self::BATCH_SIZE) [[unlikely]] { // returned all elements from the batch -> retrieve new batch
43 constexpr_for<0, INPUT_CNT>([&](auto idx) {
44 self.currentBatch[idx] = std::tuple_element_t<idx, ChainInputIterators>::next( std::get<idx>(self.inputs) );
45 return true;
46 });
47 self.batchElementIdx = 0;
48 }
49 return std::move(self.currentBatch[self.batchElementIdx++]);
50 }
51 static constexpr inline SizeHint sizeHint(const Self& self) {
52 size_t lowerBoundMin = std::numeric_limits<size_t>::max();
53 std::optional<size_t> upperBoundMin = {};
54 size_t minIdx = 0;
55 constexpr_for<0, INPUT_CNT>([&](auto idx) {
56 SizeHint tmp = std::tuple_element_t<idx, ChainInputIterators>::sizeHint( std::get<idx>(self.inputs) );
57 if(lowerBoundMin > tmp.lowerBound) {
58 minIdx = idx;
59 lowerBoundMin = tmp.lowerBound;
60 }
61 upperBoundMin = SizeHint::upperBoundMin(upperBoundMin, tmp.upperBound);
62 return true;
63 });
64 // smallest input iterator defines base length. The amount of elements then is that
65 // length, multiplied by the amount of input iterators + the index of the shortest
66 if(upperBoundMin.has_value()) { upperBoundMin.value() = upperBoundMin.value() * Self::BATCH_SIZE + minIdx; }
67 SizeHint result = SizeHint(
68 lowerBoundMin * Self::BATCH_SIZE + minIdx,
69 upperBoundMin
70 );
71 return result;
72 }
73 static constexpr inline size_t advanceBy(Self& self, size_t n) { return util::advanceByPull(self, n); }
74 };
76 template<CXXIterExactSizeIterator TChainInput1, CXXIterExactSizeIterator... TChainInputs>
77 struct trait::ExactSizeIterator<op::Alternater<TChainInput1, TChainInputs...>> {
78 static constexpr inline size_t size(const op::Alternater<TChainInput1, TChainInputs...>& self) {
79 return trait::Iterator<op::Alternater<TChainInput1, TChainInputs...>>::sizeHint(self).lowerBound;
80 }
81 };
82
83}
CXXIter.
Definition: CXXIter.h:48