76 :
public detail::ListSignalMixin<MappedList<Source, Target, SourceList>,
78 friend detail::ListSignalMixin<MappedList<Source, Target, SourceList>,
87 using Signal = detail::ListSignal<Target>;
102 bool remap_on_change =
false)
103 : source_(
std::move(source)),
105 state_(
std::make_shared<SharedState>())
107 state_->mapper = std::move(mapper);
108 state_->remap_on_change = remap_on_change;
112 std::unique_lock lk(state_->m);
113 auto snap = source_->snapshot();
114 state_->source_items = snap;
115 state_->targets.reserve(snap.size());
116 for (
const auto& s : snap) {
117 state_->targets.push_back(state_->mapper(*s));
122 std::weak_ptr<SharedState> weak_state = state_;
123 std::weak_ptr<Signal> weak_signal = signal_;
124 std::weak_ptr<SourceList> weak_source{source_};
125 source_sub_ = source_->observe(
127 auto st = weak_state.lock();
128 auto sig = weak_signal.lock();
129 auto src = weak_source.lock();
130 if (!st || !sig || !src)
return;
131 dispatch_source_change_(*st, *sig, ch);
141 [[nodiscard]] std::size_t
size()
const {
142 std::shared_lock lk(state_->m);
143 return state_->targets.size();
146 [[nodiscard]]
bool empty()
const {
return size() == 0; }
148 [[nodiscard]] std::shared_ptr<Target>
at(std::size_t idx)
const {
149 std::shared_lock lk(state_->m);
150 return state_->targets.at(idx);
153 [[nodiscard]] std::vector<std::shared_ptr<Target>>
snapshot()
const {
154 std::shared_lock lk(state_->m);
155 return state_->targets;
160 mutable std::shared_mutex m;
162 bool remap_on_change{
false};
163 std::vector<std::shared_ptr<Target>> targets;
167 std::vector<std::shared_ptr<Source>> source_items;
168 bool needs_rebuild =
false;
171 std::shared_ptr<SourceList> source_;
172 std::shared_ptr<Signal> signal_;
173 std::shared_ptr<SharedState> state_;
174 Subscription source_sub_;
176 static void dispatch_source_change_(SharedState& st,
178 const ListChange<Source>& ch) {
179 detail::replay_list_change(st.source_items, ch);
180 if (st.needs_rebuild) {
182 st.needs_rebuild =
false;
187 st.needs_rebuild =
true;
196 st.needs_rebuild =
false;
199 static void handle_insert_(SharedState& st,
Signal& sig,
200 const ListChange<Source>& ch) {
201 auto t = st.mapper(*ch.item);
203 std::unique_lock lk(st.m);
204 const std::size_t idx = ch.index;
205 st.targets.insert(st.targets.begin()
206 +
static_cast<std::ptrdiff_t
>(idx), t);
211 static void handle_remove_(SharedState& st,
Signal& sig,
212 const ListChange<Source>& ch) {
213 std::shared_ptr<Target> removed;
215 std::unique_lock lk(st.m);
216 const std::size_t idx = ch.index;
217 if (idx >= st.targets.size())
return;
218 removed = st.targets[idx];
219 st.targets.erase(st.targets.begin()
220 +
static_cast<std::ptrdiff_t
>(idx));
226 static void handle_replace_(SharedState& st,
Signal& sig,
227 const ListChange<Source>& ch) {
228 auto t = st.mapper(*ch.item);
229 std::shared_ptr<Target> retired;
231 std::unique_lock lk(st.m);
232 const std::size_t idx = ch.index;
233 if (idx >= st.targets.size())
return;
234 retired = std::exchange(st.targets[idx], t);
240 static void handle_item_changed_(SharedState& st,
Signal& sig,
241 const ListChange<Source>& ch) {
242 auto t = st.remap_on_change ? st.mapper(*ch.item) : std::shared_ptr<Target>{};
243 std::shared_ptr<Target> retired;
245 std::unique_lock lk(st.m);
246 const std::size_t idx = ch.index;
247 if (idx >= st.targets.size())
return;
249 if (st.remap_on_change) {
250 retired = std::exchange(st.targets[idx], t);
263 static void handle_move_(SharedState& st,
Signal& sig,
264 const ListChange<Source>& ch) {
265 std::shared_ptr<Target> moved;
267 std::unique_lock lk(st.m);
268 const std::size_t from = ch.from_index;
269 const std::size_t to = ch.index;
270 if (from == to)
return;
271 if (from >= st.targets.size() || to >= st.targets.size())
return;
273 moved = st.targets[from];
274 st.targets.erase(st.targets.begin()
275 +
static_cast<std::ptrdiff_t
>(from));
276 st.targets.insert(st.targets.begin()
277 +
static_cast<std::ptrdiff_t
>(to), moved);
280 moved, ch.from_index});
283 static void handle_reset_(SharedState& st,
Signal& sig,
284 const ListChange<Source>& ch) {
285 std::vector<std::shared_ptr<Target>> replacement;
286 replacement.reserve(ch.snapshot->size());
287 for (
const auto& item : *ch.snapshot) {
288 replacement.push_back(st.mapper(*item));
292 std::unique_lock lk(st.m);
293 st.targets.swap(replacement);
295 sig.emit(std::move(reset));