File indexing completed on 2025-09-15 08:55:03
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 inline explicit operator bool() const;
0087
0088
0089 SpanConstIdT duplicates() const { return make_span(duplicates_); }
0090
0091 private:
0092 std::string type_label_;
0093 VecLabel keys_;
0094 std::vector<IdT> id_data_;
0095 std::vector<size_type> id_offsets_;
0096 std::vector<IdT> duplicates_;
0097 std::unordered_map<std::string, size_type> ids_;
0098 };
0099
0100
0101
0102
0103
0104
0105
0106 template<class I>
0107 LabelIdMultiMap<I>::LabelIdMultiMap(VecLabel&& keys)
0108 : LabelIdMultiMap{{}, std::move(keys)}
0109 {
0110 }
0111
0112
0113
0114
0115
0116 template<class I>
0117 LabelIdMultiMap<I>::LabelIdMultiMap(std::string&& label, VecLabel&& keys)
0118 : type_label_{std::move(label)}, keys_{std::move(keys)}
0119 {
0120 if (keys_.empty())
0121 {
0122
0123
0124 return;
0125 }
0126
0127
0128 id_data_.resize(keys_.size());
0129 for (auto idx : range<size_type>(keys_.size()))
0130 {
0131 id_data_[idx] = IdT{idx};
0132 }
0133
0134 std::sort(id_data_.begin(), id_data_.end(), [&keys = keys_](IdT a, IdT b) {
0135 return keys[a.unchecked_get()] < keys[b.unchecked_get()];
0136 });
0137
0138
0139 id_offsets_.reserve(keys_.size() / 2 + 2);
0140 ids_.reserve(id_offsets_.capacity());
0141
0142
0143 id_offsets_.push_back(0);
0144 ids_.insert({keys_[id_data_[0].unchecked_get()].name, 0});
0145 for (auto idx : range<size_type>(1, id_data_.size()))
0146 {
0147 Label const& prev = keys_[id_data_[idx - 1].unchecked_get()];
0148 Label const& cur = keys_[id_data_[idx].unchecked_get()];
0149 if (prev == cur && !cur.empty())
0150 {
0151 if (duplicates_.empty()
0152 || keys_[duplicates_.back().unchecked_get()] != prev)
0153 {
0154
0155 duplicates_.push_back(id_data_[idx - 1]);
0156 }
0157 duplicates_.push_back(id_data_[idx]);
0158 }
0159 if (prev.name != cur.name)
0160 {
0161
0162 size_type offset_idx = id_offsets_.size();
0163 id_offsets_.push_back(idx);
0164 auto insert_ok = ids_.insert({cur.name, offset_idx});
0165 CELER_ASSERT(insert_ok.second);
0166 }
0167 }
0168 id_offsets_.push_back(id_data_.size());
0169
0170 CELER_ENSURE(keys_.size() == id_data_.size());
0171 CELER_ENSURE(id_offsets_.size() == ids_.size() + 1);
0172 }
0173
0174
0175
0176
0177
0178
0179
0180
0181 template<class I>
0182 auto LabelIdMultiMap<I>::find_all(std::string const& name) const -> SpanConstIdT
0183 {
0184 auto iter = ids_.find(name);
0185 if (iter == ids_.end())
0186 return {};
0187
0188 size_type offset_idx = iter->second;
0189 CELER_ASSERT(offset_idx + 1 < id_offsets_.size());
0190 size_type start = id_offsets_[offset_idx];
0191 size_type stop = id_offsets_[offset_idx + 1];
0192 CELER_ENSURE(start < stop && stop <= id_data_.size());
0193 return {id_data_.data() + start, stop - start};
0194 }
0195
0196
0197
0198
0199
0200
0201
0202
0203 template<class I>
0204 auto LabelIdMultiMap<I>::find_unique(std::string const& name) const -> IdT
0205 {
0206 auto items = this->find_all(name);
0207 if (items.empty())
0208 return {};
0209 CELER_VALIDATE(items.size() == 1,
0210 << type_label_ << " '" << name << "' is not unique");
0211 return items.front();
0212 }
0213
0214
0215
0216
0217
0218
0219
0220 template<class I>
0221 auto LabelIdMultiMap<I>::find_exact(Label const& label_sub) const -> IdT
0222 {
0223 auto items = this->find_all(label_sub.name);
0224
0225
0226 auto iter = std::find_if(
0227 items.begin(), items.end(), [&keys = keys_, &label_sub](IdT id) {
0228 CELER_EXPECT(id < keys.size());
0229 return keys[id.unchecked_get()].ext == label_sub.ext;
0230 });
0231 if (iter == items.end())
0232 {
0233
0234 return {};
0235 }
0236 CELER_ENSURE(keys_[iter->unchecked_get()] == label_sub);
0237 return *iter;
0238 }
0239
0240
0241
0242
0243
0244
0245
0246 template<class I>
0247 Label const& LabelIdMultiMap<I>::at(IdT id) const
0248 {
0249 CELER_EXPECT(id < this->size());
0250 return keys_[id.unchecked_get()];
0251 }
0252
0253
0254
0255
0256
0257 template<class I>
0258 CELER_FORCEINLINE LabelIdMultiMap<I>::operator bool() const
0259 {
0260 return !keys_.empty() || !type_label_.empty();
0261 }
0262
0263
0264 }