34 namespace native_merge_detail {
35 template <
class T> T &
composer(T & value) {
return value; }
36 template <
class T> T &
composer(std::reference_wrapper<T> value) {
return value.get(); }
39 if constexpr (
requires { semantic.is_tombstone(value); })
40 return semantic.is_tombstone(value);
41 else if constexpr (
requires { semantic.is_tombstone(
bit_view{}, value); }) {
42 auto full = std::invoke(std::forward<Key>(key));
43 if constexpr (std::is_same_v<
decltype(full),
bit_view>)
return semantic.is_tombstone(full, value);
44 else return semantic.is_tombstone(full.view(), value);
54 :
data_(view.bytes(), view.metadata().extent << P::unit_shift),
cursor_(view) {
63 std::uint64_t begin = 0;
74 if (
done())
return std::nullopt;
77 if (result.order >= 0)
78 throw std::invalid_argument(
"native merge inputs must have unique sorted keys");
88 static_assert(
sizeof(
span) == 16);
90 auto first =
spans_.size();
93 while (first &&
spans_[first - 1].end_units > retained) --first;
94 auto begin = first ?
spans_[first - 1].end_units : 0;
98 auto offset =
spans_[first].source_bit_offset + ((retained - begin) << P::unit_shift);
101 if (before != after) {
102 auto common =
unsigned(std::countl_zero(before ^ after)) - (64 - P::bits_per_unit);
103 return {(retained << P::unit_shift) + common, before < after ? -1 : 1};
106 auto position = retained;
115 result.common_bits += (retained << P::unit_shift) +
compared;
125 return {(retained << P::unit_shift) +
compared,
132 if (begin >= retained)
spans_.pop_back();
134 if (
spans_.back().end_units > retained)
spans_.back().end_units = retained;
172 template <
class P,
class Native = profile_array<P>,
class Compose = replace_native_value,
173 class Output = profile_detail::native_output<P>>
175 static_assert(std::is_same_v<typename Native::policy_type, P>);
176 static_assert(std::is_same_v<typename Output::policy_type, P>);
180 static_assert(
noexcept(std::declval<Output const &>().finished()));
181 static_assert(
noexcept(std::declval<Output const &>().failed()));
183 static constexpr bool encoded_keys = std::is_same_v<Compose, replace_native_value> ||
184 (!std::is_invocable_v<Compose &, bit_view, bit_view, bit_view> &&
185 std::is_invocable_v<Compose &, bit_view, bit_view>);
186 static_assert(
encoded_keys || std::is_invocable_v<Compose &, bit_view, bit_view, bit_view>,
187 "native composition accepts (key, older, newer) or (older, newer)");
190 std::optional<std::uint64_t> common_value_width = P::value_width)
191 requires std::is_constructible_v<Output, std::optional<std::uint64_t>>
192 :
native_merge_builder(Output(common_value_width), std::move(older), std::move(newer), std::move(compose)) {}
201 requires (std::is_move_assignable_v<Compose> && std::is_move_assignable_v<Output>) {
202 if (
this != &other) {
206 older_ = std::move(other.older_);
newer_ = std::move(other.newer_);
208 writer_ = std::move(other.writer_);
compose_ = std::move(other.compose_);
229 while (work.
keys < key_budget && !
done()) {
231 auto order = comparison.order;
232 auto consumed = order == 0 ? 2u : 1u;
240 }
else if (order > 0) {
249 else return std::invoke(
compose_, older.key.prefix, older.value, newer.value);
252 auto emit = [&](
auto const & source,
auto const & item) {
253 if constexpr (std::is_same_v<
decltype(value),
bit_view>)
261 if (newer.retained < older.retained) emit(
newer_cursor_, newer);
280 if (!
done())
throw std::logic_error(
"native merge has unconsumed inputs");
281 try {
return writer_.finish(); }
291 using cursor_type = std::conditional_t<encoded_keys, native_merge_detail::encoded_source<P>,
295 if (retained < item.retained)
296 throw std::invalid_argument(
"native merge output prefix precedes input prefix");
297 auto first = (retained - item.retained) << P::unit_shift;
298 return item.suffix.subview(first, item.suffix.size() - first);
300 auto first = retained << P::unit_shift;
301 return item.key.prefix.subview(first, item.key.prefix.size() - first);
305 std::uint64_t retained, std::uint64_t limit_bits) {
307 if constexpr (
encoded_keys)
return source.materialize();
308 else return item.key.prefix;
309 })) retained = std::min(retained, limit_bits >> P::unit_shift);
311 if (retained < item.retained) {
312 auto key = source.materialize();
313 auto first = retained << P::unit_shift;
331 result.common_bits += start;
335 auto comparison = cursor.advance_comparison();
336 if (!comparison)
return 0;
337 if (comparison->order >= 0)
338 throw std::invalid_argument(
"native merge inputs must have unique sorted keys");
339 return comparison->common_bits >> P::unit_shift;
342 if (output.size() || output.finished() || output.failed())
343 throw std::invalid_argument(
"native merge output must be empty and active");
347 if (!source)
throw std::invalid_argument(
"null native merge input");
352 throw std::logic_error(
"native merge is inactive");
bool is_tombstone(Compose &compose, bit_view value, Key &&key)
Definition native_merge.h:37
T & composer(T &value)
Definition native_merge.h:35
std::uint64_t add(std::uint64_t a, std::uint64_t b)
Definition profile.h:39
std::uint64_t load_bits(bit_view data, std::uint64_t first, unsigned width) noexcept
Definition profile.h:93
void append(bit_string &target, bit_view source)
Definition profile.h:480
Definition active_engine.h:18
Builds native front-coded profiles incrementally with explicit value widths.
bit_view view() const &
Definition profile.h:178
std::uint64_t bit_size
Definition profile.h:168
std::uint64_t size() const noexcept
Definition profile.h:64
std::uint64_t offset() const noexcept
Definition profile.h:66
bool empty() const noexcept
Definition profile.h:65
bit_view subview(std::uint64_t first, std::uint64_t count) const
Definition profile.h:73
Definition native_merge.h:174
source_pointer older_
Definition native_merge.h:354
std::uint64_t older_prefix_
Definition native_merge.h:361
Native source_type
Definition native_merge.h:178
std::uint64_t newer_prefix_
Definition native_merge.h:362
native_merge_builder(Output output, source_pointer older, source_pointer newer, Compose compose={})
Definition native_merge.h:193
native_merge_progress step(std::uint64_t key_budget=1)
Definition native_merge.h:225
std::shared_ptr< Native const > source_pointer
Definition native_merge.h:182
Output output_type
Definition native_merge.h:179
cursor_type older_cursor_
Definition native_merge.h:356
native_merge_builder(native_merge_builder const &)=delete
auto finish()
Definition native_merge.h:278
P policy_type
Definition native_merge.h:177
std::conditional_t< encoded_keys, native_merge_detail::encoded_source< P >, profile_cursor< P, stream_role::native > > cursor_type
Definition native_merge.h:292
native_merge_builder & operator=(native_merge_builder &&other)
Definition native_merge.h:200
static source_pointer checked(source_pointer source)
Definition native_merge.h:346
Output writer_
Definition native_merge.h:358
bool done() const noexcept
Definition native_merge.h:216
bool finished() const noexcept
Definition native_merge.h:220
native_merge_builder(source_pointer older, source_pointer newer, Compose compose={}, std::optional< std::uint64_t > common_value_width=P::value_width)
Definition native_merge.h:189
native_merge_progress progress() const noexcept
Definition native_merge.h:221
bool failed() const noexcept
Definition native_merge.h:219
void require_active() const
Definition native_merge.h:350
source_pointer newer_source() const noexcept
Definition native_merge.h:223
void append(cursor_type const &source, auto const &item, bit_view value, std::uint64_t retained, std::uint64_t limit_bits)
Definition native_merge.h:304
source_pointer newer_
Definition native_merge.h:355
native_merge_progress progress_
Definition native_merge.h:360
Compose compose_
Definition native_merge.h:359
static constexpr bool encoded_keys
Definition native_merge.h:183
static bit_view suffix(auto const &item, std::uint64_t retained)
Definition native_merge.h:293
bit_comparison compare_heads() const
Definition native_merge.h:322
source_pointer older_source() const noexcept
Definition native_merge.h:222
static std::uint64_t advance(cursor_type &cursor)
Definition native_merge.h:334
native_merge_builder(native_merge_builder &&)=default
bool failed_
Definition native_merge.h:363
native_merge_builder & operator=(native_merge_builder const &)=delete
static Output checked_output(Output output)
Definition native_merge.h:341
cursor_type newer_cursor_
Definition native_merge.h:357
Definition native_merge.h:84
std::uint64_t source_bit_offset
Definition native_merge.h:85
std::uint64_t end_units
Definition native_merge.h:86
Definition native_merge.h:52
encoded_source(profile_view< P > view)
Definition native_merge.h:53
bit_comparison compare_successor(std::uint64_t retained, bit_view suffix) const
Definition native_merge.h:89
profile_encoded_cursor< P > cursor_
Definition native_merge.h:143
void retain(profile_encoded_record const &record)
Definition native_merge.h:128
bit_string materialize() const
Definition native_merge.h:61
profile_encoded_record const & peek() const &&=delete
std::uint64_t retained_bits() const
Definition native_merge.h:60
std::optional< bit_comparison > advance_comparison()
Definition native_merge.h:72
std::vector< span > spans_
Definition native_merge.h:144
bool done() const noexcept
Definition native_merge.h:57
bit_view data_
Definition native_merge.h:142
profile_encoded_record const & peek() const &
Definition native_merge.h:58
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 profile.h:1066
bool done() const noexcept
Definition profile.h:1023
void advance()
Definition profile.h:1031
profile_encoded_record const & peek() const &
Definition profile.h:1025
bit_view suffix
Definition profile.h:312
std::uint64_t retained
Definition profile.h:309
std::uint64_t key_units
Definition profile.h:310
Definition native_merge.h:29
bit_view operator()(bit_view, bit_view, bit_view newer) const
Definition native_merge.h:30
bit_view operator()(bit_view, bit_view newer) const
Definition native_merge.h:31