File indexing completed on 2026-05-05 08:35:18
0001
0002
0003
0004
0005
0006
0007 #pragma once
0008
0009 #include <algorithm>
0010 #include <string>
0011 #include <unordered_map>
0012 #include <vector>
0013
0014 #include "corecel/Assert.hh"
0015 #include "corecel/io/Label.hh"
0016
0017 #include "Range.hh"
0018 #include "Span.hh"
0019
0020 namespace celeritas
0021 {
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048 template<class I>
0049 class LabelIdMultiMap
0050 {
0051 public:
0052
0053
0054 using IdT = I;
0055 using SpanConstIdT = Span<IdT const>;
0056 using VecLabel = std::vector<Label>;
0057 using size_type = typename IdT::size_type;
0058
0059
0060 public:
0061
0062 LabelIdMultiMap() = default;
0063
0064
0065 inline LabelIdMultiMap(std::string&& label, VecLabel&& keys);
0066
0067
0068 inline explicit LabelIdMultiMap(VecLabel&& keys);
0069
0070
0071 inline SpanConstIdT find_all(std::string const& name) const;
0072
0073
0074 inline IdT find_unique(std::string const& name) const;
0075
0076
0077 inline IdT find_exact(Label const& label) const;
0078
0079
0080 inline Label const& at(IdT id) const;
0081
0082
0083 CELER_FORCEINLINE size_type size() const { return keys_.size(); }
0084
0085
0086 CELER_FORCEINLINE bool empty() const { return keys_.empty(); }
0087
0088
0089 inline explicit operator bool() const;
0090
0091
0092 SpanConstIdT duplicates() const { return make_span(duplicates_); }
0093
0094 private:
0095 std::string type_label_;
0096 VecLabel keys_;
0097 std::vector<IdT> id_data_;
0098 std::vector<size_type> id_offsets_;
0099 std::vector<IdT> duplicates_;
0100 std::unordered_map<std::string, size_type> ids_;
0101 };
0102
0103
0104
0105
0106
0107
0108
0109 template<class I>
0110 LabelIdMultiMap<I>::LabelIdMultiMap(VecLabel&& keys)
0111 : LabelIdMultiMap{{}, std::move(keys)}
0112 {
0113 }
0114
0115
0116
0117
0118
0119 template<class I>
0120 LabelIdMultiMap<I>::LabelIdMultiMap(std::string&& label, VecLabel&& keys)
0121 : type_label_{std::move(label)}, keys_{std::move(keys)}
0122 {
0123 if (keys_.empty())
0124 {
0125
0126
0127 return;
0128 }
0129
0130
0131 id_data_.resize(keys_.size());
0132 for (auto idx : range<size_type>(keys_.size()))
0133 {
0134 id_data_[idx] = IdT{idx};
0135 }
0136
0137 std::sort(id_data_.begin(), id_data_.end(), [&keys = keys_](IdT a, IdT b) {
0138 return keys[a.unchecked_get()] < keys[b.unchecked_get()];
0139 });
0140
0141
0142 id_offsets_.reserve(keys_.size() / 2 + 2);
0143 ids_.reserve(id_offsets_.capacity());
0144
0145
0146 id_offsets_.push_back(0);
0147 ids_.insert({keys_[id_data_[0].unchecked_get()].name, 0});
0148 for (auto idx : range<size_type>(1, id_data_.size()))
0149 {
0150 Label const& prev = keys_[id_data_[idx - 1].unchecked_get()];
0151 Label const& cur = keys_[id_data_[idx].unchecked_get()];
0152 if (prev == cur && !cur.empty())
0153 {
0154 if (duplicates_.empty()
0155 || keys_[duplicates_.back().unchecked_get()] != prev)
0156 {
0157
0158 duplicates_.push_back(id_data_[idx - 1]);
0159 }
0160 duplicates_.push_back(id_data_[idx]);
0161 }
0162 if (prev.name != cur.name)
0163 {
0164
0165 size_type offset_idx = id_offsets_.size();
0166 id_offsets_.push_back(idx);
0167 auto insert_ok = ids_.insert({cur.name, offset_idx});
0168 CELER_ASSERT(insert_ok.second);
0169 }
0170 }
0171 id_offsets_.push_back(id_data_.size());
0172
0173 CELER_ENSURE(keys_.size() == id_data_.size());
0174 CELER_ENSURE(id_offsets_.size() == ids_.size() + 1);
0175 }
0176
0177
0178
0179
0180
0181
0182
0183
0184 template<class I>
0185 auto LabelIdMultiMap<I>::find_all(std::string const& name) const
0186 -> SpanConstIdT
0187 {
0188 auto iter = ids_.find(name);
0189 if (iter == ids_.end())
0190 return {};
0191
0192 size_type offset_idx = iter->second;
0193 CELER_ASSERT(offset_idx + 1 < id_offsets_.size());
0194 size_type start = id_offsets_[offset_idx];
0195 size_type stop = id_offsets_[offset_idx + 1];
0196 CELER_ENSURE(start < stop && stop <= id_data_.size());
0197 return {id_data_.data() + start, stop - start};
0198 }
0199
0200
0201
0202
0203
0204
0205
0206
0207 template<class I>
0208 auto LabelIdMultiMap<I>::find_unique(std::string const& name) const -> IdT
0209 {
0210 auto items = this->find_all(name);
0211 if (items.empty())
0212 return {};
0213 CELER_VALIDATE(items.size() == 1,
0214 << type_label_ << " '" << name << "' is not unique");
0215 return items.front();
0216 }
0217
0218
0219
0220
0221
0222
0223
0224 template<class I>
0225 auto LabelIdMultiMap<I>::find_exact(Label const& label_sub) const -> IdT
0226 {
0227 auto items = this->find_all(label_sub.name);
0228
0229
0230 auto iter = std::find_if(
0231 items.begin(), items.end(), [&keys = keys_, &label_sub](IdT id) {
0232 CELER_EXPECT(id < keys.size());
0233 return keys[id.unchecked_get()].ext == label_sub.ext;
0234 });
0235 if (iter == items.end())
0236 {
0237
0238 return {};
0239 }
0240 CELER_ENSURE(keys_[iter->unchecked_get()] == label_sub);
0241 return *iter;
0242 }
0243
0244
0245
0246
0247
0248
0249
0250 template<class I>
0251 Label const& LabelIdMultiMap<I>::at(IdT id) const
0252 {
0253 CELER_EXPECT(id < this->size());
0254 return keys_[id.unchecked_get()];
0255 }
0256
0257
0258
0259
0260
0261 template<class I>
0262 CELER_FORCEINLINE LabelIdMultiMap<I>::operator bool() const
0263 {
0264 return !keys_.empty() || !type_label_.empty();
0265 }
0266
0267
0268 }