dimval 0.2.0
Modern C++23 header-only library of dimensional values (units, measures, ranges)
Loading...
Searching...
No Matches
registry.hpp
Go to the documentation of this file.
1#pragma once
2
10
11#include <dimval/descriptor.hpp>
12#include <dimval/traits.hpp>
13
14#include <mutex>
15#include <shared_mutex>
16#include <string_view>
17#include <unordered_map>
18#include <utility>
19#include <vector>
20
21namespace dimval {
22
27public:
28 UnitRegistry() = default;
29 UnitRegistry(const UnitRegistry&) = delete;
30 UnitRegistry& operator=(const UnitRegistry&) = delete;
31 UnitRegistry(UnitRegistry&&) = delete;
32 UnitRegistry& operator=(UnitRegistry&&) = delete;
33 ~UnitRegistry() = default;
34
36 static UnitRegistry& global() {
37 static UnitRegistry instance;
38 return instance;
39 }
40
43 const std::unique_lock lock{mutex_};
44 register_unit_locked(d);
45 }
46
50 template <UnitLike Unit>
52 const auto d = Unit::descriptor();
53 const std::unique_lock lock{mutex_};
54 if (id_index_.contains(d.id)) {
55 return false;
56 }
57 register_unit_locked(d);
58 return true;
59 }
60
62 [[nodiscard]] const UnitDescriptor* find(const std::string_view id_or_symbol) const {
63 const std::shared_lock lock{mutex_};
64 if (const auto it = id_index_.find(id_or_symbol); it != id_index_.end()) {
65 return &entries_[it->second];
66 }
67 if (const auto it = symbol_index_.find(id_or_symbol); it != symbol_index_.end()) {
68 return &entries_[it->second];
69 }
70 return nullptr;
71 }
72
74 [[nodiscard]] std::vector<UnitDescriptor> list() const {
75 const std::shared_lock lock{mutex_};
76 return entries_;
77 }
78
80 [[nodiscard]] std::vector<UnitDescriptor> by_kind(const std::string_view kind) const {
81 const std::shared_lock lock{mutex_};
82 std::vector<UnitDescriptor> out;
83 for (const auto& e : entries_) {
84 if (e.kind == kind) {
85 out.push_back(e);
86 }
87 }
88 return out;
89 }
90
92 [[nodiscard]] bool compatible(const std::string_view a, const std::string_view b) const {
93 const std::shared_lock lock{mutex_};
94 const auto* da = find_locked(a);
95 const auto* db = find_locked(b);
96 return da != nullptr && db != nullptr && da->kind == db->kind;
97 }
98
100 [[nodiscard]] std::size_t size() const {
101 const std::shared_lock lock{mutex_};
102 return entries_.size();
103 }
104
105private:
106 [[nodiscard]] const UnitDescriptor* find_locked(const std::string_view key) const {
107 if (const auto it = id_index_.find(key); it != id_index_.end()) {
108 return &entries_[it->second];
109 }
110 if (const auto it = symbol_index_.find(key); it != symbol_index_.end()) {
111 return &entries_[it->second];
112 }
113 return nullptr;
114 }
115
116 void register_unit_locked(const UnitDescriptor& d) {
117 if (const auto it = id_index_.find(d.id); it != id_index_.end()) {
118 entries_[it->second] = d;
119 } else {
120 const auto idx = entries_.size();
121 entries_.push_back(d);
122 id_index_[d.id] = idx;
123 if (!d.symbol.empty() && d.symbol != d.id) {
124 symbol_index_[d.symbol] = idx;
125 }
126 }
127 }
128
129 mutable std::shared_mutex mutex_;
130 std::vector<UnitDescriptor> entries_;
131 std::unordered_map<std::string_view, std::size_t> id_index_;
132 std::unordered_map<std::string_view, std::size_t> symbol_index_;
133};
134
137public:
138 MeasureRegistry() = default;
139 MeasureRegistry(const MeasureRegistry&) = delete;
140 MeasureRegistry& operator=(const MeasureRegistry&) = delete;
142 MeasureRegistry& operator=(MeasureRegistry&&) = delete;
143 ~MeasureRegistry() = default;
144
147 static MeasureRegistry instance;
148 return instance;
149 }
150
153 const std::unique_lock lock{mutex_};
154 register_measure_locked(d);
155 }
156
159 template <MeasureLike Measure>
161 const auto d = Measure::descriptor();
162 const std::unique_lock lock{mutex_};
163 if (id_index_.contains(d.id)) {
164 return false;
165 }
166 register_measure_locked(d);
167 return true;
168 }
169
170 [[nodiscard]] const MeasureDescriptor* find(const std::string_view id) const {
171 const std::shared_lock lock{mutex_};
172 if (const auto it = id_index_.find(id); it != id_index_.end()) {
173 return &entries_[it->second];
174 }
175 return nullptr;
176 }
177
178 [[nodiscard]] std::vector<MeasureDescriptor> list() const {
179 const std::shared_lock lock{mutex_};
180 return entries_;
181 }
182
185 [[nodiscard]] bool compatible(const std::string_view measure_id,
186 const std::string_view unit_id) const {
187 const std::shared_lock lock{mutex_};
188 if (const auto it = id_index_.find(measure_id); it != id_index_.end()) {
189 return entries_[it->second].base_unit_id == unit_id;
190 }
191 return false;
192 }
193
194 [[nodiscard]] std::size_t size() const {
195 const std::shared_lock lock{mutex_};
196 return entries_.size();
197 }
198
199private:
200 void register_measure_locked(const MeasureDescriptor& d) {
201 if (const auto it = id_index_.find(d.id); it != id_index_.end()) {
202 entries_[it->second] = d;
203 } else {
204 const auto idx = entries_.size();
205 entries_.push_back(d);
206 id_index_[d.id] = idx;
207 }
208 }
209
210 mutable std::shared_mutex mutex_;
211 std::vector<MeasureDescriptor> entries_;
212 std::unordered_map<std::string_view, std::size_t> id_index_;
213};
214
215namespace detail {
216
220template <UnitLike Unit>
221[[maybe_unused]] inline int register_unit_tag() {
223 return 0;
224}
225
227template <MeasureLike Measure>
228[[maybe_unused]] inline int register_measure_tag() {
230 return 0;
231}
232
233} // namespace detail
234
235} // namespace dimval
Registry of measure descriptors.
Definition registry.hpp:136
static MeasureRegistry & global()
Process-wide singleton.
Definition registry.hpp:146
bool compatible(const std::string_view measure_id, const std::string_view unit_id) const
True iff measure_id and unit_id both resolve and the measure's declared base unit equals unit_id.
Definition registry.hpp:185
void register_measure(const MeasureDescriptor &d)
Register a descriptor. Existing entries with the same id are replaced.
Definition registry.hpp:152
bool register_measure()
Register a measure by tag — pulls the descriptor through Measure::descriptor().
Definition registry.hpp:160
Registry of unit descriptors.
Definition registry.hpp:26
const UnitDescriptor * find(const std::string_view id_or_symbol) const
Look up by id, then by symbol. Returns nullptr if not found.
Definition registry.hpp:62
std::vector< UnitDescriptor > list() const
Snapshot all registered descriptors.
Definition registry.hpp:74
std::size_t size() const
Number of registered descriptors.
Definition registry.hpp:100
bool compatible(const std::string_view a, const std::string_view b) const
True iff both ids resolve and share the same kind.
Definition registry.hpp:92
std::vector< UnitDescriptor > by_kind(const std::string_view kind) const
Snapshot all descriptors whose kind matches.
Definition registry.hpp:80
bool register_unit()
Register a unit by tag — pulls the descriptor through Unit::descriptor().
Definition registry.hpp:51
static UnitRegistry & global()
Process-wide singleton.
Definition registry.hpp:36
void register_unit(const UnitDescriptor &d)
Register a descriptor. Existing entries with the same id are replaced.
Definition registry.hpp:42
Runtime metadata structs for units and measures.
Runtime metadata for a measure (a semantic specialization of a unit).
Definition descriptor.hpp:54
Runtime metadata for a unit.
Definition descriptor.hpp:29
Concepts and helper accessors that drive the static side of dimval.