19#include <initializer_list>
34template <
typename K,
typename V,
typename C,
typename A>
35struct detail::disables_basecell_compare<std::map<K, V, C, A>> : std::true_type {
71 return descriptor::CellCategory::TypedMap;
74 [[nodiscard]] std::vector<std::string_view>
sub_kinds()
const override {
84 j[
"element_kind"] = T::kind_id;
106 :
public BaseCell<TypedMapCell<T>, std::map<std::string, typename T::storage_t>> {
110 using element_type = T;
111 using element_storage_t =
typename T::storage_t;
113 using base_t::base_t;
114 using base_t::operator=;
120 TypedMapCell(std::initializer_list<std::pair<const std::string, element_storage_t>> elems)
121 :
base_t(std::map<std::string, element_storage_t>(elems)) {}
126 template <std::ranges::input_range R>
127 requires requires(std::ranges::range_value_t<R> p) {
128 { p.first } -> std::convertible_to<std::string>;
129 { p.second } -> std::convertible_to<element_storage_t>;
132 :
base_t(std::map<std::string, element_storage_t>(std::ranges::begin(r),
133 std::ranges::end(r))) {}
141 [[nodiscard]]
auto keys() const noexcept {
142 return this->
value | std::views::keys;
146 [[nodiscard]]
auto values() const noexcept {
147 return this->
value | std::views::values;
153 using map_t = std::map<std::string, element_storage_t>;
154 using key_type = map_t::key_type;
155 using mapped_type = map_t::mapped_type;
156 using value_type = map_t::value_type;
157 using size_type = map_t::size_type;
158 using iterator = map_t::iterator;
159 using const_iterator = map_t::const_iterator;
161 [[nodiscard]] size_type size() const noexcept {
162 return this->
value.size();
164 [[nodiscard]]
bool empty() const noexcept {
165 return this->
value.empty();
168 mapped_type& operator[](key_type
const& k) {
169 return this->
value[k];
171 mapped_type& operator[](key_type&& k) {
172 return this->
value[std::move(k)];
174 mapped_type& at(key_type
const& k) {
175 return this->
value.at(k);
177 [[nodiscard]] mapped_type
const& at(key_type
const& k)
const {
178 return this->
value.at(k);
181 iterator find(key_type
const& k) {
182 return this->
value.find(k);
184 [[nodiscard]] const_iterator find(key_type
const& k)
const {
185 return this->
value.find(k);
187 [[nodiscard]]
bool contains(key_type
const& k)
const {
188 return this->
value.contains(k);
190 [[nodiscard]] size_type count(key_type
const& k)
const {
191 return this->
value.count(k);
194 iterator begin() noexcept {
195 return this->
value.begin();
197 [[nodiscard]] const_iterator begin() const noexcept {
198 return this->
value.begin();
200 [[nodiscard]] const_iterator cbegin() const noexcept {
201 return this->
value.cbegin();
203 iterator end() noexcept {
204 return this->
value.end();
206 [[nodiscard]] const_iterator end() const noexcept {
207 return this->
value.end();
209 [[nodiscard]] const_iterator cend() const noexcept {
210 return this->
value.cend();
213 std::pair<iterator, bool> insert(value_type
const& v) {
214 return this->
value.insert(v);
216 std::pair<iterator, bool> insert(value_type&& v) {
217 return this->
value.insert(std::move(v));
219 template <
typename... Args>
220 std::pair<iterator, bool> emplace(Args&&... args) {
221 return this->
value.emplace(std::forward<Args>(args)...);
223 size_type erase(key_type
const& k) {
224 return this->
value.erase(k);
226 iterator erase(const_iterator pos) {
227 return this->
value.erase(pos);
229 void clear() noexcept {
251 std::string out =
"{";
253 for (
auto const& [key, el] : this->
value) {
260 out += wrapper.to_string();
268 json_t obj = json_t::object();
269 for (
auto const& [key, el] : this->
value) {
288 [[nodiscard]] std::partial_ordering
compare(
ICell const& other)
const override {
289 if (
const auto k_cmp = this->
kind() <=> other.
kind(); k_cmp != 0) {
292 const auto* o =
dynamic_cast<TypedMapCell const*
>(&other);
294 return std::partial_ordering::unordered;
296 auto it_a = this->
value.begin();
297 auto it_b = o->value.begin();
298 const auto end_a = this->
value.end();
299 const auto end_b = o->value.end();
300 while (it_a != end_a && it_b != end_b) {
301 if (
const auto kc = it_a->first <=> it_b->first; kc != 0) {
306 if (
const auto vc = wa.compare(wb); vc != 0) {
312 return this->
value.size() <=> o->value.size();
324 if (!j.is_object()) {
330 if (it_k == j.end() || !it_k->is_string()) {
335 if (it_k->get<std::string_view>() !=
kind_id) {
342 if (it_v == j.end() || !it_v->is_object()) {
347 std::map<std::string, element_storage_t> elems;
348 for (
auto const& [key, raw] : it_v->items()) {
350 cell_t v = T::from_json(wrapped, reg);
351 auto* typed =
dynamic_cast<T*
>(v.get());
352 if (typed ==
nullptr) {
353 throw TypeException(std::string(
"TypedMapCell: element from_json did not return ") +
354 std::string(T::kind_id),
357 elems.emplace(key, std::move(typed->value));
359 auto cell = std::make_shared<TypedMapCell<T>>(std::move(elems));
369 static const auto d = std::make_shared<TypedMapCellTypeDescriptor<T>>(
DisplayInfo{
371 .description = std::string(
"Homogeneous map of ") + std::string(T::kind_id),
394 using base_t::base_t;
395 using base_t::operator=;
401 MapCell(
const std::initializer_list<std::pair<const std::string, cell_t>> elems)
405 [[nodiscard]]
auto keys() const noexcept {
406 return this->
value | std::views::keys;
410 [[nodiscard]]
auto values() const noexcept {
411 return this->
value | std::views::values;
416 using map_t = std::map<std::string, cell_t>;
417 using key_type = map_t::key_type;
418 using mapped_type = map_t::mapped_type;
419 using value_type = map_t::value_type;
420 using size_type = map_t::size_type;
421 using iterator = map_t::iterator;
422 using const_iterator = map_t::const_iterator;
424 [[nodiscard]] size_type size() const noexcept {
425 return this->
value.size();
427 [[nodiscard]]
bool empty() const noexcept {
428 return this->
value.empty();
431 mapped_type& operator[](key_type
const& k) {
432 return this->
value[k];
434 mapped_type& operator[](key_type&& k) {
435 return this->
value[std::move(k)];
437 mapped_type& at(key_type
const& k) {
438 return this->
value.at(k);
440 [[nodiscard]] mapped_type
const& at(key_type
const& k)
const {
441 return this->
value.at(k);
444 iterator find(key_type
const& k) {
445 return this->
value.find(k);
447 [[nodiscard]] const_iterator find(key_type
const& k)
const {
448 return this->
value.find(k);
450 [[nodiscard]]
bool contains(key_type
const& k)
const {
451 return this->
value.contains(k);
453 [[nodiscard]] size_type count(key_type
const& k)
const {
454 return this->
value.count(k);
457 iterator begin() noexcept {
458 return this->
value.begin();
460 [[nodiscard]] const_iterator begin() const noexcept {
461 return this->
value.begin();
463 [[nodiscard]] const_iterator cbegin() const noexcept {
464 return this->
value.cbegin();
466 iterator end() noexcept {
467 return this->
value.end();
469 [[nodiscard]] const_iterator end() const noexcept {
470 return this->
value.end();
472 [[nodiscard]] const_iterator cend() const noexcept {
473 return this->
value.cend();
476 std::pair<iterator, bool> insert(value_type
const& v) {
477 return this->
value.insert(v);
479 std::pair<iterator, bool> insert(value_type&& v) {
480 return this->
value.insert(std::move(v));
482 template <
typename... Args>
483 std::pair<iterator, bool> emplace(Args&&... args) {
484 return this->
value.emplace(std::forward<Args>(args)...);
486 size_type erase(key_type
const& k) {
487 return this->
value.erase(k);
489 iterator erase(
const const_iterator pos) {
490 return this->
value.erase(pos);
492 void clear() noexcept {
498 static constexpr std::string_view
kind_id =
"m";
505 std::string out =
"{";
507 for (
auto const& [key, el] : this->
value) {
513 out += el ? el->to_string() :
"<null>";
521 json_t obj = json_t::object();
522 for (
auto const& [key, el] : this->
value) {
523 obj[key] = el ? el->to_json() :
json_t();
534 std::map<std::string, cell_t> copied;
535 for (
auto const& [key, el] : this->
value) {
536 copied.emplace(key, el ? el->clone() :
nullptr);
538 auto out = std::make_shared<MapCell>(std::move(copied));
543 [[nodiscard]] std::size_t
hash_value() const noexcept
override {
544 std::size_t h = std::hash<std::string_view>{}(
kind());
546 for (
auto const& [key, el] : this->
value) {
547 const std::size_t hk = std::hash<std::string>{}(key);
548 const std::size_t hv = el ? el->hash_value() : std::size_t{0};
549 h ^= hk + 0x9e3779b97f4a7c15ULL + (h << 6) + (h >> 2);
550 h ^= hv + 0x9e3779b97f4a7c15ULL + (h << 6) + (h >> 2);
561 [[nodiscard]] std::partial_ordering
compare(
ICell const& other)
const override {
562 if (
const auto k_cmp = this->
kind() <=> other.
kind(); k_cmp != 0) {
565 const auto* o =
dynamic_cast<MapCell const*
>(&other);
567 return std::partial_ordering::unordered;
569 auto it_a = this->
value.begin();
570 auto it_b = o->value.begin();
571 const auto end_a = this->
value.end();
572 const auto end_b = o->value.end();
573 while (it_a != end_a && it_b != end_b) {
574 if (
const auto kc = it_a->first <=> it_b->first; kc != 0) {
577 if (it_a->second && it_b->second) {
578 if (
const auto vc = it_a->second->compare(*it_b->second); vc != 0) {
581 }
else if (!it_a->second && it_b->second) {
582 return std::partial_ordering::less;
583 }
else if (it_a->second && !it_b->second) {
584 return std::partial_ordering::greater;
589 return this->
value.size() <=> o->value.size();
600 if (!j.is_object()) {
605 if (it_k == j.end() || !it_k->is_string()) {
609 if (it_k->get<std::string_view>() !=
kind_id) {
615 if (it_v == j.end() || !it_v->is_object()) {
620 std::map<std::string, cell_t> elems;
621 for (
auto const& [key, raw] : it_v->items()) {
624 auto cell = std::make_shared<MapCell>(std::move(elems));
650 return descriptor::CellCategory::Map;
659 static const auto d = std::make_shared<MapCellTypeDescriptor>(
660 DisplayInfo{.name =
"Map", .description =
"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
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
JSON shape was wrong (missing/non-string k, missing v, etc.).
Definition error.h:158
k field was present but did not match the expected kind.
Definition error.h:168
Descriptor for the heterogeneous MapCell.
Definition map.h:642
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 map.h:653
descriptor::CellCategory category() const override
Coarse classification (primitive, list, struct, …).
Definition map.h:649
Heterogeneous string-keyed map of cell_t — wire kind "m".
Definition map.h:390
cell_t clone() const override
Deep-copy this cell.
Definition map.h:533
auto values() const noexcept
Lazy view over the cell values of the map.
Definition map.h:410
std::string to_string() const override
Render the map as {k1: v1, …}; null values appear as <null>.
Definition map.h:504
auto keys() const noexcept
Lazy view over the keys of the map.
Definition map.h:405
std::partial_ordering compare(ICell const &other) const override
Lexicographic three-way comparison over keys then values; ignores display info.
Definition map.h:561
static cell_t from_json(json_t const &j, ParcelRegistry const ®)
Deserialize a MapCell from JSON.
Definition map.h:599
static cell_type_descriptor_t descriptor()
Cached descriptor for MapCell.
Definition map.h:658
std::size_t hash_value() const noexcept override
Equality-consistent hash that mirrors compare's display-info-insensitivity.
Definition map.h:543
static constexpr std::string_view kind_id
Wire kind id ("m").
Definition map.h:498
MapCell(const std::initializer_list< std::pair< const std::string, cell_t > > elems)
Construct from a brace-enclosed list of {key, cell} pairs.
Definition map.h:401
json_t to_json() const override
Default JSON serialization for cells with JSON-convertible storage.
Definition map.h:520
Runtime catalog of cell-type descriptors, keyed by wire kind id.
Definition registry.h:115
cell_t cell_from_json(json_t const &j) const
Deserialize any registered cell from JSON, dispatching by "k".
Definition registry.h:266
Typed value (cast, struct field, etc.) failed conversion.
Definition error.h:190
Descriptor for TypedMapCell<T>.
Definition map.h:54
std::string_view element_kind() const
Wire kind id of the map's value type.
Definition map.h:66
TypedMapCellTypeDescriptor(DisplayInfo info)
Construct with the given display info.
Definition map.h:63
json_t to_json() const override
Serialize the descriptor itself (kind + display info + category + extras).
Definition map.h:82
std::vector< std::string_view > sub_kinds() const override
Sub-kind ids reachable from this descriptor.
Definition map.h:74
cell_t cell_from_json(json_t const &j, ParcelRegistry const ®) const override
Construct a cell from JSON, dispatching to the concrete from_json.
Definition map.h:78
descriptor::CellCategory category() const override
Coarse classification (primitive, list, struct, …).
Definition map.h:70
Homogeneous string-keyed map of values of type T.
Definition map.h:106
TypedMapCell(std::from_range_t, R &&r)
Construct from any input range whose elements are {key, value}-like.
Definition map.h:131
std::string to_string() const override
Render the map as {k1: v1, k2: v2} using each value's to_string.
Definition map.h:250
json_t to_json() const override
Default JSON serialization for cells with JSON-convertible storage.
Definition map.h:267
TypedMapCell(std::initializer_list< std::pair< const std::string, element_storage_t > > elems)
Construct from a brace-enclosed list of {key, value} pairs.
Definition map.h:120
auto keys() const noexcept
Lazy view over the keys of the map.
Definition map.h:141
auto values() const noexcept
Lazy view over the values of the map.
Definition map.h:146
static cell_type_descriptor_t descriptor()
Cached descriptor for this typed map.
Definition map.h:368
std::partial_ordering compare(ICell const &other) const override
Lexicographic three-way comparison over (key, value) pairs; ignores display info.
Definition map.h:288
static constexpr std::string_view kind_id
Wire kind id of this typed map ("m:" + T::kind_id).
Definition map.h:244
static cell_t from_json(json_t const &j, ParcelRegistry const ®)
Deserialize a TypedMapCell<T> from JSON.
Definition map.h:323
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::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
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
Mix-in declaring a descriptor refers to other registered cell kinds.
Definition descriptor.h:148