Everett
Loading...
Searching...
No Matches
typed_scan.h
Go to the documentation of this file.
1
12#pragma once
13
14#include <everett/typed_world.h>
15#include <iterator>
16#include <ranges>
17
18namespace everett {
23
24 // Native runs are oldest first. The heap orders equal keys by that age,
25 // so noncommutative arrows are applied in exactly their original order.
26 // The fractional cascade positions each native run at the lower bound.
27 // It retains one reconstructed key per native run and at most one resolved
28 // output row. Values continue borrowing native bytes.
29 // Each step unit consumes one physical record; key bytes, callbacks and
30 // heap comparisons are additional costs. Construction searches bounded
31 // catalog windows and seeds each run from the lower-bound query. The captured
32 // world keeps all mappings and cursors alive.
33 template <class S, class World> struct typed_scan {
34 using policy_type = typename World::policy_type;
37 using native_type = typename World::runtime_family::native_type;
38 using key_transport = typename World::key_transport;
39
41 explicit typed_scan(World snapshot, std::optional<key_type> lo = {}, std::optional<key_type> hi = {},
42 range_positioning_work * work = nullptr)
43 : snapshot_(std::move(snapshot)), prefix_(key_transport::template prefix<S>()),
44 lower_(lo ? std::optional{key_transport::template encode<S>(*lo)} : std::nullopt),
45 upper_(hi ? std::optional{key_transport::template encode<S>(*hi)} : std::nullopt) {
46 if (work) *work = {};
47 if (lower_ && upper_ && compare_bits<typename policy_type::architecture>(lower_->view(), upper_->view()) > 0)
48 throw std::invalid_argument("reversed typed range");
49 if (lower_ && upper_ && compare_bits<typename policy_type::architecture>(lower_->view(), upper_->view()) == 0) { finished_ = true; return; }
50 sweep_ = typed_detail::native_sweep<World>(snapshot_, lower_ ? lower_->view() : prefix_.view(), work);
51 finished_ = sweep_.done();
52 }
53 typed_scan(typed_scan const &) = default;
54 typed_scan & operator=(typed_scan const &) = default;
55 typed_scan(typed_scan &&) = default;
57
58 // Dereferencing returns an owning row. Iterator copies share their walk
59 // until one advances, then copy the per-run keys and cursor positions.
60 // No reference escapes into an iterator's mutable FC reconstruction.
61 struct iterator {
63 using difference_type = std::ptrdiff_t;
64 using iterator_concept = std::forward_iterator_tag;
65 using iterator_category = std::input_iterator_tag;
66 iterator() = default;
68 if (!state_ || !state_->has_row()) throw std::out_of_range("typed range iterator end");
69 return *state_->row_;
70 }
72 if (!state_ || !state_->has_row()) throw std::out_of_range("typed range iterator end");
73 if (state_.use_count() != 1) state_ = std::make_shared<typed_scan>(*state_);
74 state_->row_.reset(); settle(); return *this;
75 }
76 iterator operator++(int) { auto previous = *this; ++*this; return previous; }
77 friend bool operator==(iterator const & a, iterator const & b) {
78 if (a.at_end() || b.at_end()) return a.at_end() && b.at_end();
79 return a.same_position(b);
80 }
81 friend bool operator==(iterator const & value, std::default_sentinel_t) { return value.at_end(); }
82 private:
83 friend typed_scan;
84 std::shared_ptr<typed_scan> state_;
85 explicit iterator(typed_scan const & value) : state_(std::make_shared<typed_scan>(value)) { settle(); }
86 bool at_end() const { return !state_ || state_->done(); }
87 bool same_position(iterator const & other) const {
88 return state_->identity_ == other.state_->identity_ && state_->consumed() == other.state_->consumed();
89 }
90 void settle() { while (!state_->has_row() && !state_->done()) state_->step(256); }
91 };
92 iterator begin() const {
93 if (failed_) throw std::logic_error("failed typed scan");
94 return iterator(*this);
95 }
96 std::default_sentinel_t end() const noexcept { return {}; }
97
98 bool done() const noexcept { return finished_ && !row_; }
99 bool has_row() const noexcept { return row_.has_value(); }
100 bool failed() const noexcept { return failed_; }
101 std::uint64_t consumed() const noexcept { return sweep_.consumed(); }
103 if (failed_) throw std::logic_error("failed typed scan");
104 if (!row_) throw std::logic_error("typed scan has no row");
105 auto result = std::move(*row_); row_.reset(); return result;
106 }
107 std::optional<row_type> next() {
108 if (failed_) throw std::logic_error("failed typed scan");
109 while (!has_row() && !done()) step(256);
110 return has_row() ? std::optional<row_type>{take_row()} : std::nullopt;
111 }
112 std::uint64_t step(std::uint64_t budget) {
113 if (failed_) throw std::logic_error("failed typed scan");
114 if (!budget || done() || has_row()) return 0;
115 std::uint64_t used = 0;
116 try {
117 while (used != budget && !finished_ && !row_) {
118 if (sweep_.done()) { finish_group(); finished_ = true; break; }
119 auto current = sweep_.peek();
120 if (group_ && compare_bits<typename policy_type::architecture>(group_key_.view(), current.key.prefix) != 0) {
121 finish_group();
122 if (row_) break;
123 }
124 if (!group_) {
125 if (upper_ && compare_bits<typename policy_type::architecture>(current.key.prefix, upper_->view()) >= 0) { finished_ = true; break; }
126 if (lower_ && compare_bits<typename policy_type::architecture>(current.key.prefix, lower_->view()) < 0) { sweep_.consume(); ++used; continue; }
127 auto order = compare_prefix(current.key.prefix);
128 if (order > 0) { finished_ = true; break; }
129 if (order < 0) { sweep_.consume(); ++used; continue; }
130 group_key_ = bit_string::copy(current.key.prefix);
131 auto key = key_transport::template decode<S>(group_key_.view().subview(prefix_.bit_size,
133 auto value = semantics::initial(key);
134 group_.emplace(row_type{std::move(key), std::move(value)});
135 }
136 if constexpr (typed_detail::replacement<S>) {
137 last_value_ = current.value;
138 last_retained_ = sweep_.retained_bits();
139 }
140 else group_->value = semantics::apply(group_->key, std::move(group_->value),
141 typed_detail::value<policy_type, S>(current.value));
142 sweep_.consume(); ++used;
143 if (sweep_.done() || compare_bits<typename policy_type::architecture>(group_key_.view(), sweep_.peek().key.prefix) != 0)
144 finish_group();
145 if (sweep_.done()) finished_ = true;
146 }
147 } catch (...) { failed_ = true; throw; }
148 return used;
149 }
150
151 // Delete exactly the rows this cursor has not yet returned. The private
152 // observations carry old arrows, not hash-only evidence of old values.
153 auto erase_remaining() requires typed_detail::replacement<S> {
154 if (failed_) throw std::logic_error("failed typed scan");
155 try {
156 typename World::contribution_type result{snapshot_, {}};
157 result.observed_.emplace();
158 while (!done()) {
159 while (!has_row() && !done()) step(256);
160 if (!has_row()) break;
161 result.records_.push_back({bit_string::copy(group_key_.view()),
162 typed_detail::value<policy_type, S>(semantics::erase(row_->key)), last_retained_});
163 result.observed_->push_back(last_value_);
164 row_.reset();
165 }
166 return result;
167 } catch (...) { failed_ = true; throw; }
168 }
169
170 private:
171 std::shared_ptr<void const> identity_ = std::make_shared<int const>(0);
174 std::optional<bit_string> lower_, upper_;
176 std::optional<row_type> group_, row_;
178 std::uint64_t last_retained_ = 0;
179 bool finished_ = false, failed_ = false;
180
181 int compare_prefix(bit_view key) const {
182 auto count = std::min(key.size(), prefix_.bit_size);
183 auto order = compare_bits<typename policy_type::architecture>(key.subview(0, count), prefix_.view().subview(0, count));
184 return order ? order : key.size() < prefix_.bit_size ? -1 : 0;
185 }
187 if (!group_) return;
188 if constexpr (typed_detail::replacement<S>)
189 group_->value = semantics::apply(group_->key, std::move(group_->value),
190 typed_detail::value<policy_type, S>(last_value_));
191 if (semantics::present(group_->key, group_->value)) row_.emplace(std::move(*group_));
192 group_.reset();
193 }
194 };
195
196 // Bounds follow the sort's encoded ordering. Omitted endpoints are open.
197 // The fractional cascade finds the native starts; cursors remain open thereafter.
198 template <class S = void, class World> auto range(World snapshot,
199 std::optional<typed_detail::key_t<std::conditional_t<std::is_void_v<S>,
201 std::optional<typed_detail::key_t<std::conditional_t<std::is_void_v<S>,
202 typed_detail::default_sort_t<typename World::policy_type>, S>>> hi = {},
203 range_positioning_work * work = nullptr) {
204 using selected = std::conditional_t<std::is_void_v<S>, typed_detail::default_sort_t<typename World::policy_type>, S>;
205 return typed_scan<selected, World>(std::move(snapshot), std::move(lo), std::move(hi), work);
206 }
207 template <class S = void, class World> auto erase_range(World snapshot,
208 std::optional<typed_detail::key_t<std::conditional_t<std::is_void_v<S>,
210 std::optional<typed_detail::key_t<std::conditional_t<std::is_void_v<S>,
211 typed_detail::default_sort_t<typename World::policy_type>, S>>> hi = {})
212 requires typed_detail::replacement<std::conditional_t<std::is_void_v<S>,
213 typed_detail::default_sort_t<typename World::policy_type>, S>> {
214 return range<S>(std::move(snapshot), std::move(lo), std::move(hi)).erase_remaining();
215 }
216 template <class S = void, class World> auto scan(World snapshot) {
217 using selected = std::conditional_t<std::is_void_v<S>, typed_detail::default_sort_t<typename World::policy_type>, S>;
218 return typed_scan<selected, World>(std::move(snapshot));
219 }
220}
221
222// Standard customization: iterators retain their own snapshot and walk state.
224namespace std::ranges {
225 template <class S, class World>
226 inline constexpr bool enable_borrowed_range<everett::typed_scan<S, World>> = true;
227}
constexpr bool replacement
Definition typed_world.h:55
typename sort_codec< S >::key_codec::value_type key_t
Definition typed_world.h:52
typename default_sort< typename registry_detail::info< typename P::registry_type >::leaves >::type default_sort_t
Definition typed_world.h:51
typename sort_semantics< S >::state_type state_t
Definition typed_world.h:54
Definition active_engine.h:18
auto range(World snapshot, std::optional< typed_detail::key_t< std::conditional_t< std::is_void_v< S >, typed_detail::default_sort_t< typename World::policy_type >, S > > > lo={}, std::optional< typed_detail::key_t< std::conditional_t< std::is_void_v< S >, typed_detail::default_sort_t< typename World::policy_type >, S > > > hi={}, range_positioning_work *work=nullptr)
Definition typed_scan.h:198
auto erase_range(World snapshot, std::optional< typed_detail::key_t< std::conditional_t< std::is_void_v< S >, typed_detail::default_sort_t< typename World::policy_type >, S > > > lo={}, std::optional< typed_detail::key_t< std::conditional_t< std::is_void_v< S >, typed_detail::default_sort_t< typename World::policy_type >, S > > > hi={})
Definition typed_scan.h:207
Definition profile.h:166
bit_view view() const &
Definition profile.h:178
static bit_string copy(bit_view source)
Definition profile.h:181
std::uint64_t bit_size
Definition profile.h:168
Definition profile.h:56
bit_view subview(std::uint64_t first, std::uint64_t count) const
Definition profile.h:73
bit_view prefix(std::uint64_t count) const
Definition profile.h:80
Definition typed_world.h:31
Definition native_sweep.h:32
Definition typed_scan.h:19
typed_detail::key_t< S > key
Definition typed_scan.h:20
typed_detail::state_t< S > value
Definition typed_scan.h:21
Definition typed_scan.h:61
iterator & operator++()
Definition typed_scan.h:71
friend bool operator==(iterator const &a, iterator const &b)
Definition typed_scan.h:77
friend typed_scan
Definition typed_scan.h:83
std::forward_iterator_tag iterator_concept
Definition typed_scan.h:64
std::input_iterator_tag iterator_category
Definition typed_scan.h:65
value_type operator*() const
Definition typed_scan.h:67
iterator operator++(int)
Definition typed_scan.h:76
void settle()
Definition typed_scan.h:90
std::shared_ptr< typed_scan > state_
Definition typed_scan.h:84
bool at_end() const
Definition typed_scan.h:86
friend bool operator==(iterator const &value, std::default_sentinel_t)
Definition typed_scan.h:81
std::ptrdiff_t difference_type
Definition typed_scan.h:63
iterator(typed_scan const &value)
Definition typed_scan.h:85
bool same_position(iterator const &other) const
Definition typed_scan.h:87
Definition typed_scan.h:33
std::uint64_t last_retained_
Definition typed_scan.h:178
bool has_row() const noexcept
Definition typed_scan.h:99
typename World::runtime_family::native_type native_type
Definition typed_scan.h:37
bit_string group_key_
Definition typed_scan.h:173
bool done() const noexcept
Definition typed_scan.h:98
typed_scan(typed_scan const &)=default
iterator begin() const
Definition typed_scan.h:92
bit_string prefix_
Definition typed_scan.h:173
std::uint64_t step(std::uint64_t budget)
Definition typed_scan.h:112
row_type take_row()
Definition typed_scan.h:102
bool failed_
Definition typed_scan.h:179
bit_view last_value_
Definition typed_scan.h:177
std::optional< bit_string > upper_
Definition typed_scan.h:174
void finish_group()
Definition typed_scan.h:186
bool finished_
Definition typed_scan.h:179
std::optional< row_type > next()
Definition typed_scan.h:107
typed_scan(World snapshot, std::optional< key_type > lo={}, std::optional< key_type > hi={}, range_positioning_work *work=nullptr)
Definition typed_scan.h:41
typed_row< S > row_type
Definition typed_scan.h:35
std::default_sentinel_t end() const noexcept
Definition typed_scan.h:96
World snapshot_
Definition typed_scan.h:172
typed_scan & operator=(typed_scan const &)=default
typename World::key_transport key_transport
Definition typed_scan.h:38
std::uint64_t consumed() const noexcept
Definition typed_scan.h:101
typed_scan & operator=(typed_scan &&)=default
typed_scan(typed_scan &&)=default
std::optional< bit_string > lower_
Definition typed_scan.h:174
std::shared_ptr< void const > identity_
Definition typed_scan.h:171
typed_detail::key_t< S > key_type
Definition typed_scan.h:40
int compare_prefix(bit_view key) const
Definition typed_scan.h:181
std::optional< row_type > group_
Definition typed_scan.h:176
typed_detail::native_sweep< World > sweep_
Definition typed_scan.h:175
std::optional< row_type > row_
Definition typed_scan.h:176
typename World::policy_type policy_type
Definition typed_scan.h:34
auto erase_remaining()
Definition typed_scan.h:153
bool failed() const noexcept
Definition typed_scan.h:100
Connects sort-owned semantics to encoded COLA updates and immutable typed snapshots.