9#include "../util/TraitImpl.h"
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...>>;
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;
28 constexpr Alternater(TChainInput1&& input1, TChainInputs&&... inputs) : inputs( std::forward_as_tuple(std::move(input1), std::move(inputs)...) ) {}
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);
38 using Self = op::Alternater<TChainInput1, TChainInputs...>;
39 using Item =
typename TChainInput1::Item;
41 static constexpr inline IterValue<Item> next(Self& self) {
42 if(self.batchElementIdx == Self::BATCH_SIZE) [[unlikely]] {
43 constexpr_for<0, INPUT_CNT>([&](
auto idx) {
44 self.currentBatch[idx] = std::tuple_element_t<idx, ChainInputIterators>::next( std::get<idx>(self.inputs) );
47 self.batchElementIdx = 0;
49 return std::move(self.currentBatch[self.batchElementIdx++]);
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 = {};
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) {
59 lowerBoundMin = tmp.lowerBound;
61 upperBoundMin = SizeHint::upperBoundMin(upperBoundMin, tmp.upperBound);
66 if(upperBoundMin.has_value()) { upperBoundMin.value() = upperBoundMin.value() * Self::BATCH_SIZE + minIdx; }
67 SizeHint result = SizeHint(
68 lowerBoundMin * Self::BATCH_SIZE + minIdx,
73 static constexpr inline size_t advanceBy(Self& self,
size_t n) {
return util::advanceByPull(self, n); }
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;