AliceVision
Photogrammetric Computer Vision Framework
SharedPtrMap.hpp
1 // This file is part of the AliceVision project.
2 // Copyright (c) 2025 AliceVision contributors.
3 // This Source Code Form is subject to the terms of the Mozilla Public License,
4 // v. 2.0. If a copy of the MPL was not distributed with this file,
5 // You can obtain one at https://mozilla.org/MPL/2.0/.
6 
7 #pragma once
8 
9 #include <map>
10 #include <memory>
11 #include <aliceVision/types.hpp>
12 #include <iterator>
13 #include <tuple>
14 
15 namespace aliceVision {
16 namespace sfmData {
17 
18 template <class T, bool IsConstant>
19 struct MapTraits
20 {
21  using mapType = std::map<IndexT, std::shared_ptr<T>>;
22  using baseIterator = std::conditional_t<IsConstant,
23  typename mapType::const_iterator,
24  typename mapType::iterator>;
25 
26  using keyType = const IndexT;
27  using valueType = std::conditional_t<IsConstant, const T, T>;
28  using pairType = std::conditional_t<IsConstant,
29  const std::pair<const IndexT, T>,
30  std::pair<const IndexT, T>>;
31 };
32 
37 template <class T, bool IsConstant>
38 class ProxyPair
39 {
40 public:
42 public:
43  explicit ProxyPair(Traits::baseIterator it)
44  : _it(it)
45  {
46  }
47 
48  Traits::baseIterator getIterator() const
49  {
50  return _it;
51  }
52 
53  Traits::keyType & first() const
54  {
55  return _it->first;
56  }
57 
58  Traits::valueType & second() const
59  {
60  return *(_it->second);
61  }
62 
63  #ifndef SWIG
64  template<std::size_t I>
65  decltype(auto) get() const
66  {
67  if constexpr (I == 0)
68  {
69  return first();
70  }
71  else if constexpr (I == 1)
72  {
73  return second();
74  }
75  else
76  {
77  static_assert(I < 2, "Index out of bounds");
78  return first();
79  }
80  }
81  #endif
82 
83 private:
84  Traits::baseIterator _it;
85 };
86 
92 template <class T, bool IsConstant>
94 {
95 public:
97  using iterator_category = std::forward_iterator_tag;
98  using value_type = Traits::pairType;
99  using difference_type = ptrdiff_t;
100  using pointer = void;
102 
103 public:
104 
105  ValueIteratorT(Traits::baseIterator current, Traits::baseIterator end)
106  : _current(current), _end(end), _pair(current)
107  {
108  nextWhileInvalid();
109  }
110 
111  reference & operator*()
112  {
113  return _pair;
114  }
115 
116  ValueIteratorT& operator++() {
117 
118  ++_current;
119  nextWhileInvalid();
120  return *this;
121  }
122 
123  ValueIteratorT operator++(int) {
124  ValueIteratorT tmp = *this;
125  ++(*this);
126  return tmp;
127  }
128 
129  bool operator==(const ValueIteratorT & other) const
130  {
131  return _current == other._current;
132  }
133 
134  bool operator!=(const ValueIteratorT & other) const
135  {
136  return !(*this == other);
137  }
138 
139  const std::pair<const IndexT, std::shared_ptr<T>>& raw() const {
140  return *_current;
141  }
142 
143  Traits::baseIterator baseIterator() const
144  {
145  return _current;
146  }
147 
148 private:
149  void nextWhileInvalid()
150  {
151  while (_current != _end)
152  {
153  if (_current->second != nullptr)
154  {
155  break;
156  }
157 
158  ++_current;
159  }
160 
161  if (_current != _end)
162  {
163  _pair = ProxyPair<T, IsConstant>(_current);
164  }
165  }
166 
167 private:
168  Traits::baseIterator _current;
169  Traits::baseIterator _end;
170  reference _pair;
171 };
172 
173 
177 template <typename T, bool IsConstant>
179 {
180 public:
182 
183 public:
184  RangeValueT(Traits::baseIterator begin_, Traits::baseIterator end_)
185  : _begin(begin_), _end(end_)
186  {
187 
188  }
189 
191  {
192  return ValueIteratorT<T, IsConstant>(_begin, _end);
193  }
194 
196  {
197  return ValueIteratorT<T, IsConstant>(_end, _end);
198  }
199 
200 private:
201  Traits::baseIterator _begin;
202  Traits::baseIterator _end;
203 };
204 
205 
209 template <typename T, bool IsConstant>
211 {
212 public:
214 
215 public:
216  RangeBaseT(Traits::baseIterator begin_, Traits::baseIterator end_)
217  : _begin(begin_), _end(end_)
218  {
219 
220  }
221 
222  Traits::baseIterator begin()
223  {
224  return _begin;
225  }
226 
227  Traits::baseIterator end()
228  {
229  return _end;
230  }
231 
232 private:
233  Traits::baseIterator _begin;
234  Traits::baseIterator _end;
235 };
236 
242 template <class T, bool ForceValueIterator = false>
243 class SharedPtrMap : public std::map<IndexT, std::shared_ptr<T>>
244 {
245 public:
246  using mapType = std::map<IndexT, std::shared_ptr<T>>;
253 
254 public:
255  SharedPtrMap() : mapType() {};
256 
257  SharedPtrMap(const SharedPtrMap & other) : mapType()
258  {
259  //Clone the shared_ptr content instead of shallow copy
260  for (const auto & [key, value] : other.baseRange())
261  {
262  this->emplace(key, value->clone());
263  }
264  }
265 
266  SharedPtrMap<T> & operator=(const SharedPtrMap<T> &other)
267  {
268  if (this == &other)
269  {
270  return *this;
271  }
272 
273  //Assign by copy
274  SharedPtrMap<T> tmp(other);
275  tmp.swap(*this);
276 
277  return *this;
278  }
279 
280  bool operator!=(const SharedPtrMap<T> & other) const
281  {
282  return !(*this == other);
283  }
284 
285  bool operator==(const SharedPtrMap<T> & other) const
286  {
287  //Check same size
288  if (this->size() != other.size())
289  {
290  return false;
291  }
292 
293  //Compare all items
294  for (const auto & [key, value]: other)
295  {
296  //Check that we have an item with same key
297  const auto it = this->mapType::find(key);
298  if (it == this->mapType::end())
299  {
300  return false;
301  }
302 
303  //If both have nullptr, then it's ok, no need to compare values
304  const auto sptr = it->second;
305  if (sptr == nullptr && value == nullptr)
306  {
307  continue;
308  }
309 
310  //Error if one has nullptr
311  if (sptr == nullptr || value == nullptr)
312  {
313  return false;
314  }
315 
316  //Compare values
317  if (!((*sptr) == (*value)))
318  {
319  return false;
320  }
321  }
322 
323  return true;
324  }
325 
326  bool isValid(const IndexT &key) const
327  {
328  //Check that the key exists
329  auto it = this->mapType::find(key);
330  if (it == this->mapType::end())
331  {
332  return false;
333  }
334 
335  //Check that the value is the same
336  return (it->second != nullptr);
337  }
338 
339  #ifndef SWIG
340  void assign(const IndexT & key, const T & value)
341  {
342  std::shared_ptr<T> ptr;
343 
344  //Does the key exists ? If it exists, retrieve the pointer
345  auto it = this->mapType::find(key);
346  if (it != this->mapType::end())
347  {
348  ptr = it->second;
349  }
350 
351  if (ptr == nullptr)
352  {
353  ptr = std::make_shared<T>(value);
354  this->insert_or_assign(key, ptr);
355  }
356  else
357  {
358  *ptr = value;
359  }
360  }
361  #endif
362 
363  ConstRangeValue valueRange() const
364  {
365  return ConstRangeValue(mapType::begin(), mapType::end());
366  }
367 
368  RangeValue valueRange()
369  {
370  return RangeValue(mapType::begin(), mapType::end());
371  }
372 
373  ConstRangeBase baseRange() const
374  {
375  return ConstRangeBase(mapType::begin(), mapType::end());
376  }
377 
378  RangeBase baseRange()
379  {
380  return RangeBase(mapType::begin(), mapType::end());
381  }
382 
383  //Delete operators [] as we don't want to create on the fly
384  T & operator[] (const IndexT& index)
385  {
386  std::shared_ptr<T> ptr;
387 
388  //Does the key exists ? If it exists, retrieve the pointer
389  auto it = this->mapType::find(index);
390  if (it != this->mapType::end())
391  {
392  ptr = it->second;
393  }
394 
395  if (ptr == nullptr)
396  {
397  ptr = std::make_shared<T>();
398  this->insert_or_assign(index, ptr);
399  }
400 
401  return *ptr;
402  }
403 
404  T & operator[] (IndexT&& index)
405  {
406  std::shared_ptr<T> ptr;
407 
408  //Does the key exists ? If it exists, retrieve the pointer
409  auto it = this->mapType::find(index);
410  if (it != this->mapType::end())
411  {
412  ptr = it->second;
413  }
414 
415  if (ptr == nullptr)
416  {
417  ptr = std::make_shared<T>();
418  this->insert_or_assign(index, ptr);
419  }
420 
421  return *ptr;
422  }
423 
424  auto begin()
425  {
426  if constexpr (ForceValueIterator)
427  {
428  return ValueIteratorT<T, false>(mapType::begin(), mapType::end());
429  }
430  else
431  {
432  return mapType::begin();
433  }
434  }
435 
436  auto end()
437  {
438  if constexpr (ForceValueIterator)
439  {
440  return ValueIteratorT<T, false>(mapType::end(), mapType::end());
441  }
442  else
443  {
444  return mapType::end();
445  }
446  }
447 
448  auto begin() const
449  {
450  if constexpr (ForceValueIterator)
451  {
452  return ValueIteratorT<T, true>(mapType::begin(), mapType::end());
453  }
454  else
455  {
456  return mapType::begin();
457  }
458  }
459 
460  auto end() const
461  {
462  if constexpr (ForceValueIterator)
463  {
464  return ValueIteratorT<T, true>(mapType::end(), mapType::end());
465  }
466  else
467  {
468  return mapType::end();
469  }
470  }
471 
472  auto find(IndexT index)
473  {
474  if constexpr (ForceValueIterator)
475  {
476  return ValueIteratorT<T, false>(mapType::find(index), mapType::end());
477  }
478  else
479  {
480  return mapType::find(index);
481  }
482  }
483 
484  auto find(IndexT index) const
485  {
486  if constexpr (ForceValueIterator)
487  {
488  return ValueIteratorT<T, true>(mapType::find(index), mapType::end());
489  }
490  else
491  {
492  return mapType::find(index);
493  }
494  }
495 
496  std::vector<IndexT> getKeys() const
497  {
498  std::vector<IndexT> keys;
499  for (const auto& pair : *this)
500  {
501  keys.push_back(pair.first);
502  }
503 
504  return keys;
505  }
506 
507  std::vector<std::shared_ptr<T>> getValues() const
508  {
509  std::vector<std::shared_ptr<T>> values;
510  for (const auto& pair : *this)
511  {
512  values.push_back(pair.second);
513  }
514 
515  return values;
516  }
517 };
518 
519 } // namespace sfmData
520 } // namespace aliceVision
521 
522 namespace std
523 {
524 
525 template <class T, bool IsConstant>
526 struct tuple_size<aliceVision::sfmData::ProxyPair<T, IsConstant>> :
527 std::integral_constant<std::size_t, 2> {};
528 
529 template<class T, bool IsConstant>
530 struct tuple_element<0, aliceVision::sfmData::ProxyPair<T, IsConstant>> {
531  using type = aliceVision::sfmData::MapTraits<T, IsConstant>::keyType&;
532 };
533 
534 template<class T, bool IsConstant>
535 struct tuple_element<1, aliceVision::sfmData::ProxyPair<T, IsConstant>> {
536  using type = aliceVision::sfmData::MapTraits<T, IsConstant>::valueType&;
537 };
538 
539 
540 
541 }
542 
aliceVision::sfmData::RangeValueT
Definition: SharedPtrMap.hpp:178
aliceVision::sfmData::RangeBaseT
Definition: SharedPtrMap.hpp:210
aliceVision
Definition: checkerDetector.cpp:32
aliceVision::sfmData::SharedPtrMap
Definition: SharedPtrMap.hpp:243
aliceVision::sfmData::ProxyPair
Definition: SharedPtrMap.hpp:38
aliceVision::sfmData::MapTraits
Definition: SharedPtrMap.hpp:19
aliceVision::sfmData::ValueIteratorT
Definition: SharedPtrMap.hpp:93