91 :
public detail::ListSignalMixin<SortedList<T, Source>, T> {
92 friend detail::ListSignalMixin<SortedList<T, Source>, T>;
104 : source_(
std::move(source)),
106 state_(
std::make_shared<SharedState>())
108 state_->comparator = std::move(comparator);
116 std::unique_lock lk(state_->m);
117 rebuild_from_snapshot_unlocked_(*state_, source_->snapshot());
121 std::weak_ptr<SharedState> weak_state = state_;
122 std::weak_ptr<Signal> weak_signal = signal_;
123 std::weak_ptr<Source> weak_source{source_};
124 source_sub_ = source_->observe(
125 [weak_state, weak_signal, weak_source](
const ListChange<T>& ch) {
126 auto st = weak_state.lock();
127 auto sig = weak_signal.lock();
128 auto src = weak_source.lock();
129 if (!st || !sig || !src)
return;
130 dispatch_source_change_(*st, *sig, ch);
140 [[nodiscard]] std::size_t
size()
const {
141 std::shared_lock lk(state_->m);
142 return state_->items.size();
145 [[nodiscard]]
bool empty()
const {
return size() == 0; }
147 [[nodiscard]] std::shared_ptr<T>
at(std::size_t derived_index)
const {
148 std::shared_lock lk(state_->m);
149 return state_->items.at(derived_index);
152 [[nodiscard]] std::vector<std::shared_ptr<T>>
snapshot()
const {
153 std::shared_lock lk(state_->m);
154 return state_->items;
157 [[nodiscard]] std::optional<std::size_t>
159 std::shared_lock lk(state_->m);
160 if (derived_index >= state_->derived_to_source.size())
return std::nullopt;
161 return state_->derived_to_source[derived_index];
171 auto signal = signal_;
174 std::unique_lock lk(state_->m);
175 state_->comparator = std::move(new_comparator);
176 std::vector<std::shared_ptr<T>> source_items(state_->items.size());
177 for (std::size_t i = 0; i < state_->items.size(); ++i) {
178 source_items[state_->derived_to_source[i]] = state_->items[i];
180 rebuild_from_snapshot_unlocked_(*state_, std::move(source_items));
183 signal->emit(std::move(reset));
189 mutable std::shared_mutex m;
192 std::vector<std::size_t> source_to_derived;
194 std::vector<std::size_t> derived_to_source;
196 std::vector<std::shared_ptr<T>> items;
199 std::shared_ptr<Source> source_;
200 std::shared_ptr<Signal> signal_;
201 std::shared_ptr<SharedState> state_;
202 Subscription source_sub_;
207 static void rebuild_from_snapshot_unlocked_(
209 std::vector<std::shared_ptr<T>> snap)
211 std::vector<std::size_t> idx(snap.size());
212 for (std::size_t i = 0; i < snap.size(); ++i) idx[i] = i;
213 std::stable_sort(idx.begin(), idx.end(),
214 [&](std::size_t a, std::size_t b) {
215 return st.comparator(*snap[a], *snap[b]);
218 st.source_to_derived.assign(snap.size(), 0);
219 st.derived_to_source.assign(idx.size(), 0);
221 st.items.reserve(idx.size());
222 for (std::size_t d = 0; d < idx.size(); ++d) {
223 const std::size_t s = idx[d];
224 st.derived_to_source[d] = s;
225 st.source_to_derived[s] = d;
226 st.items.push_back(snap[s]);
232 static void dispatch_source_change_(SharedState& st,
234 const ListChange<T>& ch) {
266 static std::size_t binary_search_insert_(
267 const SharedState& st,
const T& needle, std::size_t needle_src_i,
268 std::optional<std::size_t> skip_derived_idx = std::nullopt)
270 const auto& cmp = st.comparator;
271 const auto& items = st.items;
272 const auto& d2s = st.derived_to_source;
278 auto real = [&](std::size_t compressed) -> std::size_t {
279 if (skip_derived_idx && compressed >= *skip_derived_idx)
280 return compressed + 1;
283 const std::size_t n_eff = items.size()
284 - (skip_derived_idx ? 1u : 0u);
287 std::size_t hi = n_eff;
289 const std::size_t mid = lo + (hi - lo) / 2;
290 const std::size_t r = real(mid);
291 const auto& mid_item = *items[r];
292 if (cmp(needle, mid_item)) {
294 }
else if (cmp(mid_item, needle)) {
299 if (needle_src_i < d2s[r]) hi = mid;
306 static void handle_insert_(SharedState& st,
Signal& sig,
307 const ListChange<T>& ch) {
308 std::unique_lock lk(st.m);
309 const std::size_t src_idx = ch.index;
313 if (src_idx != st.items.size()) {
314 for (
auto& s : st.derived_to_source) {
315 if (s >= src_idx) ++s;
318 st.source_to_derived.insert(st.source_to_derived.begin()
319 +
static_cast<std::ptrdiff_t
>(src_idx),
324 auto shared = ch.item;
326 const bool ordered = ordered_unlocked_(st);
327 const std::size_t d_idx = ordered ? binary_search_insert_(st, *shared, src_idx) : st.items.
size();
329 st.derived_to_source.insert(st.derived_to_source.begin()
330 +
static_cast<std::ptrdiff_t
>(d_idx),
332 st.items.insert(st.items.begin()
333 +
static_cast<std::ptrdiff_t
>(d_idx),
338 renumber_s2d_(st, d_idx);
341 auto moves = reorder_unlocked_(st);
342 moves.insert(moves.begin(), {ListChangeKind::Insert, d_idx, ch.item, 0});
344 sig.emit_batch(std::move(moves));
351 static void handle_remove_(SharedState& st,
Signal& sig,
352 const ListChange<T>& ch) {
353 std::unique_lock lk(st.m);
354 const std::size_t src_idx = ch.index;
355 if (src_idx >= st.source_to_derived.size())
return;
357 const std::size_t d_idx = st.source_to_derived[src_idx];
358 auto removed = st.items[d_idx];
360 st.items.erase(st.items.begin() +
static_cast<std::ptrdiff_t
>(d_idx));
361 st.derived_to_source.erase(
362 st.derived_to_source.begin() +
static_cast<std::ptrdiff_t
>(d_idx));
363 st.source_to_derived.erase(
364 st.source_to_derived.begin() +
static_cast<std::ptrdiff_t
>(src_idx));
367 for (
auto& s : st.derived_to_source) {
368 if (s > src_idx) --s;
372 if (!ordered_unlocked_(st)) {
373 auto moves = reorder_unlocked_(st);
374 moves.insert(moves.begin(), {ListChangeKind::Remove, d_idx, removed, 0});
376 sig.emit_batch(std::move(moves));
383 static void handle_replace_(SharedState& st,
Signal& sig,
384 const ListChange<T>& ch) {
385 handle_slot_changed_(st, sig, ch,
391 static void handle_item_changed_(SharedState& st,
Signal& sig,
392 const ListChange<T>& ch) {
393 handle_slot_changed_(st, sig, ch,
402 static bool ordered_unlocked_(
const SharedState& st,
403 std::optional<std::size_t> skip = std::nullopt) {
404 std::optional<std::size_t> previous;
405 for (std::size_t d = 0; d < st.items.size(); ++d) {
406 if (skip == d)
continue;
408 const auto p = *previous;
413 if (st.derived_to_source[d] < st.derived_to_source[p]) {
414 if (!st.comparator(*st.items[p], *st.items[d]))
return false;
415 }
else if (st.comparator(*st.items[d], *st.items[p])) {
426 static void move_row_unlocked_(SharedState& st, std::size_t from, std::size_t to)
noexcept {
427 auto item = std::move(st.items[from]);
428 const auto source_index = st.derived_to_source[from];
429 const auto first =
static_cast<std::ptrdiff_t
>(std::min(from, to));
430 const auto last =
static_cast<std::ptrdiff_t
>(std::max(from, to));
432 std::move(st.items.begin() + first + 1, st.items.begin() + last + 1, st.items.begin() + first);
433 std::move(st.derived_to_source.begin() + first + 1, st.derived_to_source.begin() + last + 1,
434 st.derived_to_source.begin() + first);
436 std::move_backward(st.items.begin() + first, st.items.begin() + last, st.items.begin() + last + 1);
437 std::move_backward(st.derived_to_source.begin() + first, st.derived_to_source.begin() + last,
438 st.derived_to_source.begin() + last + 1);
440 st.items[to] = std::move(item);
441 st.derived_to_source[to] = source_index;
442 for (
auto d = std::min(from, to); d <= std::max(from, to); ++d)
443 st.source_to_derived[st.derived_to_source[d]] = d;
449 static std::vector<ListChange<T>> reorder_unlocked_(SharedState& st) {
450 auto before = [&](std::size_t a, std::size_t b) {
451 const auto& lhs = *st.items[st.source_to_derived[a]];
452 const auto& rhs = *st.items[st.source_to_derived[b]];
453 if (st.comparator(lhs, rhs))
return true;
454 if (st.comparator(rhs, lhs))
return false;
457 std::vector<ListChange<T>> events;
458 if (std::is_sorted(st.derived_to_source.begin(), st.derived_to_source.end(), before))
return events;
459 auto target = st.derived_to_source;
460 std::sort(target.begin(), target.end(), before);
461 events.reserve(target.size());
465 std::size_t first = 0, last = target.size();
466 while (first < last && target[first] == st.derived_to_source[first]) ++first;
467 while (last > first && target[last - 1] == st.derived_to_source[last - 1]) --last;
468 const bool reverse = st.source_to_derived[target[first]] - first <
469 last - 1 - st.source_to_derived[target[last - 1]];
470 auto place = [&](std::size_t to) {
471 const auto from = st.source_to_derived[target[to]];
472 if (from == to)
return;
473 const auto item = st.items[from];
475 move_row_unlocked_(st, from, to);
477 if (reverse) {
for (
auto i = last; i-- > first;) place(i); }
478 else {
for (
auto i = first; i < last; ++i) place(i); }
492 static void handle_slot_changed_(SharedState& st,
Signal& sig,
493 const ListChange<T>& ch,
494 bool new_ptr_from_src,
496 bool cross_slot_use_move) {
497 std::unique_lock lk(st.m);
498 const std::size_t src_idx = ch.index;
499 if (src_idx >= st.source_to_derived.size())
return;
501 const std::size_t d_old = st.source_to_derived[src_idx];
504 auto previous = st.items[d_old];
505 auto fresh = new_ptr_from_src ? ch.item : previous;
506 if (new_ptr_from_src) st.items[d_old] = fresh;
507 if (!ordered_unlocked_(st, d_old)) {
508 auto moves = reorder_unlocked_(st);
509 if (new_ptr_from_src) {
511 moves.insert(moves.begin(), {ListChangeKind::Replace, d_old, fresh, 0});
516 sig.emit_batch(std::move(moves));
525 const std::size_t p_small = binary_search_insert_(
526 st, *fresh, src_idx, d_old);
528 if (p_small == d_old) {
531 sig.emit(ListChange<T>{same_slot_kind, d_old, fresh, 0});
537 const std::size_t d_insert = p_small;
538 move_row_unlocked_(st, d_old, d_insert);
541 if (cross_slot_use_move) {
553 static void handle_move_(SharedState& st,
Signal& sig,
554 const ListChange<T>& ch) {
555 std::unique_lock lk(st.m);
556 const std::size_t from = ch.from_index;
557 const std::size_t to = ch.index;
558 if (from == to)
return;
559 if (from >= st.source_to_derived.size())
return;
560 if (to >= st.source_to_derived.size())
return;
566 const std::size_t moved_d = st.source_to_derived[from];
569 for (
auto& s : st.derived_to_source) {
570 if (s > from && s <= to) --s;
573 for (
auto& s : st.derived_to_source) {
574 if (s >= to && s < from) ++s;
577 st.derived_to_source[moved_d] = to;
581 if (!ordered_unlocked_(st)) {
582 auto moves = reorder_unlocked_(st);
584 sig.emit_batch(std::move(moves));
588 static void handle_reset_(SharedState& st,
Signal& sig,
589 const ListChange<T>& ch) {
592 std::unique_lock lk(st.m);
593 rebuild_from_snapshot_unlocked_(st, *ch.snapshot);
596 sig.emit(std::move(reset));
602 static void renumber_s2d_(SharedState& st, std::size_t first = 0) {
603 for (std::size_t d = first; d < st.derived_to_source.size(); ++d) {
604 st.source_to_derived[st.derived_to_source[d]] = d;