File indexing completed on 2025-01-18 09:54:46
0001
0002
0003
0004
0005
0006
0007
0008 #pragma once
0009
0010 #include <algorithm>
0011 #include <string>
0012 #include <unordered_map>
0013 #include <vector>
0014
0015 #include "corecel/Assert.hh"
0016 #include "corecel/io/Label.hh"
0017
0018 #include "Range.hh"
0019 #include "Span.hh"
0020
0021 namespace celeritas
0022 {
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043 template<class I>
0044 class LabelIdMultiMap
0045 {
0046 public:
0047
0048
0049 using IdT = I;
0050 using SpanConstIdT = Span<IdT const>;
0051 using VecLabel = std::vector<Label>;
0052 using size_type = typename IdT::size_type;
0053
0054
0055 public:
0056
0057 LabelIdMultiMap() = default;
0058
0059
0060 explicit LabelIdMultiMap(VecLabel keys);
0061
0062
0063 inline SpanConstIdT find_all(std::string const& label) const;
0064
0065
0066 inline IdT find(Label const& label_sub) const;
0067
0068
0069 inline Label const& get(IdT id) const;
0070
0071
0072 SpanConstIdT duplicates() const { return make_span(duplicates_); }
0073
0074
0075 size_type size() const { return keys_.size(); }
0076
0077 private:
0078 VecLabel keys_;
0079 std::vector<IdT> id_data_;
0080 std::vector<size_type> id_offsets_;
0081 std::vector<IdT> duplicates_;
0082 std::unordered_map<std::string, size_type> ids_;
0083 };
0084
0085
0086
0087
0088
0089
0090
0091 template<class I>
0092 LabelIdMultiMap<I>::LabelIdMultiMap(VecLabel keys) : keys_(std::move(keys))
0093 {
0094 if (keys_.empty())
0095 {
0096
0097
0098 return;
0099 }
0100
0101
0102 id_data_.resize(keys_.size());
0103 for (auto idx : range<size_type>(keys_.size()))
0104 {
0105 id_data_[idx] = IdT{idx};
0106 }
0107
0108 std::sort(id_data_.begin(), id_data_.end(), [this](IdT a, IdT b) {
0109 return this->keys_[a.unchecked_get()] < this->keys_[b.unchecked_get()];
0110 });
0111
0112
0113 id_offsets_.reserve(keys_.size() / 2 + 2);
0114 ids_.reserve(id_offsets_.capacity());
0115
0116
0117 id_offsets_.push_back(0);
0118 ids_.insert({keys_[id_data_[0].unchecked_get()].name, 0});
0119 for (auto idx : range<size_type>(1, id_data_.size()))
0120 {
0121 Label const& prev = keys_[id_data_[idx - 1].unchecked_get()];
0122 Label const& cur = keys_[id_data_[idx].unchecked_get()];
0123 if (prev == cur && !cur.empty())
0124 {
0125 if (duplicates_.empty()
0126 || keys_[duplicates_.back().unchecked_get()] != prev)
0127 {
0128
0129 duplicates_.push_back(id_data_[idx - 1]);
0130 }
0131 duplicates_.push_back(id_data_[idx]);
0132 }
0133 if (prev.name != cur.name)
0134 {
0135
0136 size_type offset_idx = id_offsets_.size();
0137 id_offsets_.push_back(idx);
0138 auto insert_ok = ids_.insert({cur.name, offset_idx});
0139 CELER_ASSERT(insert_ok.second);
0140 }
0141 }
0142 id_offsets_.push_back(id_data_.size());
0143
0144 CELER_ENSURE(keys_.size() == id_data_.size());
0145 CELER_ENSURE(id_offsets_.size() == ids_.size() + 1);
0146 }
0147
0148
0149
0150
0151
0152 template<class I>
0153 auto LabelIdMultiMap<I>::find_all(std::string const& name) const -> SpanConstIdT
0154 {
0155 auto iter = ids_.find(name);
0156 if (iter == ids_.end())
0157 return {};
0158
0159 size_type offset_idx = iter->second;
0160 CELER_ASSERT(offset_idx + 1 < id_offsets_.size());
0161 size_type start = id_offsets_[offset_idx];
0162 size_type stop = id_offsets_[offset_idx + 1];
0163 CELER_ENSURE(start < stop && stop <= id_data_.size());
0164 return {id_data_.data() + start, stop - start};
0165 }
0166
0167
0168
0169
0170
0171
0172
0173 template<class I>
0174 auto LabelIdMultiMap<I>::find(Label const& label_sub) const -> IdT
0175 {
0176 auto items = this->find_all(label_sub.name);
0177
0178
0179 auto iter
0180 = std::find_if(items.begin(), items.end(), [this, &label_sub](IdT id) {
0181 CELER_EXPECT(id < this->keys_.size());
0182 return this->keys_[id.unchecked_get()].ext == label_sub.ext;
0183 });
0184 if (iter == items.end())
0185 {
0186
0187 return {};
0188 }
0189 CELER_ENSURE(keys_[iter->unchecked_get()] == label_sub);
0190 return *iter;
0191 }
0192
0193
0194
0195
0196
0197
0198
0199 template<class I>
0200 Label const& LabelIdMultiMap<I>::get(IdT id) const
0201 {
0202 CELER_EXPECT(id < this->size());
0203 return keys_[id.unchecked_get()];
0204 }
0205
0206
0207 }