CXXIter 0.2
Loading...
Searching...
No Matches
Reverse.h
1#pragma once
2
3#include <cstdlib>
4#include <optional>
5
6#include "../Common.h"
7#include "../sources/ContainerSources.h"
8#include "../util/TraitImpl.h"
9
10namespace CXXIter {
11
12 // ################################################################################################
13 // SORTER
14 // ################################################################################################
15 namespace op {
17 template<typename TChainInput>
18 class [[nodiscard(CXXITER_CHAINER_NODISCARD_WARNING)]] Reverse : public IterApi<Reverse<TChainInput>> {
19 friend struct trait::Iterator<Reverse<TChainInput>>;
20 friend struct trait::DoubleEndedIterator<Reverse<TChainInput>>;
21 friend struct trait::ExactSizeIterator<Reverse<TChainInput>>;
22
23 using InputItem = typename TChainInput::Item;
24
25 struct NoReverseCache {};
26 using ReverseCacheContainer = std::conditional_t<
27 std::is_reference_v<InputItem>,
28 std::vector<std::reference_wrapper<InputItem>>,
29 std::vector<InputItem>>;
30 using ReverseCache = SrcMov<ReverseCacheContainer>;
31
32 private:
33 // If the underlying iterator pipeline is double-ended, we don't need to use the reverseCache
34 static constexpr bool USE_CACHE = !CXXIterDoubleEndedIterator<TChainInput>;
35 TChainInput input;
36 std::conditional_t<USE_CACHE, std::optional<ReverseCache>, NoReverseCache> reverseCache;
37
38 public:
39 constexpr Reverse(TChainInput&& input) : input(std::move(input)) {}
40 };
41 }
42 // ------------------------------------------------------------------------------------------------
44 template<typename TChainInput>
45 struct trait::Iterator<op::Reverse<TChainInput>> {
46 using ChainInputIterator = trait::Iterator<TChainInput>;
47 using InputItem = typename TChainInput::Item;
48 // CXXIter Interface
49 using Self = op::Reverse<TChainInput>;
50 using Item = InputItem;
51
52 static void initReverseCache(Self& self) {
53 // drain input iterator into reverse cache
54 typename Self::ReverseCacheContainer reverseCache;
55 reverseCache.reserve(self.input.sizeHint().expectedResultSize());
56 while(true) {
57 auto item = ChainInputIterator::next(self.input);
58 if(!item.has_value()) { break; }
59 reverseCache.push_back(std::move(item.value()));
60 }
61 self.reverseCache = typename Self::ReverseCache(std::move(reverseCache));
62 }
63
64 static constexpr inline IterValue<Item> next(Self& self) {
65 if constexpr(Self::USE_CACHE) {
66 if(!self.reverseCache.has_value()) [[unlikely]] { initReverseCache(self); }
67 return trait::DoubleEndedIterator<typename Self::ReverseCache>::nextBack(self.reverseCache.value());
68 } else {
69 return trait::DoubleEndedIterator<TChainInput>::nextBack(self.input);
70 }
71 }
72 static constexpr inline SizeHint sizeHint(const Self& self) { return ChainInputIterator::sizeHint(self.input); }
73 static constexpr inline size_t advanceBy(Self& self, size_t n) { return util::advanceByPullBack(self, n); }
74 };
76 template<CXXIterDoubleEndedIterator TChainInput>
77 struct trait::DoubleEndedIterator<op::Reverse<TChainInput>> {
78 using ChainInputIterator = trait::Iterator<TChainInput>;
79 using InputItem = typename TChainInput::Item;
80 // CXXIter Interface
81 using Self = op::Reverse<TChainInput>;
82 using Item = InputItem;
83
84 static constexpr inline IterValue<Item> nextBack(Self& self) {
85 if constexpr(Self::USE_CACHE) {
86 if(!self.reverseCache.has_value()) [[unlikely]] { initReverseCache(self); }
87 return trait::Iterator<typename Self::ReverseCache>::next(self.reverseCache.value());
88 } else {
89 return ChainInputIterator::next(self.input);
90 }
91 }
92 };
94 template<CXXIterExactSizeIterator TChainInput>
95 struct trait::ExactSizeIterator<op::Reverse<TChainInput>> {
96 static constexpr inline size_t size(const op::Reverse<TChainInput>& self) {
97 return trait::ExactSizeIterator<TChainInput>::size(self.input);
98 }
99 };
100
101}
CXXIter.
Definition: CXXIter.h:48