100 :
public detail::ListSignalMixin<FilteredList<T, Source>, T> {
101 friend detail::ListSignalMixin<FilteredList<T, Source>, T>;
113 : source_(
std::move(source)),
115 state_(
std::make_shared<SharedState>())
117 state_->predicate = std::make_shared<Predicate>(std::move(predicate));
123 std::unique_lock lk(state_->m);
124 auto snap = source_->snapshot();
125 state_->source_items = snap;
126 state_->source_to_derived.assign(snap.size(), std::nullopt);
127 for (std::size_t i = 0; i < snap.size(); ++i) {
128 if ((*state_->predicate)(*snap[i])) {
129 state_->source_to_derived[i] = state_->derived_to_source.size();
130 state_->derived_to_source.push_back(i);
131 state_->items.push_back(snap[i]);
139 std::weak_ptr<SharedState> weak_state = state_;
140 std::weak_ptr<Signal> weak_signal = signal_;
141 std::weak_ptr<Source> weak_source{source_};
142 source_sub_ = source_->observe(
143 [weak_state, weak_signal, weak_source](
const ListChange<T>& ch) {
144 auto st = weak_state.lock();
145 auto sig = weak_signal.lock();
146 auto src = weak_source.lock();
147 if (!st || !sig || !src)
return;
148 st->updates.submit([st, sig, ch] { dispatch_source_change_(*st, *sig, ch); });
158 [[nodiscard]] std::size_t
size()
const {
159 std::shared_lock lk(state_->m);
160 return state_->items.size();
163 [[nodiscard]]
bool empty()
const {
return size() == 0; }
165 [[nodiscard]] std::shared_ptr<T>
at(std::size_t derived_index)
const {
166 std::shared_lock lk(state_->m);
167 return state_->items.at(derived_index);
170 [[nodiscard]] std::vector<std::shared_ptr<T>>
snapshot()
const {
171 std::shared_lock lk(state_->m);
172 return state_->items;
175 [[nodiscard]] std::optional<std::size_t>
177 std::shared_lock lk(state_->m);
178 if (derived_index >= state_->derived_to_source.size())
return std::nullopt;
179 return state_->derived_to_source[derived_index];
191 auto signal = signal_;
192 auto predicate = std::make_shared<Predicate>(std::move(new_predicate));
193 state->updates.submit([state, signal, predicate = std::move(predicate)] {
194 replace_predicate(*state, *signal, predicate);
203 mutable std::shared_mutex m;
204 std::shared_ptr<Predicate> predicate;
205 detail::ListUpdateQueue updates;
206 bool needs_rebuild =
false;
208 std::vector<std::optional<std::size_t>> source_to_derived;
210 std::vector<std::size_t> derived_to_source;
212 std::vector<std::shared_ptr<T>> items;
213 std::vector<std::shared_ptr<T>> source_items;
216 std::shared_ptr<Source> source_;
217 std::shared_ptr<Signal> signal_;
218 std::shared_ptr<SharedState> state_;
219 Subscription source_sub_;
221 template<
class Value>
222 static void reserve_one(std::vector<Value>& values) {
223 if (values.size() != values.capacity()) {
return; }
224 const auto next = values.size() < values.max_size() / 2
225 ? std::max<std::size_t>(1, values.size() * 2) : values.max_size();
226 values.reserve(next);
229 static void replace_predicate(SharedState& st,
Signal& signal,
230 std::shared_ptr<Predicate> predicate) {
233 const auto& snap = st.source_items;
234 std::vector<std::optional<std::size_t>> s2d(snap.size(), std::nullopt);
235 std::vector<std::size_t> d2s;
236 std::vector<std::shared_ptr<T>> items;
237 std::vector<ListChange<T>> events;
238 d2s.reserve(snap.size());
239 items.reserve(snap.size());
240 events.reserve(snap.size());
241 std::size_t observed_pos = 0;
242 for (std::size_t i = 0; i < snap.size(); ++i) {
243 const bool was_in = i < st.source_to_derived.size() && st.source_to_derived[i].has_value();
244 const bool is_in = (*predicate)(*snap[i]);
246 s2d[i] = items.size();
248 items.push_back(snap[i]);
250 if (was_in && !is_in) {
252 }
else if (!was_in && is_in) {
255 if (is_in) { ++observed_pos; }
259 std::unique_lock lock(st.m);
260 st.predicate.swap(predicate);
261 st.source_to_derived.swap(s2d);
262 st.derived_to_source.swap(d2s);
263 st.items.swap(items);
264 st.needs_rebuild =
false;
266 signal.emit_batch(std::move(events));
271 static void dispatch_source_change_(SharedState& st,
273 const ListChange<T>& ch) {
274 detail::replay_list_change(st.source_items, ch);
275 if (st.needs_rebuild) {
277 st.needs_rebuild =
false;
280 st.needs_rebuild =
true;
289 st.needs_rebuild =
false;
292 static void handle_insert_(SharedState& st,
Signal& sig,
293 const ListChange<T>& ch) {
294 const bool is_in = (*st.predicate)(*ch.item);
295 std::unique_lock lk(st.m);
296 const std::size_t src_idx = ch.index;
298 reserve_one(st.source_to_derived);
300 reserve_one(st.items);
301 reserve_one(st.derived_to_source);
306 const auto position = st.derived_to_source.empty() || st.derived_to_source.back() < src_idx
307 ? st.derived_to_source.end()
308 : std::lower_bound(st.derived_to_source.begin(), st.derived_to_source.end(), src_idx);
309 const auto d_idx =
static_cast<std::size_t
>(position - st.derived_to_source.begin());
310 for (
auto it = position; it != st.derived_to_source.end(); ++it) ++*it;
312 st.source_to_derived.insert(st.source_to_derived.begin() +
static_cast<std::ptrdiff_t
>(src_idx),
317 st.derived_to_source.insert(st.derived_to_source.begin() +
static_cast<std::ptrdiff_t
>(d_idx),
321 auto shared = ch.item;
322 st.items.insert(st.items.begin() +
static_cast<std::ptrdiff_t
>(d_idx), std::move(shared));
324 for (std::size_t d = d_idx; d < st.derived_to_source.size(); ++d)
325 st.source_to_derived[st.derived_to_source[d]] = d;
331 static void handle_remove_(SharedState& st,
Signal& sig,
332 const ListChange<T>& ch) {
333 std::unique_lock lk(st.m);
334 const std::size_t src_idx = ch.index;
336 if (src_idx >= st.source_to_derived.size())
return;
338 std::optional<std::size_t> maybe_d = st.source_to_derived[src_idx];
339 st.source_to_derived.erase(st.source_to_derived.begin() +
static_cast<std::ptrdiff_t
>(src_idx));
342 for (
auto& s : st.derived_to_source) {
343 if (s > src_idx) --s;
347 const std::size_t d_idx = *maybe_d;
348 auto removed = st.items[d_idx];
349 st.items.erase(st.items.begin() +
static_cast<std::ptrdiff_t
>(d_idx));
350 st.derived_to_source.erase(st.derived_to_source.begin() +
static_cast<std::ptrdiff_t
>(d_idx));
372 static void handle_membership_transition_(SharedState& st,
Signal& sig,
373 const ListChange<T>& ch,
375 bool refresh_value) {
376 const bool is_in = (*st.predicate)(*ch.item);
377 std::shared_ptr<T> retired;
378 std::unique_lock lk(st.m);
379 const std::size_t src_idx = ch.index;
381 if (src_idx >= st.source_to_derived.size())
return;
382 const bool was_in = st.source_to_derived[src_idx].has_value();
383 if (!was_in && is_in) {
384 reserve_one(st.items);
385 reserve_one(st.derived_to_source);
388 if (!was_in && !is_in)
return;
390 if (was_in && is_in) {
391 const std::size_t d_idx = *st.source_to_derived[src_idx];
393 retired = std::exchange(st.items[d_idx], ch.item);
396 sig.emit(ListChange<T>{kind_for_in_in, d_idx, ch.item, 0});
400 if (was_in && !is_in) {
401 const std::size_t d_idx = *st.source_to_derived[src_idx];
402 auto removed = st.items[d_idx];
403 st.items.erase(st.items.begin() +
static_cast<std::ptrdiff_t
>(d_idx));
404 st.derived_to_source.erase(st.derived_to_source.begin() +
static_cast<std::ptrdiff_t
>(d_idx));
405 st.source_to_derived[src_idx] = std::nullopt;
414 std::size_t d_idx = 0;
415 for (std::size_t i = 0; i < src_idx; ++i) {
416 if (st.source_to_derived[i].has_value()) ++d_idx;
418 st.derived_to_source.insert(st.derived_to_source.begin() +
static_cast<std::ptrdiff_t
>(d_idx),
420 st.items.insert(st.items.begin() +
static_cast<std::ptrdiff_t
>(d_idx), ch.item);
421 st.source_to_derived[src_idx] = d_idx;
427 static void handle_replace_(SharedState& st,
Signal& sig,
428 const ListChange<T>& ch) {
429 handle_membership_transition_(st, sig, ch,
434 static void handle_item_changed_(SharedState& st,
Signal& sig,
435 const ListChange<T>& ch) {
436 handle_membership_transition_(st, sig, ch,
441 static void handle_move_(SharedState& st,
Signal& sig,
442 const ListChange<T>& ch) {
443 std::unique_lock lk(st.m);
444 const std::size_t from = ch.from_index;
445 const std::size_t to = ch.index;
447 if (from == to)
return;
448 if (from >= st.source_to_derived.size() ||
449 to >= st.source_to_derived.size()) {
454 const std::optional<std::size_t> old_d = st.source_to_derived[from];
457 auto moved_slot = st.source_to_derived[from];
458 st.source_to_derived.erase(st.source_to_derived.begin() +
static_cast<std::ptrdiff_t
>(from));
459 st.source_to_derived.insert(st.source_to_derived.begin() +
static_cast<std::ptrdiff_t
>(to),
468 std::size_t new_d = 0;
469 for (std::size_t i = 0; i < to; ++i) {
470 if (st.source_to_derived[i].has_value()) ++new_d;
475 if (new_d != *old_d) {
476 auto moved_src = st.derived_to_source[*old_d];
477 auto moved_item = st.items[*old_d];
478 st.derived_to_source.erase(st.derived_to_source.begin() +
static_cast<std::ptrdiff_t
>(*old_d));
479 st.items.erase(st.items.begin() +
static_cast<std::ptrdiff_t
>(*old_d));
480 st.derived_to_source.insert(
481 st.derived_to_source.begin() +
static_cast<std::ptrdiff_t
>(new_d), moved_src);
482 st.items.insert(st.items.begin() +
static_cast<std::ptrdiff_t
>(new_d), std::move(moved_item));
489 if (new_d != *old_d) {
499 renumber_d2s_after_source_move_(st, from, to);
503 static void handle_reset_(SharedState& st,
Signal& sig,
const ListChange<T>& ch) {
504 const auto&
snapshot = *ch.snapshot;
505 std::vector<std::optional<std::size_t>> s2d(
snapshot.size(), std::nullopt);
506 std::vector<std::size_t> d2s;
507 std::vector<std::shared_ptr<T>> items;
510 for (std::size_t i = 0; i <
snapshot.size(); ++i) {
511 if (!(*st.predicate)(*
snapshot[i]))
continue;
512 s2d[i] = items.size();
518 std::unique_lock lock(st.m);
519 st.source_to_derived.swap(s2d);
520 st.derived_to_source.swap(d2s);
521 st.items.swap(items);
523 sig.emit(std::move(reset));
529 static void renumber_s2d_(SharedState& st) {
531 for (std::size_t s = 0; s < st.source_to_derived.size(); ++s) {
532 auto& slot = st.source_to_derived[s];
533 if (slot.has_value()) {
535 st.derived_to_source[d++] = s;
545 static void renumber_d2s_after_source_move_(SharedState& st,
549 for (
auto& s : st.derived_to_source) {
550 if (s > from && s <= to) --s;
555 for (
auto& s : st.derived_to_source) {
556 if (s >= to && s < from) ++s;