75 :
public detail::ListSignalMixin<MappedList<Source, Target, SourceList>,
77 friend detail::ListSignalMixin<MappedList<Source, Target, SourceList>,
86 using Signal = detail::ListSignal<Target>;
101 bool remap_on_change =
false)
102 : source_(
std::move(source)),
104 state_(
std::make_shared<SharedState>())
106 state_->mapper = std::move(mapper);
107 state_->remap_on_change = remap_on_change;
111 std::unique_lock lk(state_->m);
112 auto snap = source_->snapshot();
113 state_->targets.reserve(snap.size());
114 for (
const auto& s : snap) {
115 state_->targets.push_back(state_->mapper(*s));
120 std::weak_ptr<SharedState> weak_state = state_;
121 std::weak_ptr<Signal> weak_signal = signal_;
122 std::weak_ptr<SourceList> weak_source{source_};
123 source_sub_ = source_->observe(
125 auto st = weak_state.lock();
126 auto sig = weak_signal.lock();
127 auto src = weak_source.lock();
128 if (!st || !sig || !src)
return;
129 dispatch_source_change_(*st, *sig, ch);
139 [[nodiscard]] std::size_t
size()
const {
140 std::shared_lock lk(state_->m);
141 return state_->targets.size();
144 [[nodiscard]]
bool empty()
const {
return size() == 0; }
146 [[nodiscard]] std::shared_ptr<Target>
at(std::size_t idx)
const {
147 std::shared_lock lk(state_->m);
148 return state_->targets.at(idx);
151 [[nodiscard]] std::vector<std::shared_ptr<Target>>
snapshot()
const {
152 std::shared_lock lk(state_->m);
153 return state_->targets;
158 mutable std::shared_mutex m;
160 bool remap_on_change{
false};
161 std::vector<std::shared_ptr<Target>> targets;
164 std::shared_ptr<SourceList> source_;
165 std::shared_ptr<Signal> signal_;
166 std::shared_ptr<SharedState> state_;
167 Subscription source_sub_;
169 static void dispatch_source_change_(SharedState& st,
171 const ListChange<Source>& ch) {
182 static void handle_insert_(SharedState& st,
Signal& sig,
183 const ListChange<Source>& ch) {
184 std::shared_ptr<Target> t;
186 std::unique_lock lk(st.m);
187 const std::size_t idx = ch.index;
188 auto shared_src = ch.item;
189 t = st.mapper(*shared_src);
190 st.targets.insert(st.targets.begin()
191 +
static_cast<std::ptrdiff_t
>(idx), t);
196 static void handle_remove_(SharedState& st,
Signal& sig,
197 const ListChange<Source>& ch) {
198 std::shared_ptr<Target> removed;
200 std::unique_lock lk(st.m);
201 const std::size_t idx = ch.index;
202 if (idx >= st.targets.size())
return;
203 removed = st.targets[idx];
204 st.targets.erase(st.targets.begin()
205 +
static_cast<std::ptrdiff_t
>(idx));
211 static void handle_replace_(SharedState& st,
Signal& sig,
212 const ListChange<Source>& ch) {
213 std::shared_ptr<Target> t;
215 std::unique_lock lk(st.m);
216 const std::size_t idx = ch.index;
217 if (idx >= st.targets.size())
return;
218 auto shared_new = ch.item;
219 t = st.mapper(*shared_new);
228 static void handle_item_changed_(SharedState& st,
Signal& sig,
229 const ListChange<Source>& ch) {
230 std::shared_ptr<Target> t;
232 std::unique_lock lk(st.m);
233 const std::size_t idx = ch.index;
234 if (idx >= st.targets.size())
return;
236 if (st.remap_on_change) {
237 auto shared_new = ch.item;
238 t = st.mapper(*shared_new);
252 static void handle_move_(SharedState& st,
Signal& sig,
253 const ListChange<Source>& ch) {
254 std::shared_ptr<Target> moved;
256 std::unique_lock lk(st.m);
257 const std::size_t from = ch.from_index;
258 const std::size_t to = ch.index;
259 if (from == to)
return;
260 if (from >= st.targets.size() || to >= st.targets.size())
return;
262 moved = st.targets[from];
263 st.targets.erase(st.targets.begin()
264 +
static_cast<std::ptrdiff_t
>(from));
265 st.targets.insert(st.targets.begin()
266 +
static_cast<std::ptrdiff_t
>(to), moved);
269 moved, ch.from_index});
272 static void handle_reset_(SharedState& st,
Signal& sig,
273 const ListChange<Source>& ch) {
274 ListChange<Target> reset;
276 std::unique_lock lk(st.m);
278 const auto& snap = *ch.snapshot;
279 st.targets.reserve(snap.size());
280 for (
const auto& s : snap) {
281 st.targets.push_back(st.mapper(*s));
285 sig.emit(std::move(reset));