Everett
Loading...
Searching...
No Matches
sort_profile_merge.h
Go to the documentation of this file.
1
12#pragma once
13
16
17namespace everett {
18 namespace sort_profile_detail {
19 template <class View> struct merge_source {
20 explicit merge_source(View view) : view_(view) {
21 if (view_.size()) { frame_ = view_.encoded_at(0); retain(); }
22 }
23 bool done() const noexcept { return ordinal_ == view_.size(); }
24 auto const & frame() const noexcept { return frame_; }
25 std::span<bit_view const> spans() const noexcept { return spans_; }
26 std::optional<bit_comparison> advance() {
27 if (done()) throw std::out_of_range("sort merge source end");
28 if (++ordinal_ == view_.size()) {
29 if (frame_.next_offset != view_.data().size() || frame_.key_units != view_.metadata().terminal_key_units)
30 throw std::invalid_argument("sort merge source terminal mismatch");
31 return std::nullopt;
32 }
33 frame_ = view_.next(frame_);
34 if (frame_.retained > length_) throw std::invalid_argument("sort merge missing inherited prefix");
35 auto comparison = compare_spans(spans_, frame_.literal, frame_.retained);
36 comparison.common_bits += frame_.retained;
37 if (comparison.order >= 0) throw std::invalid_argument("sort merge input is not strictly ordered");
38 retain(); return comparison;
39 }
41 bit_string result;
42 for (auto span : spans_) profile_detail::append(result, span);
43 return result;
44 }
45 private:
46 View view_;
48 std::vector<bit_view> spans_;
49 std::uint64_t ordinal_ = 0, length_ = 0;
50 void retain() {
51 if (frame_.retained > length_) throw std::invalid_argument("sort merge requires an initial prefix");
52 while (length_ > frame_.retained) {
53 auto amount = std::min(spans_.back().size(), length_ - frame_.retained);
54 auto keep = spans_.back().size() - amount; length_ -= amount;
55 if (!keep) spans_.pop_back(); else spans_.back() = spans_.back().prefix(keep);
56 }
57 for (auto part : frame_.literal) if (part.size()) { spans_.push_back(part); length_ += part.size(); }
58 if (length_ != frame_.key_units) throw std::invalid_argument("sort merge logical frame length");
59 }
60 };
61 }
62
63 template <class P, class Native = sort_profile_array<P>, class Compose = replace_native_value,
64 class Selector = typename Native::stream_family::selector_type,
65 class Output = sort_profile_writer<P, Selector>>
67 using source_pointer = std::shared_ptr<Native const>;
68 using view_type = decltype(std::declval<Native const &>().view());
69 sort_profile_merge_builder(source_pointer older, source_pointer newer, Compose compose = {})
70 : sort_profile_merge_builder(Output{}, std::move(older), std::move(newer), std::move(compose)) {}
71 sort_profile_merge_builder(Output output, source_pointer older, source_pointer newer, Compose compose = {})
72 : older_(checked(std::move(older))), newer_(checked(std::move(newer))),
73 left_(older_->view()), right_(newer_->view()), output_(std::move(output)), compose_(std::move(compose)) {}
74 bool done() const noexcept { return older_ && newer_ && !failed_ && left_.done() && right_.done(); }
75 bool failed() const noexcept { return failed_ || output_.failed(); }
76 bool finished() const noexcept { return finished_; }
77 native_merge_progress progress() const noexcept { return progress_; }
78 std::uint64_t materialized_keys() const noexcept { return materialized_keys_; }
79 native_merge_progress step(std::uint64_t budget = 1) {
80 if (!older_ || !newer_ || failed_ || finished_) throw std::logic_error("inactive sort merge");
82 try {
83 while (work.keys < budget && !done()) {
84 auto comparison = compare();
85 if (comparison.order < 0) {
86 append(left_, left_common_, left_.frame().value, left_.frame().retained);
87 right_common_ = comparison.common_bits; left_common_ = advance(left_);
88 } else if (comparison.order > 0) {
89 append(right_, right_common_, right_.frame().value, right_.frame().retained);
90 left_common_ = comparison.common_bits; right_common_ = advance(right_);
91 } else {
92 bit_string key;
93 auto value = [&] {
94 if constexpr (!std::is_same_v<Compose, replace_native_value> && std::is_invocable_v<Compose &, bit_view, bit_view, bit_view>) {
96 return std::invoke(compose_, key.view(), left_.frame().value, right_.frame().value);
97 } else return std::invoke(compose_, left_.frame().value, right_.frame().value);
98 }();
99 auto limit = std::min(left_.frame().retained, right_.frame().retained);
100 if constexpr (std::is_same_v<decltype(value), bit_view>)
101 append(left_, left_common_, value, limit);
102 else append(left_, left_common_, value.view(), limit);
104 }
105 ++work.keys; work.input_records += comparison.order ? 1 : 2;
106 }
108 return work;
109 } catch (...) { failed_ = true; throw; }
110 }
111 auto finish() {
112 if (!done() || finished_) throw std::logic_error("unfinished sort merge");
113 try { auto result = output_.finish(); finished_ = true; return result; }
114 catch (...) { failed_ = true; throw; }
115 }
116 private:
119 Output output_;
120 Compose compose_;
122 std::uint64_t left_common_ = 0, right_common_ = 0, materialized_keys_ = 0;
123 bool failed_ = false, finished_ = false;
125 std::uint64_t common, bit_view value, std::uint64_t limit) {
126 auto frame = source.frame();
128 ++materialized_keys_; return source.materialize();
129 })) frame.retained_limit_bits = limit;
130 output_.append_frame(frame, source.spans(), common, value);
131 }
133 if (!value) throw std::invalid_argument("null sort merge input");
134 return value;
135 }
136 static std::uint64_t advance(auto & source) { auto cmp = source.advance(); return cmp ? cmp->common_bits : 0; }
138 if (left_.done()) return {0, 1};
139 if (right_.done()) return {0, -1};
141 return {std::min(left_common_, right_common_), left_common_ > right_common_ ? -1 : 1};
142 auto cmp = sort_profile_detail::compare_spans<typename P::architecture>(left_.spans(), right_.spans(), left_common_, right_common_);
143 cmp.common_bits += left_common_; return cmp;
144 }
145 };
146}
bool is_tombstone(Compose &compose, bit_view value, Key &&key)
Definition native_merge.h:37
void append(bit_string &target, bit_view source)
Definition profile.h:480
bit_comparison compare_spans(std::span< bit_view const > a, std::span< bit_view const > b, std::uint64_t first_a=0, std::uint64_t first_b=0)
Definition sort_profile.h:116
Definition active_engine.h:18
Merges ordered native streams incrementally with policy-specific value composition.
Navigates sort-owned bit records using shared sort seeds and sparse offsets.
Definition profile.h:209
Definition profile.h:166
bit_view view() const &
Definition profile.h:178
Definition profile.h:56
Definition native_merge.h:148
std::uint64_t input_records
Definition native_merge.h:150
std::uint64_t keys
Definition native_merge.h:149
Definition sort_profile_merge.h:19
std::vector< bit_view > spans_
Definition sort_profile_merge.h:48
bit_string materialize() const
Definition sort_profile_merge.h:40
std::uint64_t ordinal_
Definition sort_profile_merge.h:49
bool done() const noexcept
Definition sort_profile_merge.h:23
View view_
Definition sort_profile_merge.h:46
std::uint64_t length_
Definition sort_profile_merge.h:49
std::optional< bit_comparison > advance()
Definition sort_profile_merge.h:26
merge_source(View view)
Definition sort_profile_merge.h:20
auto const & frame() const noexcept
Definition sort_profile_merge.h:24
void retain()
Definition sort_profile_merge.h:50
std::span< bit_view const > spans() const noexcept
Definition sort_profile_merge.h:25
sort_profile_frame frame_
Definition sort_profile_merge.h:47
Definition sort_profile.h:163
std::array< bit_view, 2 > literal
Definition sort_profile.h:165
std::uint64_t next_offset
Definition sort_profile.h:164
std::uint64_t key_units
Definition sort_profile.h:164
std::uint64_t retained
Definition sort_profile.h:164
Definition sort_profile_merge.h:66
sort_profile_merge_builder(Output output, source_pointer older, source_pointer newer, Compose compose={})
Definition sort_profile_merge.h:71
Output output_
Definition sort_profile_merge.h:119
std::uint64_t materialized_keys() const noexcept
Definition sort_profile_merge.h:78
sort_profile_detail::merge_source< view_type > left_
Definition sort_profile_merge.h:118
std::uint64_t materialized_keys_
Definition sort_profile_merge.h:122
Compose compose_
Definition sort_profile_merge.h:120
auto finish()
Definition sort_profile_merge.h:111
bool failed_
Definition sort_profile_merge.h:123
sort_profile_detail::merge_source< view_type > right_
Definition sort_profile_merge.h:118
bool failed() const noexcept
Definition sort_profile_merge.h:75
std::uint64_t left_common_
Definition sort_profile_merge.h:122
bool done() const noexcept
Definition sort_profile_merge.h:74
native_merge_progress step(std::uint64_t budget=1)
Definition sort_profile_merge.h:79
bool finished_
Definition sort_profile_merge.h:123
bool finished() const noexcept
Definition sort_profile_merge.h:76
source_pointer older_
Definition sort_profile_merge.h:117
source_pointer newer_
Definition sort_profile_merge.h:117
static std::uint64_t advance(auto &source)
Definition sort_profile_merge.h:136
native_merge_progress progress() const noexcept
Definition sort_profile_merge.h:77
std::shared_ptr< Native const > source_pointer
Definition sort_profile_merge.h:67
native_merge_progress progress_
Definition sort_profile_merge.h:121
decltype(std::declval< Native const & >().view()) view_type
Definition sort_profile_merge.h:68
bit_comparison compare() const
Definition sort_profile_merge.h:137
void append(sort_profile_detail::merge_source< view_type > const &source, std::uint64_t common, bit_view value, std::uint64_t limit)
Definition sort_profile_merge.h:124
std::uint64_t right_common_
Definition sort_profile_merge.h:122
static source_pointer checked(source_pointer value)
Definition sort_profile_merge.h:132
sort_profile_merge_builder(source_pointer older, source_pointer newer, Compose compose={})
Definition sort_profile_merge.h:69