19#include <initializer_list>
26#include <unordered_map>
32template <
typename K,
typename V,
typename H,
typename E,
typename A>
33struct detail::disables_basecell_compare<std::unordered_map<K, V, H, E, A>> : std::true_type {
37class TypedHashMapCell;
40class TypedHashMapCellTypeDescriptor final :
public BaseCellTypeDescriptor<TypedHashMapCell<T>>,
43 using cell_type = TypedHashMapCell<T>;
44 using base_t = BaseCellTypeDescriptor<TypedHashMapCell<T>>;
46 explicit TypedHashMapCellTypeDescriptor(DisplayInfo info) : base_t(std::move(info)) {}
48 [[nodiscard]] descriptor::CellCategory category()
const override {
49 return descriptor::CellCategory::TypedMap;
52 [[nodiscard]] std::vector<std::string_view> sub_kinds()
const override {
56 [[nodiscard]]
cell_t cell_from_json(json_t
const& j, ParcelRegistry
const& reg)
const override {
57 return TypedHashMapCell<T>::from_json(j, reg);
62 j[
"element_kind"] = T::kind_id;
75 :
public BaseCell<TypedHashMapCell<T>, std::unordered_map<std::string, typename T::storage_t>> {
80 using element_type = T;
81 using element_storage_t =
typename T::storage_t;
82 using map_t = std::unordered_map<std::string, element_storage_t>;
85 using base_t::operator=;
87 TypedHashMapCell(std::initializer_list<std::pair<const std::string, element_storage_t>> elems)
90 [[nodiscard]] std::size_t size()
const noexcept {
91 return this->
value.size();
93 [[nodiscard]]
bool empty()
const noexcept {
94 return this->
value.empty();
97 element_storage_t& operator[](std::string
const& k) {
98 return this->
value[k];
100 [[nodiscard]] element_storage_t
const& at(std::string
const& k)
const {
101 return this->
value.at(k);
103 [[nodiscard]]
bool contains(std::string
const& k)
const {
104 return this->
value.contains(k);
106 auto begin()
noexcept {
107 return this->
value.begin();
109 auto end()
noexcept {
110 return this->
value.end();
112 [[nodiscard]]
auto begin()
const noexcept {
113 return this->
value.begin();
115 [[nodiscard]]
auto end()
const noexcept {
116 return this->
value.end();
119 static constexpr std::string_view kind_id =
prefixed_id_v<
"hm:", T::kind_id>;
122 std::string out =
"{";
124 for (
auto const& [k, vp] : sorted_view()) {
131 out += wrapper.to_string();
139 json_t obj = json_t::object();
140 for (
auto const& [k, vp] : sorted_view()) {
152 [[nodiscard]] std::partial_ordering
compare(
ICell const& other)
const override {
153 if (
const auto k_cmp = this->
kind() <=> other.
kind(); k_cmp != 0) {
158 return std::partial_ordering::unordered;
160 auto a = sorted_view();
161 auto b = o->sorted_view();
162 const std::size_t n = std::min(a.size(), b.size());
163 for (std::size_t i = 0; i < n; ++i) {
164 if (
const auto kc = a[i].first <=> b[i].first; kc != 0) {
169 if (
const auto vc = wa.compare(wb); vc != 0) {
173 return a.size() <=> b.size();
177 if (!j.is_object()) {
179 std::string(kind_id));
182 if (it_k == j.end() || !it_k->is_string()) {
183 throw InvalidJsonException(
"TypedHashMapCell: missing/invalid 'k' (expected '" +
184 std::string(kind_id) +
"')",
185 std::string(kind_id));
187 if (it_k->get<std::string_view>() != kind_id) {
188 throw KindMismatchException(
"TypedHashMapCell: missing/invalid 'k' (expected '" +
189 std::string(kind_id) +
"')",
190 std::string(kind_id));
193 if (it_v == j.end() || !it_v->is_object()) {
194 throw InvalidJsonException(
"TypedHashMapCell: missing/invalid 'v' (expected object)",
195 std::string(kind_id));
199 for (
auto const& [key, raw] : it_v->items()) {
201 cell_t v = T::from_json(wrapped, reg);
202 auto* typed =
dynamic_cast<T*
>(v.get());
203 if (typed ==
nullptr) {
204 throw TypeException(
"TypedHashMapCell: element from_json mismatch",
205 std::string(kind_id));
207 elems.emplace(key, std::move(typed->value));
209 auto cell = std::make_shared<TypedHashMapCell<T>>(std::move(elems));
215 static const auto d = std::make_shared<TypedHashMapCellTypeDescriptor<T>>(
DisplayInfo{
217 .description = std::string(
"Hash-backed map of ") + std::string(T::kind_id),
223 [[nodiscard]] std::vector<std::pair<std::string_view, element_storage_t const*>>
224 sorted_view()
const {
225 std::vector<std::pair<std::string_view, element_storage_t const*>> out;
226 out.reserve(this->
value.size());
227 for (
auto const& [k, v] : this->
value) {
228 out.emplace_back(std::string_view(k), &v);
230 std::ranges::sort(out, {}, &std::pair<std::string_view, element_storage_t const*>::first);
245 using base_t::base_t;
246 using base_t::operator=;
248 HashMapCell(
const std::initializer_list<std::pair<const std::string, cell_t>> elems)
249 :
base_t(std::unordered_map<std::string, cell_t>(elems)) {}
251 [[nodiscard]] std::size_t size()
const noexcept {
252 return this->
value.size();
254 [[nodiscard]]
bool empty()
const noexcept {
255 return this->
value.empty();
258 cell_t& operator[](std::string
const& k) {
259 return this->
value[k];
261 [[nodiscard]]
cell_t const& at(std::string
const& k)
const {
262 return this->
value.at(k);
264 [[nodiscard]]
bool contains(std::string
const& k)
const {
265 return this->
value.contains(k);
268 static constexpr std::string_view kind_id =
"hm";
271 std::vector<std::string_view> keys;
272 keys.reserve(this->
value.size());
273 for (
const auto& k : this->
value | std::views::keys) {
274 keys.emplace_back(k);
276 std::ranges::sort(keys);
277 std::string out =
"{";
279 for (
auto k : keys) {
285 const auto& v = this->
value.at(std::string(k));
286 out += v ? v->to_string() :
"<null>";
294 std::vector<std::string_view> keys;
295 keys.reserve(this->
value.size());
296 for (
const auto& k : this->
value | std::views::keys) {
297 keys.emplace_back(k);
299 std::ranges::sort(keys);
300 json_t obj = json_t::object();
301 for (
auto k : keys) {
302 const auto& v = this->
value.at(std::string(k));
303 obj[std::string(k)] = v ? v->to_json() :
json_t();
314 std::unordered_map<std::string, cell_t> copied;
315 for (
auto const& [k, v] : this->
value) {
316 copied.emplace(k, v ? v->clone() :
nullptr);
318 auto out = std::make_shared<HashMapCell>(std::move(copied));
323 [[nodiscard]] std::size_t
hash_value() const noexcept
override {
324 std::size_t h = std::hash<std::string_view>{}(
kind());
326 std::vector<std::string_view> keys;
327 keys.reserve(this->
value.size());
328 for (
const auto& k : this->
value | std::views::keys) {
329 keys.emplace_back(k);
331 std::ranges::sort(keys);
332 for (
const auto k : keys) {
333 const auto& el = this->
value.at(std::string(k));
334 const std::size_t hk = std::hash<std::string_view>{}(k);
335 const std::size_t hv = el ? el->hash_value() : std::size_t{0};
336 h ^= hk + 0x9e3779b97f4a7c15ULL + (h << 6) + (h >> 2);
337 h ^= hv + 0x9e3779b97f4a7c15ULL + (h << 6) + (h >> 2);
342 [[nodiscard]] std::partial_ordering
compare(
ICell const& other)
const override {
343 if (
const auto k_cmp = this->
kind() <=> other.
kind(); k_cmp != 0) {
346 const auto* o =
dynamic_cast<HashMapCell const*
>(&other);
348 return std::partial_ordering::unordered;
351 std::map<std::string, cell_t> a(this->
value.begin(), this->value.end());
352 std::map<std::string, cell_t> b(o->value.begin(), o->value.end());
353 auto it_a = a.begin();
354 auto it_b = b.begin();
355 while (it_a != a.end() && it_b != b.end()) {
356 if (
const auto kc = it_a->first <=> it_b->first; kc != 0) {
359 if (it_a->second && it_b->second) {
360 if (
const auto vc = it_a->second->compare(*it_b->second); vc != 0) {
363 }
else if (!it_a->second && it_b->second) {
364 return std::partial_ordering::less;
365 }
else if (it_a->second && !it_b->second) {
366 return std::partial_ordering::greater;
371 return a.size() <=> b.size();
375 if (!j.is_object()) {
377 std::string(kind_id));
380 if (it_k == j.end() || !it_k->is_string()) {
381 throw InvalidJsonException(
"HashMapCell: missing/invalid 'k' (expected 'hm')",
382 std::string(kind_id));
384 if (it_k->get<std::string_view>() != kind_id) {
385 throw KindMismatchException(
"HashMapCell: missing/invalid 'k' (expected 'hm')",
386 std::string(kind_id));
389 if (it_v == j.end() || !it_v->is_object()) {
390 throw InvalidJsonException(
"HashMapCell: missing/invalid 'v' (expected object)",
391 std::string(kind_id));
393 std::unordered_map<std::string, cell_t> elems;
394 for (
auto const& [k, raw] : it_v->items()) {
395 elems.emplace(k, raw.is_null() ? cell_t{} : reg.
cell_from_json(raw));
397 auto cell = std::make_shared<HashMapCell>(std::move(elems));
419 return descriptor::CellCategory::Map;
423 return HashMapCell::from_json(j, reg);
427inline cell_type_descriptor_t HashMapCell::descriptor() {
428 static const auto d = std::make_shared<HashMapCellTypeDescriptor>(
429 DisplayInfo{.name =
"HashMap", .description =
"Hash-backed heterogeneous map of cells"});
Core ICell interface, cell_t handle, BaseCell CRTP base, and CellLike concept.
std::shared_ptr< ICellTypeDescriptor > cell_type_descriptor_t
Shared handle to a runtime cell-type descriptor.
Definition cell.h:63
void to_json(json_t &j, T const &v)
ADL hook that lets nlohmann serialize any ICell-derived cell.
Definition cell.h:293
std::shared_ptr< ICell > cell_t
Shared handle to any ICell-derived value — the canonical cell pointer.
Definition cell.h:68
CRTP base that fills in the boilerplate of every cell-type descriptor.
Definition descriptor.h:165
json_t base_to_json() const
Common JSON skeleton (kind, display_info, category) reused by overrides.
Definition descriptor.h:202
Descriptor for the heterogeneous HashMapCell.
Definition unordered_map.h:411
descriptor::CellCategory category() const override
Coarse classification (primitive, list, struct, …).
Definition unordered_map.h:418
cell_t cell_from_json(const json_t &j, const ParcelRegistry ®) const override
Construct a cell from JSON, dispatching to the concrete from_json.
Definition unordered_map.h:422
Heterogeneous string-keyed unordered_map of cell_t.
Definition unordered_map.h:241
cell_t clone() const override
Deep-copy this cell.
Definition unordered_map.h:313
std::size_t hash_value() const noexcept override
Equality-consistent hash that mirrors compare's display-info-insensitivity.
Definition unordered_map.h:323
json_t to_json() const override
Default JSON serialization for cells with JSON-convertible storage.
Definition unordered_map.h:293
std::partial_ordering compare(ICell const &other) const override
Default three-way comparison: kind first, then storage value.
Definition unordered_map.h:342
std::string to_string() const override
Render the cell's value as a compact human-readable string.
Definition unordered_map.h:270
JSON shape was wrong (missing/non-string k, missing v, etc.).
Definition error.h:158
Runtime catalog of cell-type descriptors, keyed by wire kind id.
Definition registry.h:115
Homogeneous string-keyed unordered_map of values of type T.
Definition unordered_map.h:75
json_t to_json() const override
Default JSON serialization for cells with JSON-convertible storage.
Definition unordered_map.h:138
std::partial_ordering compare(ICell const &other) const override
Default three-way comparison: kind first, then storage value.
Definition unordered_map.h:152
std::string to_string() const override
Render the cell's value as a compact human-readable string.
Definition unordered_map.h:121
comms::DisplayInfo DisplayInfo
Display info attached to a cell or descriptor — re-exported from comms::DisplayInfo.
Definition common.h:75
constexpr std::string_view prefixed_id_v
Convenience alias yielding the joined std::string_view.
Definition common.h:175
auto cell(T &&v)
Wrap a raw value into its default cell, returning a shared_ptr to the cell.
Definition defaults.h:192
Runtime cell-type descriptors and the schema-graph mix-ins (IHasFields, ISubTypes).
CellCategory
Coarse runtime classification of a cell type.
Definition descriptor.h:35
nlohmann::json json_t
Project-wide alias for nlohmann::json.
Definition json.h:19
ParcelRegistry, Definition, and BuiltinsOptions for polymorphic dispatch.
CRTP base providing default to_json / clone / kind plumbing on top of a storage type.
Definition cell.h:343
std::optional< DisplayInfo > display_info_
Optional display info; omitted from JSON when empty.
Definition cell.h:507
std::string_view kind() const override
Definition cell.h:411
static void absorb_display_info(json_t const &j, Out &out)
Read "d" (if present) from a JSON object and assign it onto a cell.
Definition cell.h:499
std::unordered_map< std::string, T::storage_t > value
Held value of the cell.
Definition cell.h:348
void inject_display_info(json_t &j) const
Copy this cell's display info (if any) into the JSON object under "d".
Definition cell.h:486
static T cell_from_json(const json_t &j, const std::string_view expected_kind)
Validate a wrapped {"k","v"} JSON object and extract its "v" as T.
Definition cell.h:526
Polymorphic root of every parcel cell.
Definition cell.h:84
static constexpr std::string_view KEY_VALUE
JSON key for the value payload ("v").
Definition cell.h:88
virtual std::string_view kind() const =0
Wire-stable kind identifier for this cell.
static constexpr std::string_view KEY_KIND
JSON key for the kind id ("k").
Definition cell.h:86