CXXIter 0.2
Loading...
Searching...
No Matches
Intersperser.h
1#pragma once
2
3#include <utility>
4#include <cstdlib>
5#include <algorithm>
6
7#include "../Common.h"
8#include "../util/SaturatingArithmetic.h"
9#include "../util/TraitImpl.h"
10
11namespace CXXIter {
12
13 // ################################################################################################
14 // INTERSPERSER
15 // ################################################################################################
16 namespace op {
18 template<typename TChainInput, typename TSeparatorInput>
19 class [[nodiscard(CXXITER_CHAINER_NODISCARD_WARNING)]] Intersperser : public IterApi<Intersperser<TChainInput, TSeparatorInput>> {
20 friend struct trait::Iterator<Intersperser<TChainInput, TSeparatorInput>>;
21 friend struct trait::ExactSizeIterator<Intersperser<TChainInput, TSeparatorInput>>;
22 enum class IntersperserState { Uninitialized, Item, Separator };
23 private:
24 TChainInput input;
25 TSeparatorInput separatorInput;
26 IterValue<typename TChainInput::Item> nextItem;
27 IntersperserState intersperserState = IntersperserState::Uninitialized;
28 public:
29 constexpr Intersperser(TChainInput&& input, TSeparatorInput&& separatorInput) : input(std::move(input)), separatorInput(std::move(separatorInput)) {}
30 };
31 }
32 // ------------------------------------------------------------------------------------------------
34 template<typename TChainInput, typename TSeparatorInput>
35 struct trait::Iterator<op::Intersperser<TChainInput, TSeparatorInput>> {
36 using ChainInputIterator = trait::Iterator<TChainInput>;
37 using SeparatorInputIterator = trait::Iterator<TSeparatorInput>;
38 // CXXIter Interface
39 using Self = op::Intersperser<TChainInput, TSeparatorInput>;
40 using Item = typename ChainInputIterator::Item;
41
42 static constexpr inline IterValue<Item> next(Self& self) {
43 if(self.intersperserState == Self::IntersperserState::Uninitialized) [[unlikely]] {
44 self.nextItem = ChainInputIterator::next(self.input);
45 self.intersperserState = Self::IntersperserState::Item;
46 }
47 if(!self.nextItem.has_value()) [[unlikely]] { return {}; }
48
49 if(self.intersperserState == Self::IntersperserState::Item) {
50 self.intersperserState = Self::IntersperserState::Separator;
51 IterValue<Item> item;
52 item.swap(self.nextItem);
53 self.nextItem = ChainInputIterator::next(self.input);
54 return item;
55 } else {
56 self.intersperserState = Self::IntersperserState::Item;
57 return SeparatorInputIterator::next(self.separatorInput);
58 }
59 }
60 static constexpr inline SizeHint sizeHint(const Self& self) {
61 SizeHint input = ChainInputIterator::sizeHint(self.input);
62 SizeHint separator = SeparatorInputIterator::sizeHint(self.separatorInput);
63
64 SizeHint result = input;
65 if(result.lowerBound > 0) {
66 size_t sepCnt = std::min((result.lowerBound - 1), separator.lowerBound);
67 result.lowerBound = (util::SaturatingArithmetic<size_t>(sepCnt) + sepCnt + 1).get();
68 }
69 if(result.upperBound.value_or(0) > 0) {
70 size_t sepCnt = std::min((result.upperBound.value() - 1), separator.upperBound.value_or(SizeHint::INFINITE));
71 result.upperBound = (util::SaturatingArithmetic<size_t>(sepCnt) + sepCnt + 1).get();
72 }
73 return result;
74 }
75 static constexpr inline size_t advanceBy(Self& self, size_t n) { return util::advanceByPull(self, n); }
76 };
78 template<CXXIterExactSizeIterator TChainInput, CXXIterExactSizeIterator TSeparatorInput>
79 struct trait::ExactSizeIterator<op::Intersperser<TChainInput, TSeparatorInput>> {
80 static constexpr inline size_t size(const op::Intersperser<TChainInput, TSeparatorInput>& self) {
81 return trait::Iterator<op::Intersperser<TChainInput, TSeparatorInput>>::sizeHint(self).lowerBound;
82 }
83 };
84
85}
CXXIter.
Definition: CXXIter.h:48