99 :
public detail::ListSignalMixin<FilteredList<T, Source>, T> {
100 friend detail::ListSignalMixin<FilteredList<T, Source>, T>;
112 : source_(
std::move(source)),
114 state_(
std::make_shared<SharedState>())
116 state_->predicate = std::move(predicate);
122 std::unique_lock lk(state_->m);
123 auto snap = source_->snapshot();
124 state_->source_items = snap;
125 state_->source_to_derived.assign(snap.size(), std::nullopt);
126 for (std::size_t i = 0; i < snap.size(); ++i) {
127 if (state_->predicate(*snap[i])) {
128 state_->source_to_derived[i] = state_->derived_to_source.size();
129 state_->derived_to_source.push_back(i);
130 state_->items.push_back(snap[i]);
138 std::weak_ptr<SharedState> weak_state = state_;
139 std::weak_ptr<Signal> weak_signal = signal_;
140 std::weak_ptr<Source> weak_source{source_};
141 source_sub_ = source_->observe(
142 [weak_state, weak_signal, weak_source](
const ListChange<T>& ch) {
143 auto st = weak_state.lock();
144 auto sig = weak_signal.lock();
145 auto src = weak_source.lock();
146 if (!st || !sig || !src)
return;
147 dispatch_source_change_(*st, *sig, ch);
157 [[nodiscard]] std::size_t
size()
const {
158 std::shared_lock lk(state_->m);
159 return state_->items.size();
162 [[nodiscard]]
bool empty()
const {
return size() == 0; }
164 [[nodiscard]] std::shared_ptr<T>
at(std::size_t derived_index)
const {
165 std::shared_lock lk(state_->m);
166 return state_->items.at(derived_index);
169 [[nodiscard]] std::vector<std::shared_ptr<T>>
snapshot()
const {
170 std::shared_lock lk(state_->m);
171 return state_->items;
174 [[nodiscard]] std::optional<std::size_t>
176 std::shared_lock lk(state_->m);
177 if (derived_index >= state_->derived_to_source.size())
return std::nullopt;
178 return state_->derived_to_source[derived_index];
189 auto signal = signal_;
190 std::vector<ListChange<T>> emissions;
193 std::unique_lock lk(state_->m);
194 state_->predicate = std::move(new_predicate);
196 const auto& snap = state_->source_items;
201 std::vector<std::optional<std::size_t>> new_s2d(snap.size(), std::nullopt);
202 std::vector<std::size_t> new_d2s;
203 std::vector<std::shared_ptr<T>> new_items;
204 new_d2s.reserve(snap.size());
205 new_items.reserve(snap.size());
225 std::size_t observed_pos = 0;
227 for (std::size_t i = 0; i < snap.size(); ++i) {
228 const bool was_in = (i < state_->source_to_derived.size())
229 && state_->source_to_derived[i].has_value();
230 const bool is_in = state_->predicate(*snap[i]);
233 new_s2d[i] = new_d2s.size();
234 new_d2s.push_back(i);
235 new_items.push_back(snap[i]);
238 if (was_in && !is_in) {
242 emissions.push_back({
246 }
else if (!was_in && is_in) {
248 emissions.push_back({
253 }
else if (was_in && is_in) {
261 state_->source_to_derived = std::move(new_s2d);
262 state_->derived_to_source = std::move(new_d2s);
263 state_->items = std::move(new_items);
269 signal->emit_batch(std::move(emissions));
277 mutable std::shared_mutex m;
280 std::vector<std::optional<std::size_t>> source_to_derived;
282 std::vector<std::size_t> derived_to_source;
284 std::vector<std::shared_ptr<T>> items;
285 std::vector<std::shared_ptr<T>> source_items;
288 std::shared_ptr<Source> source_;
289 std::shared_ptr<Signal> signal_;
290 std::shared_ptr<SharedState> state_;
291 Subscription source_sub_;
294 static void dispatch_source_change_(SharedState& st,
296 const ListChange<T>& ch) {
298 std::unique_lock lock(st.m);
299 detail::replay_list_change(st.source_items, ch);
311 static void handle_insert_(SharedState& st,
Signal& sig,
312 const ListChange<T>& ch) {
313 std::unique_lock lk(st.m);
314 const std::size_t src_idx = ch.index;
316 const bool is_in = st.predicate(*ch.item);
320 const auto position = st.derived_to_source.empty() || st.derived_to_source.back() < src_idx
321 ? st.derived_to_source.end()
322 : std::lower_bound(st.derived_to_source.begin(), st.derived_to_source.end(), src_idx);
323 const auto d_idx =
static_cast<std::size_t
>(position - st.derived_to_source.begin());
324 for (
auto it = position; it != st.derived_to_source.end(); ++it) ++*it;
326 st.source_to_derived.insert(st.source_to_derived.begin() +
static_cast<std::ptrdiff_t
>(src_idx),
331 st.derived_to_source.insert(st.derived_to_source.begin() +
static_cast<std::ptrdiff_t
>(d_idx),
335 auto shared = ch.item;
336 st.items.insert(st.items.begin() +
static_cast<std::ptrdiff_t
>(d_idx), std::move(shared));
338 for (std::size_t d = d_idx; d < st.derived_to_source.size(); ++d)
339 st.source_to_derived[st.derived_to_source[d]] = d;
345 static void handle_remove_(SharedState& st,
Signal& sig,
346 const ListChange<T>& ch) {
347 std::unique_lock lk(st.m);
348 const std::size_t src_idx = ch.index;
350 if (src_idx >= st.source_to_derived.size())
return;
352 std::optional<std::size_t> maybe_d = st.source_to_derived[src_idx];
353 st.source_to_derived.erase(st.source_to_derived.begin() +
static_cast<std::ptrdiff_t
>(src_idx));
356 for (
auto& s : st.derived_to_source) {
357 if (s > src_idx) --s;
361 const std::size_t d_idx = *maybe_d;
362 auto removed = st.items[d_idx];
363 st.items.erase(st.items.begin() +
static_cast<std::ptrdiff_t
>(d_idx));
364 st.derived_to_source.erase(st.derived_to_source.begin() +
static_cast<std::ptrdiff_t
>(d_idx));
386 static void handle_membership_transition_(SharedState& st,
Signal& sig,
387 const ListChange<T>& ch,
389 bool refresh_value) {
390 std::unique_lock lk(st.m);
391 const std::size_t src_idx = ch.index;
393 if (src_idx >= st.source_to_derived.size())
return;
395 const bool was_in = st.source_to_derived[src_idx].has_value();
396 const bool is_in = st.predicate(*ch.item);
398 if (!was_in && !is_in)
return;
400 if (was_in && is_in) {
401 const std::size_t d_idx = *st.source_to_derived[src_idx];
403 st.items[d_idx] = ch.item;
406 sig.emit(ListChange<T>{kind_for_in_in, d_idx, ch.item, 0});
410 if (was_in && !is_in) {
411 const std::size_t d_idx = *st.source_to_derived[src_idx];
412 auto removed = st.items[d_idx];
413 st.items.erase(st.items.begin() +
static_cast<std::ptrdiff_t
>(d_idx));
414 st.derived_to_source.erase(st.derived_to_source.begin() +
static_cast<std::ptrdiff_t
>(d_idx));
415 st.source_to_derived[src_idx] = std::nullopt;
424 std::size_t d_idx = 0;
425 for (std::size_t i = 0; i < src_idx; ++i) {
426 if (st.source_to_derived[i].has_value()) ++d_idx;
428 st.derived_to_source.insert(st.derived_to_source.begin() +
static_cast<std::ptrdiff_t
>(d_idx),
430 st.items.insert(st.items.begin() +
static_cast<std::ptrdiff_t
>(d_idx), ch.item);
431 st.source_to_derived[src_idx] = d_idx;
437 static void handle_replace_(SharedState& st,
Signal& sig,
438 const ListChange<T>& ch) {
439 handle_membership_transition_(st, sig, ch,
444 static void handle_item_changed_(SharedState& st,
Signal& sig,
445 const ListChange<T>& ch) {
446 handle_membership_transition_(st, sig, ch,
451 static void handle_move_(SharedState& st,
Signal& sig,
452 const ListChange<T>& ch) {
453 std::unique_lock lk(st.m);
454 const std::size_t from = ch.from_index;
455 const std::size_t to = ch.index;
457 if (from == to)
return;
458 if (from >= st.source_to_derived.size() ||
459 to >= st.source_to_derived.size()) {
464 const std::optional<std::size_t> old_d = st.source_to_derived[from];
467 auto moved_slot = st.source_to_derived[from];
468 st.source_to_derived.erase(st.source_to_derived.begin() +
static_cast<std::ptrdiff_t
>(from));
469 st.source_to_derived.insert(st.source_to_derived.begin() +
static_cast<std::ptrdiff_t
>(to),
478 std::size_t new_d = 0;
479 for (std::size_t i = 0; i < to; ++i) {
480 if (st.source_to_derived[i].has_value()) ++new_d;
485 if (new_d != *old_d) {
486 auto moved_src = st.derived_to_source[*old_d];
487 auto moved_item = st.items[*old_d];
488 st.derived_to_source.erase(st.derived_to_source.begin() +
static_cast<std::ptrdiff_t
>(*old_d));
489 st.items.erase(st.items.begin() +
static_cast<std::ptrdiff_t
>(*old_d));
490 st.derived_to_source.insert(
491 st.derived_to_source.begin() +
static_cast<std::ptrdiff_t
>(new_d), moved_src);
492 st.items.insert(st.items.begin() +
static_cast<std::ptrdiff_t
>(new_d), std::move(moved_item));
499 if (new_d != *old_d) {
509 renumber_d2s_after_source_move_(st, from, to);
513 static void handle_reset_(SharedState& st,
Signal& sig,
const ListChange<T>& ch) {
514 const auto&
snapshot = *ch.snapshot;
515 std::unique_lock lk(st.m);
516 st.source_to_derived.clear();
517 st.derived_to_source.clear();
519 st.source_to_derived.resize(
snapshot.size(), std::nullopt);
520 for (std::size_t i = 0; i <
snapshot.size(); ++i) {
521 if (!st.predicate(*
snapshot[i]))
continue;
522 st.source_to_derived[i] = st.items.size();
523 st.derived_to_source.push_back(i);
528 sig.emit(std::move(reset));
534 static void renumber_s2d_(SharedState& st) {
536 for (std::size_t s = 0; s < st.source_to_derived.size(); ++s) {
537 auto& slot = st.source_to_derived[s];
538 if (slot.has_value()) {
540 st.derived_to_source[d++] = s;
550 static void renumber_d2s_after_source_move_(SharedState& st,
554 for (
auto& s : st.derived_to_source) {
555 if (s > from && s <= to) --s;
560 for (
auto& s : st.derived_to_source) {
561 if (s >= to && s < from) ++s;