Back to home page

EIC code displayed by LXR

 
 

    


Warning, file /include/corecel/data/DedupeCollectionBuilder.hh was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

0001 //------------------------------- -*- C++ -*- -------------------------------//
0002 // Copyright Celeritas contributors: see top-level COPYRIGHT file for details
0003 // SPDX-License-Identifier: (Apache-2.0 OR MIT)
0004 //---------------------------------------------------------------------------//
0005 //! \file corecel/data/DedupeCollectionBuilder.hh
0006 //---------------------------------------------------------------------------//
0007 #pragma once
0008 
0009 #include <algorithm>
0010 #include <cstddef>
0011 #include <unordered_set>
0012 
0013 #include "corecel/math/HashUtils.hh"
0014 
0015 #include "Collection.hh"
0016 
0017 namespace celeritas
0018 {
0019 //---------------------------------------------------------------------------//
0020 /*!
0021  * Build collections, returning the same ID for reused data spans.
0022  */
0023 template<class T, class I = ItemId<T>>
0024 class DedupeCollectionBuilder
0025 {
0026   public:
0027     //!@{
0028     //! \name Type aliases
0029     using CollectionT = Collection<T, Ownership::value, MemSpace::host, I>;
0030     using value_type = T;
0031     using size_type = typename CollectionT::size_type;
0032     using ItemIdT = typename CollectionT::ItemIdT;
0033     using ItemRangeT = typename CollectionT::ItemRangeT;
0034     //!@}
0035 
0036   public:
0037     // Construct from a collection
0038     explicit DedupeCollectionBuilder(CollectionT* collection);
0039 
0040     //// ACCESSORS ////
0041 
0042     //! Number of elements in the collection
0043     size_type size() const { return this->storage().size(); }
0044 
0045     //! Get the size as an ID type
0046     ItemIdT size_id() const { return ItemIdT{this->size()}; }
0047 
0048     //// MUTATORS ////
0049 
0050     // Reserve space and hash table space
0051     inline void reserve(std::size_t count);
0052 
0053     // Extend with a series of elements, returning the range inserted
0054     template<class InputIterator>
0055     inline ItemRangeT insert_back(InputIterator first, InputIterator last);
0056 
0057     // Extend with a series of elements from an initializer list
0058     inline ItemRangeT insert_back(std::initializer_list<value_type> init);
0059 
0060     // Append a single element
0061     inline ItemIdT push_back(value_type const& element);
0062 
0063   private:
0064     //// CLASSES ////
0065 
0066     using StorageT = typename CollectionT::StorageT;
0067 
0068     struct HashRange
0069     {
0070         StorageT* storage{nullptr};
0071         std::size_t operator()(ItemRangeT) const;
0072     };
0073     struct EqualRange
0074     {
0075         StorageT* storage{nullptr};
0076         bool operator()(ItemRangeT const&, ItemRangeT const&) const;
0077     };
0078 
0079     //// DATA ////
0080 
0081     CollectionT* col_;
0082     std::unordered_set<ItemRangeT, HashRange, EqualRange> ranges_;
0083 
0084     //// FUNCTIONS ////
0085 
0086     //!@{
0087     //! Access storage
0088     CELER_FORCEINLINE StorageT& storage() { return col_->storage(); }
0089     CELER_FORCEINLINE StorageT const& storage() const
0090     {
0091         return col_->storage();
0092     }
0093     //!@}
0094 };
0095 
0096 //---------------------------------------------------------------------------//
0097 // INLINE DEFINITIONS
0098 //---------------------------------------------------------------------------//
0099 /*!
0100  * Construct from a collection.
0101  */
0102 template<class T, class I>
0103 DedupeCollectionBuilder<T, I>::DedupeCollectionBuilder(CollectionT* collection)
0104     : col_{collection}
0105     , ranges_{0, HashRange{&this->storage()}, EqualRange{&this->storage()}}
0106 {
0107     CELER_EXPECT(col_);
0108 }
0109 
0110 //---------------------------------------------------------------------------//
0111 /*!
0112  * Reserve space for elements.
0113  */
0114 template<class T, class I>
0115 void DedupeCollectionBuilder<T, I>::reserve(std::size_t count)
0116 {
0117     this->storage().reserve(count);
0118     ranges_.reserve(count);
0119 }
0120 
0121 //---------------------------------------------------------------------------//
0122 /*!
0123  * Insert the given list of elements at the end of the allocation.
0124  */
0125 template<class T, class I>
0126 template<class InputIterator>
0127 auto DedupeCollectionBuilder<T, I>::insert_back(InputIterator first,
0128                                                 InputIterator last) -> ItemRangeT
0129 {
0130     auto& s = this->storage();
0131 
0132     auto start = this->size_id();
0133     s.insert(s.end(), first, last);
0134     ItemRangeT result{start, this->size_id()};
0135     auto [iter, inserted] = ranges_.insert(result);
0136     if (!inserted)
0137     {
0138         // Roll back the change by erasing the last elements
0139         s.erase(s.begin() + start.unchecked_get(), s.end());
0140         // Return existing range
0141         return *iter;
0142     }
0143     return result;
0144 }
0145 
0146 //---------------------------------------------------------------------------//
0147 /*!
0148  * Insert the given list of elements at the end of the allocation.
0149  */
0150 template<class T, class I>
0151 auto DedupeCollectionBuilder<T, I>::insert_back(std::initializer_list<T> init)
0152     -> ItemRangeT
0153 {
0154     return this->insert_back(init.begin(), init.end());
0155 }
0156 
0157 //---------------------------------------------------------------------------//
0158 /*!
0159  * Add a new element to the end of the allocation.
0160  */
0161 template<class T, class I>
0162 auto DedupeCollectionBuilder<T, I>::push_back(T const& el) -> ItemIdT
0163 {
0164     auto result = this->size_id();
0165     this->storage().push_back(el);
0166     return result;
0167 }
0168 
0169 //---------------------------------------------------------------------------//
0170 // NESTED CLASSES
0171 //---------------------------------------------------------------------------//
0172 /*!
0173  * Compute a hash of the data underlying a range.
0174  *
0175  * By default, this uses the std::hash specialization in \c HashUtils.
0176  */
0177 template<class T, class I>
0178 std::size_t
0179 DedupeCollectionBuilder<T, I>::HashRange::operator()(ItemRangeT r) const
0180 {
0181     CELER_EXPECT(*r.end() <= storage->size());
0182 
0183     // Hash data pointed to by range
0184     Span<T const> data{storage->data() + r.begin()->unchecked_get(), r.size()};
0185     return std::hash<decltype(data)>{}(data);
0186 }
0187 
0188 //---------------------------------------------------------------------------//
0189 /*!
0190  * Compare as equal the data referenced by two ranges.
0191  */
0192 template<class T, class I>
0193 bool DedupeCollectionBuilder<T, I>::EqualRange::operator()(
0194     ItemRangeT const& a, ItemRangeT const& b) const
0195 {
0196     CELER_EXPECT(*a.end() <= storage->size());
0197     CELER_EXPECT(*b.end() <= storage->size());
0198 
0199     auto values_equal = [&s = *storage](ItemIdT left, ItemIdT right) {
0200         return s[left.unchecked_get()] == s[right.unchecked_get()];
0201     };
0202     return std::equal(a.begin(), a.end(), b.begin(), b.end(), values_equal);
0203 }
0204 
0205 //---------------------------------------------------------------------------//
0206 }  // namespace celeritas