LArSoft  v09_90_00
Liquid Argon Software toolkit - https://larsoft.org/
MappedContainer.h
Go to the documentation of this file.
1 
10 #ifndef LARDATAALG_UTILITIES_MAPPEDCONTAINER_H
11 #define LARDATAALG_UTILITIES_MAPPEDCONTAINER_H
12 
13 // LArSoft libraries
14 #include "larcorealg/CoreUtils/ContainerMeta.h" // util::collection_value_access_t
15 #include "larcorealg/CoreUtils/MetaUtils.h" // util::with_const_as_t
16 
17 // C/C++ standard libraries
18 #include <algorithm> // std::reference_wrapper<>
19 #include <cstddef> // std::size_t
20 #include <iterator> // std::iterator_category, std::size(), ...
21 #include <limits> // std::numeric_limits<>
22 #include <memory> // std::unique_ptr<>
23 #include <stdexcept> // std::out_of_range
24 #include <string> // std::to_string()
25 
26 namespace util {
27 
28  namespace details {
29 
30  // ---------------------------------------------------------------------------
31  template <typename Cont>
33 
34  // ---------------------------------------------------------------------------
35  template <typename Cont, typename = void>
37 
38  // ---------------------------------------------------------------------------
39 
40  } // namespace details
41 
42  // ---------------------------------------------------------------------------
45 
46  template <typename T = std::size_t>
47  static constexpr T invalidIndex()
48  {
49  return std::numeric_limits<T>::max();
50  }
51 
52  }; // struct MappedContainerBase
53 
54  // ---------------------------------------------------------------------------
125  template <typename Cont, typename Mapping>
127 
130 
133 
135  using Value_t = typename Storage_t::value_type;
136 
137  using Size_t = std::size_t;
138 
140 
142 
143  Size_t fSize = 0U;
144 
145  // constantness needs to be removed in order for this object to be copiable
147  std::remove_cv_t<Value_t> fDefValue{};
148 
149  template <typename Container, typename Reference>
151 
152  public:
153  using DataContainer_t = Cont;
154  using Mapping_t = Mapping;
155 
158 
161 
163  using MappingIndex_t = std::size_t;
164 
165  // --- BEGIN -- C++ standard container definitions -------------------------
170 
171  using size_type = std::size_t;
172  using difference_type = std::ptrdiff_t;
173 
177 
178  using iterator = IteratorBase<MappedContainer_t, reference>;
179  using const_iterator = IteratorBase<MappedContainer_t const, const_reference>;
180 
182  // --- END -- C++ standard container definitions ---------------------------
183 
187  static constexpr DataIndex_t InvalidIndex = invalidIndex<DataIndex_t>();
188 
189  // --- BEGIN Constructors --------------------------------------------------
192 
194  MappedContainer() = default;
195 
207  Mapping_t const& mapping,
208  size_type size,
209  value_type defValue)
210  : fData(cont), fMapping(mapping), fSize(size), fDefValue(defValue)
211  {}
212 
223  : MappedContainer(cont, mapping, size, {})
224  {}
225 
236  MappedContainer(DataContainer_t const& cont, Mapping_t const& mapping)
237  : MappedContainer(cont, mapping, minimal_size(cont, mapping))
238  {}
239 
241  // --- END Constructors ----------------------------------------------------
242 
243  // --- BEGIN Container information -----------------------------------------
262 
270  size_type size() const { return fSize; }
271 
279  size_type minimal_size() const;
280 
282  size_type max_size() const { return std::numeric_limits<size_type>::max(); }
283 
285  bool empty() const { return size() == 0U; }
286 
287  // @{
294  reference defaultValue() { return fDefValue; }
295  const_reference defaultValue() const { return fDefValue; }
296  // @}
297 
300  void setDefaultValue(value_type defValue) { fDefValue = defValue; }
301 
303  // --- END Container information -------------------------------------------
304 
305  // --- BEGIN Random access to elements -------------------------------------
308 
309  // @{
318  decltype(auto) operator[](MappingIndex_t index) const { return map_element(index); }
319  decltype(auto) operator[](MappingIndex_t index) { return map_element(index); }
320  // @}
321 
322  // @{
329  decltype(auto) at(MappingIndex_t index) const;
330  decltype(auto) at(MappingIndex_t index);
331  // @}
332 
333  // @{
338  decltype(auto) front() const { return map_element(0U); }
339  decltype(auto) front() { return map_element(0U); }
340  // @}
341 
342  // @{
347  decltype(auto) back() const { return map_element(size() - 1); }
348  decltype(auto) back() { return map_element(size() - 1); }
349  // @}
350 
351  // @{
357  decltype(auto) map_index(MappingIndex_t index) const;
358  decltype(auto) map_index(MappingIndex_t index);
359  // @}
360 
362  // --- END Random access to elements ---------------------------------------
363 
364  // --- BEGIN Iteration -----------------------------------------------------
367 
369  const_iterator cbegin() const { return {*this, 0U}; }
370 
372  const_iterator begin() const { return cbegin(); }
373 
375  iterator begin() { return {*this, 0U}; }
376 
378  const_iterator cend() const { return {*this, size()}; }
379 
381  const_iterator end() const { return cend(); }
382 
384  iterator end() { return {*this, size()}; }
385 
387  // --- END Iteration -------------------------------------------------------
388 
389  protected:
391  static size_type minimal_size(DataContainer_t const& cont, Mapping_t const& mapping);
392 
393  private:
395  decltype(auto) map_element(MappingIndex_t index);
396 
398  decltype(auto) map_element(MappingIndex_t index) const;
399 
400  }; // class MappedContainer<>
401 
402  //----------------------------------------------------------------------------
414  template <typename Cont, typename Mapping>
415  auto mapContainer(Cont cont, Mapping mapping)
416  {
417  return MappedContainer<Cont, Mapping>(cont, mapping);
418  }
419 
420  //----------------------------------------------------------------------------
421 
422 } // namespace util
423 
424 //------------------------------------------------------------------------------
425 //--- template implementation
426 //------------------------------------------------------------------------------
427 namespace util {
428 
429  namespace details {
430 
431  //--------------------------------------------------------------------------
432  template <typename T>
433  T& NullRef()
434  {
435  T* nullTptr = nullptr;
436  return *nullTptr;
437  }
438 
439  //--------------------------------------------------------------------------
440  //--- ContainerStorage
441  //--------------------------------------------------------------------------
442  template <typename Cont>
444 
445  using Container_t = Cont;
447 
448  using index_type = typename Traits_t::size_type;
449 
451  using size_type = typename Traits_t::size_type;
453  using reference = typename Traits_t::reference;
455 
457 
458  ContainerStorageBase() = default;
459  explicit ContainerStorageBase(Container_t const& cont) : fCont(cont) {}
460  explicit ContainerStorageBase(Container_t&& cont) : fCont(std::move(cont)) {}
461 
462  decltype(auto) container() const { return util::collection_from_reference(fCont); }
463  decltype(auto) container() { return util::collection_from_reference(fCont); }
464 
465  auto size() const
466  {
467  using std::size;
468  return size(container());
469  }
470 
471  decltype(auto) operator[](index_type index) { return container()[index]; }
472  decltype(auto) operator[](index_type index) const { return container()[index]; }
473 
474  }; // struct ContainerStorageBase
475 
476  //--------------------------------------------------------------------------
477  template <typename Cont, typename /* = void */>
478  class ContainerStorage : public ContainerStorageBase<Cont> {
479 
481 
482  // inherit all constructors
483  using Base_t::Base_t;
484 
485  }; // struct ContainerStorage
486 
487  template <typename Cont>
488  class ContainerStorage<Cont, std::enable_if_t<util::is_reference_wrapper_v<Cont>>>
489  : public ContainerStorageBase<Cont> {
491  using DataContainer_t = typename Cont::type;
492 
493  public:
494  // inherit all constructors
495  using Base_t::Base_t;
496 
497  // sad hack :-(
498  // calling the inherited constructor with a `reference_wrapper`
499  // (`Base_t::Container_t`) referencing an invalid reference to
500  // the wrapped data type (which is `DataContainer_t`).
501  ContainerStorage() : Base_t(typename Base_t::Container_t{NullRef<DataContainer_t>()}) {}
502 
503  }; // struct ContainerStorage
504 
505  //--------------------------------------------------------------------------
506 
507  } // namespace details
508 
509  //----------------------------------------------------------------------------
510  //--- MappedContainer::IteratorBase
511  //----------------------------------------------------------------------------
512  template <typename Cont, typename Mapping>
513  template <typename Container, typename Reference>
514  class MappedContainer<Cont, Mapping>::IteratorBase {
515 
516  using Container_t = Container;
517  using Reference_t = Reference;
518 
521 
522  Container_t* fCont = nullptr;
523  MappingIndex_t fIndex = InvalidIndex;
524 
525  public:
526  // --- BEGIN Traits --------------------------------------------------------
529 
530  using value_type = std::remove_cv_t<typename Container_t::value_type>;
531  using difference_type = typename Container_t::difference_type;
532  using size_type = typename Container_t::size_type;
534  using pointer = decltype(&std::declval<reference>());
535  using iterator_category = std::input_iterator_tag;
536 
538  // --- END Traits ----------------------------------------------------------
539 
541  IteratorBase() = default;
542 
544  IteratorBase(Container_t& cont, MappingIndex_t index) : fCont(&cont), fIndex(index) {}
545 
547  IteratorBase(Iterator_t const&) = default;
548 
550  template <typename OC, typename OR>
551  IteratorBase(IteratorBase<OC, OR> const& from) : fCont(from.cont), fIndex(from.index)
552  {}
553 
555  Iterator_t& operator=(Iterator_t const&) = default;
556 
558  template <typename OC, typename OR>
560  {
561  fCont = from.fCont;
562  fIndex = from.fIndex;
563  return *this;
564  }
565 
566  // --- BEGIN Dereferencing -------------------------------------------------
570  reference operator*() const { return (*fCont)[fIndex]; }
571 
573  reference operator->() const { return &(operator*(fIndex)); }
574 
577  reference operator[](difference_type n) const { return (*fCont)[fIndex + n]; }
578 
580  // --- END Dereferencing ---------------------------------------------------
581 
582  // --- BEGIN Transformation ------------------------------------------------
587  {
588  ++fIndex;
589  return *this;
590  }
591 
594  {
595  auto it = *this;
596  this->operator++();
597  return it;
598  }
599 
602  {
603  --fIndex;
604  return *this;
605  }
606 
609  {
610  auto it = *this;
611  this->operator--();
612  return it;
613  }
614 
617  {
618  fIndex += n;
619  return *this;
620  }
621 
624  {
625  fIndex -= n;
626  return *this;
627  }
628 
631  {
632  auto it = *this;
633  it += n;
634  return it;
635  }
636 
639  {
640  auto it = *this;
641  it -= n;
642  return it;
643  }
644 
646  difference_type operator-(Iterator_t& other) const { return fIndex - other.fIndex; }
647 
649  // --- END Transformation --------------------------------------------------
650 
651  // --- BEGIN Comparisons ---------------------------------------------------
655  template <typename OC, typename OR>
657  {
658  return (fCont == other.fCont) && (fIndex == other.fIndex);
659  }
660 
662  template <typename OC, typename OR>
664  {
665  return (fCont != other.fCont) || (fIndex != other.fIndex);
666  }
667 
669  template <typename OC, typename OR>
670  bool operator<=(IteratorBase<OC, OR> const& other) const
671  {
672  return (fCont == other.fCont) && (fIndex <= other.fIndex);
673  }
674 
676  template <typename OC, typename OR>
677  bool operator<(IteratorBase<OC, OR> const& other) const
678  {
679  return (fCont == other.fCont) && (fIndex < other.fIndex);
680  }
681 
683  template <typename OC, typename OR>
685  {
686  return (fCont == other.fCont) && (fIndex >= other.fIndex);
687  }
688 
690  template <typename OC, typename OR>
692  {
693  return (fCont == other.fCont) && (fIndex > other.fIndex);
694  }
695 
697  // --- END Comparisons -----------------------------------------------------
698 
699  }; // IteratorBase
700 
701  // it hurts the eye
702  template <typename Cont, typename Mapping, typename Container, typename Reference>
703  typename MappedContainer<Cont, Mapping>::template IteratorBase<Container, Reference> operator+(
704  typename MappedContainer<Cont, Mapping>::template IteratorBase<Container,
705  Reference>::difference_type n,
706  typename MappedContainer<Cont, Mapping>::template IteratorBase<Container, Reference> const& it)
707  {
708  return it + n;
709  }
710 
711 } // namespace util
712 
713 namespace util::details {
714 
715  //----------------------------------------------------------------------------
716  template <typename Cont>
718  using value_type = typename Cont::value_type;
719  using difference_type = typename Cont::difference_type;
720  using size_type = typename Cont::size_type;
721  using const_reference = typename Cont::const_reference;
722  using reference = typename Cont::reference;
724  using iterator = typename Cont::iterator;
725  }; // ContainerTraitsImpl<>
726 
727  template <typename T>
728  struct ContainerTraitsImpl<T*> {
729  using value_type = T; // should it be devoid of const/mutable?
730  using difference_type = std::ptrdiff_t;
731  using size_type = std::size_t;
732  using const_reference = T const&;
733  using reference = T&;
734  using const_iterator = T const*;
735  using iterator = T*;
736  }; // ContainerTraitsImpl<T*>
737 
738  // this is not as powerful as it should... hoping users do not nest
739  // crazily `unique_ptr`, `reference_wrapper` and such
740  template <typename Cont>
741  struct ContainerTraits
742  : ContainerTraitsImpl<std::remove_reference_t<
743  util::collection_from_reference_t<util::strip_referenceness_t<Cont>>>> {};
744 
745  //----------------------------------------------------------------------------
746 
747 } // namespace util::details
748 
749 //------------------------------------------------------------------------------
750 //--- util::MappedContainer
751 //------------------------------------------------------------------------------
752 template <typename Cont, typename Mapping>
754 {
755  return minimal_size(fData.container(), fMapping.container());
756 }
757 
758 //------------------------------------------------------------------------------
759 template <typename Cont, typename Mapping>
761 {
762  auto const dataIndex = map_index(index);
763  return (dataIndex == InvalidIndex) ? defaultValue() : fData[dataIndex];
764 } // util::MappedContainer<>::map_element() const
765 
766 //------------------------------------------------------------------------------
767 template <typename Cont, typename Mapping>
769 {
770  auto const dataIndex = map_index(index);
771  return (dataIndex == InvalidIndex) ? defaultValue() : fData[dataIndex];
772 } // util::MappedContainer<>::map_element()
773 
774 //------------------------------------------------------------------------------
775 template <typename Cont, typename Mapping>
777 {
778  if (index >= size()) {
779  throw std::out_of_range("MappedContainer::at(" + std::to_string(index) +
780  "): out of range (size: " + std::to_string(size()) + ")");
781  }
782  return map_element(index);
783 } // util::MappedContainer<>::at() const
784 
785 //------------------------------------------------------------------------------
786 template <typename Cont, typename Mapping>
788 {
789  if (index >= size()) {
790  throw std::out_of_range("MappedContainer::at(" + std::to_string(index) +
791  "): out of range (size: " + std::to_string(size()) + ")");
792  }
793  return map_element(index);
794 } // util::MappedContainer<>::at()
795 
796 //------------------------------------------------------------------------------
797 template <typename Cont, typename Mapping>
799  Mapping_t const& mapping) -> size_type
800 {
801  /*
802  * Obscure compiler errors are expected if the `Mapping_t` type does not
803  * support `std::size`. In that case, very simply, `minimal_size()` can't be
804  * used and the caller must specify the size of the container.
805  */
806 
807  using std::size;
808  return size(util::collection_from_reference(mapping));
809 } // util::MappedContainer<>::minimal_size(DataContainer_t, Mapping_t)
810 
811 //------------------------------------------------------------------------------
812 template <typename Cont, typename Mapping>
814 {
815  return fMapping[index];
816 }
817 
818 //------------------------------------------------------------------------------
819 template <typename Cont, typename Mapping>
821 {
822  return fMapping[index];
823 }
824 
825 //------------------------------------------------------------------------------
826 
827 #endif // LARDATAALG_UTILITIES_MAPPEDCONTAINER_H
MappedContainer< Cont, Mapping >::template IteratorBase< Container, Reference > operator+(typename MappedContainer< Cont, Mapping >::template IteratorBase< Container, Reference >::difference_type n, typename MappedContainer< Cont, Mapping >::template IteratorBase< Container, Reference > const &it)
intermediate_table::iterator iterator
auto mapContainer(Cont cont, Mapping mapping)
Returns a container-like object mapping the content of cont.
Iterator_t & operator=(IteratorBase< OC, OR > const &from)
Assignment from a different container type.
typename collection_value_access_type< Coll >::type collection_value_access_t
Type obtained by constant access to element of collection Coll.
Definition: ContainerMeta.h:71
Namespace for general, non-LArSoft-specific utilities.
Definition: PIDAAlg.h:26
typename Storage_t::value_type Value_t
Type of contained value.
IteratorBase(IteratorBase< OC, OR > const &from)
Copy constructor: from a different container type.
MappingIndex_t fIndex
Current index in container.
typename std::remove_reference_t< util::collection_from_reference_t< util::strip_referenceness_t< Cont > > >::iterator iterator
decltype(auto) constexpr cend(T &&obj)
ADL-aware version of std::cend.
Definition: StdUtils.h:93
A meta-container providing transparent mapping on top of another.
Basic C++ metaprogramming utilities.
bool operator==(IteratorBase< OC, OR > const &other) const
Returns whether this iterator is not equal to other.
Iterator_t & operator+=(difference_type n)
Increments this iterator by n steps and returns it incremented.
Iterator_t & operator--()
Decrements this iterator and returns it decremented.
const_reference defaultValue() const
Returns the nominal size of the container (after mapping).
size_type minimal_size() const
Returns the minimum size to include all mapped values.
std::size_t MappingIndex_t
Type of the index passed to the mapping.
typename std::remove_reference_t< util::collection_from_reference_t< util::strip_referenceness_t< Cont > > >::size_type size_type
reference operator*() const
Returns a member of the mapped item the iterator currently points to.
typename std::remove_reference_t< util::collection_from_reference_t< util::strip_referenceness_t< Cont > > >::reference reference
typename std::remove_reference_t< util::collection_from_reference_t< util::strip_referenceness_t< Cont > > >::const_reference const_reference
reference operator[](difference_type n) const
ContainerStorageBase(Container_t const &cont)
const_iterator cbegin() const
Returns a constant iterator to the first mapped element.
Iterator_t & operator-=(difference_type n)
Decrements this iterator by n steps and returns it decremented.
STL namespace.
typename with_const_as< Base, Key >::type with_const_as_t
The type Base, plus the constantness as in Key.
Definition: MetaUtils.h:515
util::with_const_as_t< typename Storage_t::reference, util::collection_value_access_t< DataContainer_t >> reference
size_type size() const
Returns the nominal size of the container (after mapping).
std::remove_cv_t< typename Container_t::value_type > value_type
intermediate_table::const_iterator const_iterator
Iterator_t operator++(int)
Increments this iterator and returns its old value.
Iterator_t operator--(int)
Decrements this iterator and returns its old value.
const_iterator begin() const
Returns a constant iterator to the first mapped element.
MappedContainer(DataContainer_t const &cont, Mapping_t const &mapping, size_type size)
Constructor: acquires data and mapping.
static constexpr T invalidIndex()
Non-template base class for MappedContainer.
typename Container_t::size_type size_type
void setDefaultValue(value_type defValue)
IteratorBase(Container_t &cont, MappingIndex_t index)
Constructor: iterator pointing to element index of cont.
ContainerStorageBase(Container_t &&cont)
decltype(auto) constexpr size(T &&obj)
ADL-aware version of std::size.
Definition: StdUtils.h:101
difference_type operator-(Iterator_t &other) const
Returns the number of steps this iterator is ahead of other.
Iterator_t operator+(difference_type n) const
Returns an iterator pointing n steps ahead of this one.
iterator end()
Returns an iterator past the last mapped element.
decltype(auto) constexpr to_string(T &&obj)
ADL-aware version of std::to_string.
Iterator_t & operator++()
Increments this iterator and returns its old value.
decltype(auto) map_index(MappingIndex_t index) const
Returns the index in the original data which is mapped to index.
typename std::remove_reference_t< util::collection_from_reference_t< util::strip_referenceness_t< Cont > > >::difference_type difference_type
typename Container_t::difference_type difference_type
bool operator>=(IteratorBase< OC, OR > const &other) const
Returns whether this iterator is ahead of or equal to other.
phot::IPhotonLibrary::T0s_t DataContainer_t
Type of the original container.
const_iterator cend() const
Returns a constant iterator past the last mapped element.
decltype(auto) map_element(MappingIndex_t index)
Returns the value mapped to the specified index.
bool operator!=(IteratorBase< OC, OR > const &other) const
Returns whether this iterator is not equal to other.
decltype(&std::declval< reference >()) pointer
IteratorBase< MappedContainer_t const, const_reference > const_iterator
iterator begin()
Returns an iterator to the first mapped element.
MappingStorage_t fMapping
Mapping of stored data into final one.
typename std::remove_reference_t< util::collection_from_reference_t< util::strip_referenceness_t< Cont > > >::value_type value_type
MappedContainer(DataContainer_t const &cont, Mapping_t const &mapping)
Constructor: acquires data and mapping.
const_iterator end() const
Returns a constant iterator past the last mapped element.
typename std::remove_reference_t< util::collection_from_reference_t< util::strip_referenceness_t< Cont > > >::const_iterator const_iterator
util::collection_value_t< Mapping_t > DataIndex_t
Type of the index passed to the original container.
size_type max_size() const
Returns the size of the largest possible container of this type.
Container_t * fCont
Pointer to the container.
bool empty() const
Returns whether the container has no elements.
std::input_iterator_tag iterator_category
Iterator_t operator-(difference_type n) const
Returns an iterator pointing n steps behind this one.
decltype(auto) constexpr cbegin(T &&obj)
ADL-aware version of std::cbegin.
Definition: StdUtils.h:85
Storage_t fData
Data to be mapped.
decltype(auto) at(MappingIndex_t index) const
Returns the content corresponding to the specified index.
Char_t n[5]
reference defaultValue()
Returns the default value for elements with no original content.
typename collection_value_type< Coll >::type collection_value_t
Type contained in the collection Coll.
Definition: ContainerMeta.h:62
MappedContainer(DataContainer_t const &cont, Mapping_t const &mapping, size_type size, value_type defValue)
Constructor: acquires data, mapping and a default value.
decltype(auto) collection_from_reference(CollRef &collRef)
Returns the object referenced by collRef as a C++ reference.
C++ metaprogramming utilities for dealing with containers.
QuadExpr operator*(double v, const QuadExpr &e)
Definition: QuadExpr.h:44
bool operator>(IteratorBase< OC, OR > const &other) const
Returns whether this iterator is strictly ahead of other.
reference operator->() const
Returns a member of the mapped item the iterator currently points to.
typename Traits_t::difference_type difference_type
std::size_t Size_t
Type for describing container size.