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
0002
0003
0004
0005
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
0022
0023 template<class T, class I = ItemId<T>>
0024 class DedupeCollectionBuilder
0025 {
0026 public:
0027
0028
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
0038 explicit DedupeCollectionBuilder(CollectionT* collection);
0039
0040
0041
0042
0043 size_type size() const { return this->storage().size(); }
0044
0045
0046 ItemIdT size_id() const { return ItemIdT{this->size()}; }
0047
0048
0049
0050
0051 inline void reserve(std::size_t count);
0052
0053
0054 template<class InputIterator>
0055 inline ItemRangeT insert_back(InputIterator first, InputIterator last);
0056
0057
0058 inline ItemRangeT insert_back(std::initializer_list<value_type> init);
0059
0060
0061 inline ItemIdT push_back(value_type const& element);
0062
0063 private:
0064
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
0080
0081 CollectionT* col_;
0082 std::unordered_set<ItemRangeT, HashRange, EqualRange> ranges_;
0083
0084
0085
0086
0087
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
0098
0099
0100
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
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
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
0139 s.erase(s.begin() + start.unchecked_get(), s.end());
0140
0141 return *iter;
0142 }
0143 return result;
0144 }
0145
0146
0147
0148
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
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
0171
0172
0173
0174
0175
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
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
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 }