MNX Document Model
Loading...
Searching...
No Matches
BaseTypes.h
1/*
2 * Copyright (C) 2025, Robert Patterson
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to deal
6 * in the Software without restriction, including without limitation the rights
7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 * copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 * THE SOFTWARE.
21 */
22#pragma once
23
24#include <memory>
25#include <unordered_map>
26#include <cassert>
27#include <iostream>
28#include <optional>
29#include <type_traits>
30
31#include "nlohmann/json.hpp"
32
44#define MNX_REQUIRED_PROPERTY(TYPE, NAME) \
45 TYPE NAME() const { \
46 if (!ref().contains(#NAME)) { \
47 throw std::runtime_error("Missing required property: " #NAME); \
48 } \
49 return ref()[#NAME].get<TYPE>(); \
50 } \
51 void set_##NAME(const TYPE& value) { ref()[#NAME] = value; } \
52 static_assert(true, "") // require semicolon after macro
53
66 #define MNX_ARRAY_ELEMENT_PROPERTY(TYPE, NAME, INDEX) \
67 static_assert(std::is_integral_v<decltype(INDEX)>, "array index must be an integer type"); \
68 TYPE NAME() const { return (*this)[INDEX]; } \
69 void set_##NAME(const TYPE& value) { (*this)[INDEX] = value; } \
70 static_assert(true, "") // require semicolon after macro
71
88 #define MNX_OPTIONAL_NAMED_PROPERTY(TYPE, NAME, KEY) \
89 std::optional<TYPE> NAME() const { \
90 return ref().contains(KEY) ? std::optional<TYPE>(ref()[KEY].get<TYPE>()) : std::nullopt; \
91 } \
92 TYPE NAME##_or(const TYPE& defaultVal) const { \
93 return ref().contains(KEY) ? ref()[KEY].get<TYPE>() : defaultVal; \
94 } \
95 void set_##NAME(const TYPE& value) { ref()[KEY] = value; } \
96 void clear_##NAME() { ref().erase(KEY); } \
97 static_assert(true, "") // require semicolon after macro
98
112 #define MNX_OPTIONAL_PROPERTY(TYPE, NAME) MNX_OPTIONAL_NAMED_PROPERTY(TYPE, NAME, #NAME)
113
129#define MNX_OPTIONAL_PROPERTY_WITH_DEFAULT(TYPE, NAME, DEFAULT) \
130 TYPE NAME() const { \
131 return ref().contains(#NAME) ? ref()[#NAME].get<TYPE>() : DEFAULT; \
132 } \
133 void set_##NAME(const TYPE& value) { ref()[#NAME] = value; } \
134 void clear_##NAME() { ref().erase(#NAME); } \
135 void set_or_clear_##NAME(const TYPE& value) { \
136 if (value == DEFAULT) clear_##NAME(); \
137 else set_##NAME(value); \
138 } \
139 static_assert(true, "") // require semicolon after macro
140
152 #define MNX_REQUIRED_CHILD(TYPE, NAME) \
153 TYPE NAME() const { return getChild<TYPE>(#NAME); } \
154 template<typename... Args> \
155 TYPE create_##NAME(Args&&... args) { \
156 return setChild(#NAME, TYPE(*this, #NAME, std::forward<Args>(args)...)); \
157 } \
158 static_assert(true, "") // require semicolon after macro
159
172 #define MNX_OPTIONAL_CHILD(TYPE, NAME) \
173 std::optional<TYPE> NAME() const { return getOptionalChild<TYPE>(#NAME); } \
174 template<typename... Args> \
175 TYPE create_##NAME(Args&&... args) { \
176 if (auto child = getOptionalChild<TYPE>(#NAME)) return child.value(); \
177 return setChild(#NAME, TYPE(*this, #NAME, std::forward<Args>(args)...)); \
178 } \
179 void clear_##NAME() { ref().erase(#NAME); } \
180 static_assert(true, "") // require semicolon after macro
181
182#define MNX_ASSERT_IF(TEST) \
183assert(!(TEST)); \
184if (TEST)
185
192namespace mnx {
193
195inline constexpr int MNX_VERSION = 1;
196
197using json = nlohmann::ordered_json;
198using json_pointer = json::json_pointer;
199
200class Object;
201template <typename T> class Array;
202
203namespace validation {
204class SemanticValidator;
205}; // namespace validation
206
210class Base
211{
212public:
213 virtual ~Base() = default;
214
216 Base(const Base& src) : m_root(src.m_root), m_pointer(src.m_pointer)
217 {}
218
220 Base(Base&& src) noexcept : m_root(src.m_root), // m_root must be copied (not moved)
221 m_pointer(std::move(src.m_pointer))
222 {}
223
225 Base& operator=(const Base& src)
226 {
227 if (this != &src) {
228 if (m_root != src.m_root) {
229 throw std::logic_error("Assignment from a different JSON document is not allowed.");
230 }
231 m_pointer = src.m_pointer;
232 }
233 return *this;
234 }
235
238 {
239 if (this != &src) {
240 if (m_root != src.m_root) {
241 throw std::logic_error("Assignment from a different JSON document is not allowed.");
242 }
243 m_pointer = std::move(src.m_pointer);
244 }
245 return *this;
246 }
247
250 std::string dump(int indents = -1)
251 {
252 return ref().dump(indents);
253 }
254
258 template <typename T>
259 T parent() const
260 {
261 static_assert(std::is_base_of_v<Base, T>, "Template type mush be derived from Base.");
262 return T(m_root, m_pointer.parent_pointer());
263 }
264
268 template <typename T>
269 std::optional<T> getEnclosingElement() const;
270
272 json_pointer pointer() const { return m_pointer; }
273
274protected:
280 json& ref() const { return resolve_pointer(); }
281
286 json& ref() { return resolve_pointer(); }
287
289 const std::shared_ptr<json>& root() const { return m_root; }
290
296 Base(const std::shared_ptr<json>& root, json_pointer pointer)
297 : m_root(root), m_pointer(std::move(pointer)) {}
298
305 Base(json&& jsonRef, Base& parent, const std::string_view& key)
306 : m_root(parent.m_root), m_pointer(parent.m_pointer / std::string(key))
307 {
308 (*m_root)[m_pointer] = std::move(jsonRef);
309 }
310
318 template <typename T>
319 T getChild(const std::string_view& key) const
320 {
321 static_assert(std::is_base_of_v<Base, T>, "template type must be derived from Base");
322
323 json_pointer childPointer = m_pointer / std::string(key);
324 if (!checkKeyIsValid<T>(childPointer)) {
325 throw std::runtime_error("Missing required child node: " + std::string(key));
326 }
327
328 return T(m_root, childPointer);
329 }
330
338 template <typename T>
339 T setChild(const std::string_view& key, const T& value)
340 {
341 static_assert(std::is_base_of_v<Base, T>, "template type must be derived from Base");
342
343 json_pointer childPointer = m_pointer / std::string(key);
344 (*m_root)[childPointer] = value.ref();
345 return T(m_root, childPointer);
346 }
347
355 template <typename T>
356 std::optional<T> getOptionalChild(const std::string_view& key) const
357 {
358 static_assert(std::is_base_of_v<Base, T>, "template type must be derived from Base");
359
360 json_pointer childPointer = m_pointer / std::string(key);
361 if (!checkKeyIsValid<T>(childPointer)) {
362 return std::nullopt;
363 }
364
365 return T(m_root, childPointer);
366 }
367
368private:
376 template <typename T>
377 bool checkKeyIsValid(const json_pointer& pointer) const
378 {
379 if (!(*m_root).contains(pointer)) {
380 return false;
381 }
382
383 const json& node = (*m_root).at(pointer);
384
385 if constexpr (std::is_base_of_v<Object, T>) {
386 if (!node.is_object()) {
387 throw std::runtime_error("Expected an object for: " + pointer.to_string());
388 }
389 } else if constexpr (std::is_base_of_v<Array<typename T::value_type>, T>) {
390 if (!node.is_array()) {
391 throw std::runtime_error("Expected an array for: " + pointer.to_string());
392 }
393 }
394
395 return true;
396 }
397
403 json& resolve_pointer() const
404 {
405 return (*m_root).at(m_pointer); // Throws if invalid
406 }
407
408 const std::shared_ptr<json> m_root;
409 json_pointer m_pointer;
410
411 friend class validation::SemanticValidator;
412};
413
415using ErrorHandler = std::function<void(const std::string& message, const Base& location)>;
416
420class Object : public Base
421{
422public:
426 Object(const std::shared_ptr<json>& root, json_pointer pointer) : Base(root, pointer)
427 {
428 if (!ref().is_object()) {
429 throw std::invalid_argument("mnx::Object must wrap a JSON object.");
430 }
431 }
432
436 Object(Base& parent, const std::string_view& key)
437 : Base(json::object(), parent, key) {}
438
439 MNX_OPTIONAL_PROPERTY(std::string, _c);
440 MNX_OPTIONAL_PROPERTY(std::string, id);
441};
442
445template <typename T, std::enable_if_t<!std::is_base_of_v<Base, T>, int> = 0>
446class SimpleType : public Base
447{
448 static_assert(std::is_arithmetic_v<T> || std::is_same_v<T, std::string>, "This template is for simple JSON classes");
449
450public:
451 using value_type = T;
452
456 SimpleType(const std::shared_ptr<json>& root, json_pointer pointer) : Base(root, pointer)
457 {
458 }
459
461 operator T() const
462 {
463 return ref().template get<T>();
464 }
465
468 SimpleType& operator=(const T& src)
469 {
470 ref() = src;
471 return *this;
472 }
473
475 bool operator==(const T& src) const
476 {
477 return src == ref().template get<T>();
478 }
479};
480
481class ArrayElementObject;
485template <typename T>
486class Array : public Base
487{
488 static_assert(std::is_arithmetic_v<T> || std::is_same_v<T, std::string> ||
489 std::is_base_of_v<ArrayElementObject, T>, "Invalid MNX array element type.");
490
491private:
492 template<typename ArrayType>
493 struct iter
494 {
495 private:
496 ArrayType* m_ptr;
497 mutable size_t m_idx;
498
499 public:
500 iter(ArrayType* ptr, size_t idx) : m_ptr(ptr), m_idx(idx) {}
501 T operator*() const { return (*m_ptr)[m_idx]; }
502 iter& operator++() { ++m_idx; return *this; }
503 bool operator!=(const iter& o) const { return m_idx != o.m_idx; }
504 };
505
506public:
508 using value_type = T;
509
510 using iterator = iter<Array>;
511 using const_iterator = iter<const Array>;
512
516 Array(const std::shared_ptr<json>& root, json_pointer pointer) : Base(root, pointer)
517 {
518 if (!ref().is_array()) {
519 throw std::invalid_argument("mnx::Array must wrap a JSON array.");
520 }
521 }
522
526 Array(Base& parent, const std::string_view& key)
527 : Base(json::array(), parent, key) {}
528
530 size_t size() const { return ref().size(); }
531
533 bool empty() const { return ref().empty(); }
534
536 void clear() { ref().clear(); }
537
539 auto operator[](size_t index) const
540 {
541 checkIndex(index);
542 if constexpr (std::is_base_of_v<Base, T>) {
543 return getChild<T>(std::to_string(index));
544 } else {
545 return getChild<SimpleType<T>>(std::to_string(index));
546 }
547 }
548
550 auto operator[](size_t index)
551 {
552 checkIndex(index);
553 if constexpr (std::is_base_of_v<Base, T>) {
554 return getChild<T>(std::to_string(index));
555 } else {
556 return getChild<SimpleType<T>>(std::to_string(index));
557 }
558 }
559
561 template <typename U = T>
562 std::enable_if_t<!std::is_base_of_v<Base, U>, void>
563 push_back(const U& value)
564 {
565 ref().push_back(value);
566 }
567
572 template <typename U = T, typename... Args,
573 std::enable_if_t<std::is_base_of_v<Base, U>, int> = 0>
574 U append(Args&&... args)
575 {
576 if constexpr (std::is_base_of_v<Object, U>) {
577 ref().push_back(json::object());
578 } else {
579 ref().push_back(json::array());
580 }
581 return U(*this, std::to_string(ref().size() - 1), std::forward<Args>(args)...);
582 }
583
585 void erase(size_t index)
586 {
587 checkIndex(index);
588 ref().erase(ref().begin() + index);
589 }
590
592 auto begin() { return iterator(this, 0); }
593
595 auto end() { return iterator(this, size()); }
596
598 auto begin() const { return const_iterator(this, 0); }
599
601 auto end() const { return const_iterator(this, size()); }
602
603protected:
606 void checkIndex(size_t index) const
607 {
608 assert(index < ref().size());
609 if (index >= ref().size()) {
610 throw std::out_of_range("Index out of range");
611 }
612 }
613};
614
619{
620public:
621 using Object::Object;
622
624 size_t calcArrayIndex() const
625 {
626 return std::stoul(pointer().back());
627 }
628
634 template <typename ContainerType>
635 ContainerType container() const
636 {
637 return parent<Array<ArrayElementObject>>().parent<ContainerType>();
638 }
639};
640
641class ContentArray;
644{
645protected:
646 static constexpr std::string_view ContentTypeValueDefault = "event";
647
648public:
649 using ArrayElementObject::ArrayElementObject;
650
652
654 template <typename T, std::enable_if_t<std::is_base_of_v<ContentObject, T>, int> = 0>
655 T get() const
656 {
657 return getTypedObject<T>();
658 }
659
660private:
663 template <typename T, std::enable_if_t<std::is_base_of_v<ContentObject, T>, int> = 0>
664 T getTypedObject() const
665 {
666 if (type() != T::ContentTypeValue) {
667 throw std::invalid_argument("Type mismatch: expected " + std::string(T::ContentTypeValue) +
668 ", got " + type());
669 }
670 return T(root(), pointer());
671 }
672
673 friend class ContentArray;
674};
675
703class ContentArray : public Array<ContentObject>
704{
705public:
707 using BaseArray::BaseArray; // Inherit constructors
708
710 template <typename T, std::enable_if_t<std::is_base_of_v<ContentObject, T>, int> = 0>
711 T get(size_t index) const
712 {
713 this->checkIndex(index);
714 return operator[](index).get<T>();
715 }
716
718 template <typename T, typename... Args,
719 std::enable_if_t<std::is_base_of_v<ContentObject, T>, int> = 0>
720 T append(Args&&... args)
721 {
722 auto result = BaseArray::append<T>(std::forward<Args>(args)...);
723 if constexpr (T::ContentTypeValue != ContentObject::ContentTypeValueDefault) {
724 result.set_type(std::string(T::ContentTypeValue));
725 }
726 return result;
727 }
728
729private:
732 template <typename T, std::enable_if_t<std::is_base_of_v<ContentObject, T>, int> = 0>
733 T getTypedObject(size_t index) const
734 {
735 this->checkIndex(index);
736 auto element = (*this)[index];
737 if (element.type() != T::ContentTypeValue) {
738 throw std::invalid_argument("Type mismatch: expected " + std::string(T::ContentTypeValue) +
739 ", got " + element.type());
740 }
741 return T(root(), pointer() / std::to_string(index));
742 }
743};
744
749template <typename E, typename = std::enable_if_t<std::is_enum_v<E>>>
751{
752 static const std::unordered_map<std::string, E> stringToEnum();
753
755 static const std::unordered_map<E, std::string> enumToString()
756 {
757 static const std::unordered_map<E, std::string> reverseMap = []() {
758 std::unordered_map<E, std::string> result;
759 for (const auto& element : EnumStringMapping<E>::stringToEnum()) {
760 result.emplace(element.second, element.first);
761 }
762 return result;
763 }();
764 return reverseMap;
765 }
766};
767
771template <typename T>
772class Dictionary : public Object
773{
774 static_assert(std::is_arithmetic_v<T> || std::is_same_v<T, std::string> ||
775 std::is_base_of_v<ArrayElementObject, T>, "Invalid MNX dictionary element type.");
776
777private:
778 template <typename DictionaryType, typename IteratorType>
779 struct iter
780 {
781 using value_type = std::pair<const std::string, T>;
782 using difference_type = std::ptrdiff_t;
783 using iterator_category = std::forward_iterator_tag;
784 using pointer = value_type*;
785 using reference = value_type&;
786
787 private:
788 DictionaryType* m_ptr;
789 IteratorType m_it;
790 mutable std::unique_ptr<value_type> m_pair; // Cached key-value pair for operator*() and operator->()
791
792 void update_pair() const {
793 m_pair.reset();
794 if (m_it != m_ptr->ref().end()) {
795 m_pair = std::make_unique<value_type>(m_it.key(), m_ptr->operator[](m_it.key()));
796 }
797 }
798
799 public:
800 iter(DictionaryType* ptr, IteratorType it) : m_ptr(ptr), m_it(it)
801 { update_pair(); }
802
803 reference operator*() const { return *m_pair.get(); }
804 pointer operator->() const { return m_pair.get(); }
805
806 iter& operator++() { ++m_it; update_pair(); return *this; }
807 iter operator++(int) { iter tmp = *this; ++(*this); return tmp; }
808
809 bool operator!=(const iter& o) const { return m_it != o.m_it; }
810 bool operator==(const iter& o) const { return m_it == o.m_it; }
811 };
812
813public:
815 using value_type = T;
816
817 using iterator = iter<Dictionary, json::iterator>;
818 using const_iterator = iter<const Dictionary, json::const_iterator>;
819
823 Dictionary(const std::shared_ptr<json>& root, json_pointer pointer)
825 {
826 }
827
831 Dictionary(Base& parent, const std::string_view& key)
832 : Object(parent, key) {}
833
835 size_t size() const { return ref().size(); }
836
838 bool empty() const { return ref().empty(); }
839
841 void clear() { ref().clear(); }
842
844 T operator[](const std::string& key) const
845 {
846 if constexpr (std::is_base_of_v<Base, T>) {
847 return getChild<T>(key);
848 } else {
849 return getChild<SimpleType<T>>(key);
850 }
851 }
852
854 auto operator[](const std::string& key)
855 {
856 if constexpr (std::is_base_of_v<Base, T>) {
857 return getChild<T>(key);
858 } else {
859 return getChild<SimpleType<T>>(key);
860 }
861 }
862
864 template <typename U = T>
865 std::enable_if_t<!std::is_base_of_v<Base, U>, void>
866 emplace(const std::string& key, const U& value)
867 {
868 ref()[key] = value;
869 }
870
875 template <typename U = T, typename... Args,
876 std::enable_if_t<std::is_base_of_v<Base, U>, int> = 0>
877 U append(const std::string& key, Args&&... args)
878 {
879 if constexpr (std::is_base_of_v<Object, U>) {
880 ref()[key] = json::object();
881 } else {
882 ref()[key] = json::array();
883 }
884 return U(*this, key, std::forward<Args>(args)...);
885 }
886
888 void erase(const std::string& key)
889 {
890 ref().erase(key);
891 }
892
896 auto find(const std::string& key)
897 {
898 auto it = ref().find(key);
899 return (it != ref().end()) ? iterator(this, it) : end();
900 }
901
905 auto find(const std::string& key) const
906 {
907 auto it = ref().find(key);
908 return (it != ref().end()) ? const_iterator(this, it) : end();
909 }
910
913 bool contains(const std::string& key) const
914 { return find(key) != end(); }
915
917 auto begin() { return iterator(this, ref().begin()); }
918
920 auto end() { return iterator(this, ref().end()); }
921
923 auto begin() const { return const_iterator(this, ref().begin()); }
924
926 auto end() const { return const_iterator(this, ref().end()); }
927};
928
929} // namespace mnx
930
931#ifndef DOXYGEN_SHOULD_IGNORE_THIS
932
933namespace nlohmann {
934
935#if defined(_WIN32)
936// This general adl_serializer is enabled only for enum types.
937// For some reason MSC does not like the direct function definitions below.
938template<typename EnumType>
939struct adl_serializer<EnumType, std::enable_if_t<std::is_enum_v<EnumType>>>
940{
941 template<typename BasicJsonType>
942 static EnumType from_json(const BasicJsonType& j)
943 {
944 // Lookup the string in the specialized map.
946 auto it = map.find(j.get<std::string>());
947 if (it != map.end()) {
948 return it->second;
949 }
951 return EnumType{};
952 }
953
954 template<typename BasicJsonType>
955 static void to_json(BasicJsonType& j, const EnumType& value)
956 {
958 auto it = map.find(value);
959 if (it == map.end()) {
961 j = BasicJsonType();
962 return;
963 }
964 j = it->second;
965 }
966};
967#else
968// Clang works with the adl_specialization above, but GCC does not.
969namespace detail {
970
971template<typename BasicJsonType, typename EnumType,
972 std::enable_if_t<std::is_enum<EnumType>::value, int> = 0>
973inline void from_json(const BasicJsonType& j, EnumType& value)
974{
975 // Lookup the string in the specialized map.
977 auto it = map.find(j.template get<std::string>());
978 if (it != map.end()) {
979 value = it->second;
980 } else {
982 value = EnumType{};
983 }
984}
985
986template<typename BasicJsonType, typename EnumType,
987 std::enable_if_t<std::is_enum<EnumType>::value, int> = 0>
988inline void to_json(BasicJsonType& j, EnumType value) noexcept
989{
991 auto it = map.find(value);
992 if (it != map.end()) {
993 j = it->second;
994 } else {
996 j = BasicJsonType();
997 }
998}
999
1000} // namespace detail
1001#endif // defined(_WIN32)
1002
1003} // namespace nlohmann
1004
1005#endif // DOXYGEN_SHOULD_IGNORE_THIS
Represents an MNX object that is included as an array element.
Definition BaseTypes.h:619
ContainerType container() const
Returns the container of the array this element belongs to wrapped as the specified template type.
Definition BaseTypes.h:635
size_t calcArrayIndex() const
Calculates the array index of the current instance within the array.
Definition BaseTypes.h:624
Represents an MNX array, encapsulating property access.
Definition BaseTypes.h:487
void checkIndex(size_t index) const
validates that an index is not out of range
Definition BaseTypes.h:606
auto begin()
Returns an iterator to the beginning of the array.
Definition BaseTypes.h:592
size_t size() const
Get the size of the array.
Definition BaseTypes.h:530
bool empty() const
Check if the array is empty.
Definition BaseTypes.h:533
iter< Array > iterator
non-const iterator type
Definition BaseTypes.h:510
iter< const Array > const_iterator
const iterator type
Definition BaseTypes.h:511
T value_type
The type for elements in this Array.
Definition BaseTypes.h:508
auto operator[](size_t index) const
const operator[]
Definition BaseTypes.h:539
auto begin() const
Returns a const iterator to the beginning of the array.
Definition BaseTypes.h:598
void erase(size_t index)
Remove an element at a given index.
Definition BaseTypes.h:585
auto end()
Returns an iterator to the end of the array.
Definition BaseTypes.h:595
void clear()
Clear all elements.
Definition BaseTypes.h:536
Array(const std::shared_ptr< json > &root, json_pointer pointer)
Wraps an Array class around an existing JSON array node.
Definition BaseTypes.h:516
std::enable_if_t<!std::is_base_of_v< Base, U >, void > push_back(const U &value)
Append a new value to the array. (Available only for primitive types)
Definition BaseTypes.h:563
U append(Args &&... args)
Create a new element at the end of the array. (Available only for Base types)
Definition BaseTypes.h:574
auto end() const
Returns a const iterator to the end of the array.
Definition BaseTypes.h:601
auto operator[](size_t index)
non-const operator[]
Definition BaseTypes.h:550
Array(Base &parent, const std::string_view &key)
Creates a new Array class as a child of a JSON node.
Definition BaseTypes.h:526
Base class wrapper for all MNX JSON nodes.
Definition BaseTypes.h:211
json & ref() const
Convert this node for retrieval.
Definition BaseTypes.h:280
std::optional< T > getEnclosingElement() const
Returns the enclosing array element for this instance.
Definition Implementations.cpp:54
std::string dump(int indents=-1)
Dumps the branch to a string. Useful in debugging.
Definition BaseTypes.h:250
T getChild(const std::string_view &key) const
Retrieves and validates a required child node.
Definition BaseTypes.h:319
json_pointer pointer() const
Returns the json_pointer for this node.
Definition BaseTypes.h:272
Base(json &&jsonRef, Base &parent, const std::string_view &key)
Construct a Base reference as a child inside a parent node.
Definition BaseTypes.h:305
Base(const std::shared_ptr< json > &root, json_pointer pointer)
Wrap a Base instance around a specific JSON reference using a json_pointer.
Definition BaseTypes.h:296
T setChild(const std::string_view &key, const T &value)
Sets a child node.
Definition BaseTypes.h:339
T parent() const
Returns the parent object for this node.
Definition BaseTypes.h:259
json & ref()
Access the JSON node for modification.
Definition BaseTypes.h:286
std::optional< T > getOptionalChild(const std::string_view &key) const
Retrieves an optional child node.
Definition BaseTypes.h:356
Base(const Base &src)
Copy constructor.
Definition BaseTypes.h:216
Base & operator=(const Base &src)
Copy assignment operator.
Definition BaseTypes.h:225
Base(Base &&src) noexcept
Move constructor.
Definition BaseTypes.h:220
Base & operator=(Base &&src)
Move assignment operator.
Definition BaseTypes.h:237
const std::shared_ptr< json > & root() const
Returns the root.
Definition BaseTypes.h:289
Class for content arrays.
Definition BaseTypes.h:704
T get(size_t index) const
Retrieve an element from the array as a specific type.
Definition BaseTypes.h:711
T append(Args &&... args)
Append an element of the specified type.
Definition BaseTypes.h:720
Base class for objects that are elements of content arrays.
Definition BaseTypes.h:644
MNX_OPTIONAL_PROPERTY_WITH_DEFAULT(std::string, type, std::string(ContentTypeValueDefault))
determines our type in the JSON
static constexpr std::string_view ContentTypeValueDefault
default type value that identifies the type within the content array
Definition BaseTypes.h:646
T get() const
Retrieve an element as a specific type.
Definition BaseTypes.h:655
Represents an MNX dictionary, where each key is a user-defined string.
Definition BaseTypes.h:773
iter< Dictionary, json::iterator > iterator
non-const iterator type
Definition BaseTypes.h:817
auto operator[](const std::string &key)
non-const operator[]
Definition BaseTypes.h:854
size_t size() const
Get the size of the array.
Definition BaseTypes.h:835
auto end() const
Returns a const iterator to the end of the dictionary.
Definition BaseTypes.h:926
auto begin() const
Returns a const iterator to the beginning of the dictionary.
Definition BaseTypes.h:923
auto find(const std::string &key) const
Finds an element by key and returns a const iterator.
Definition BaseTypes.h:905
U append(const std::string &key, Args &&... args)
Create a new element using the input key. (Available only for Base types)
Definition BaseTypes.h:877
void erase(const std::string &key)
Remove an element at a given key.
Definition BaseTypes.h:888
iter< const Dictionary, json::const_iterator > const_iterator
const iterator type
Definition BaseTypes.h:818
bool contains(const std::string &key) const
Returns true if the key exists in in the dictionary.
Definition BaseTypes.h:913
T operator[](const std::string &key) const
const operator[]
Definition BaseTypes.h:844
T value_type
The type for elements in this Array.
Definition BaseTypes.h:815
auto begin()
Returns an iterator to the beginning of the dictionary.
Definition BaseTypes.h:917
bool empty() const
Check if the array is empty.
Definition BaseTypes.h:838
std::enable_if_t<!std::is_base_of_v< Base, U >, void > emplace(const std::string &key, const U &value)
Add a new value to the dictonary. (Available only for primitive types)
Definition BaseTypes.h:866
Dictionary(Base &parent, const std::string_view &key)
Creates a new Dictionary class as a child of a JSON node.
Definition BaseTypes.h:831
Dictionary(const std::shared_ptr< json > &root, json_pointer pointer)
Wraps an Dictionary class around an existing JSON node.
Definition BaseTypes.h:823
auto end()
Returns an iterator to the end of the dictionary.
Definition BaseTypes.h:920
auto find(const std::string &key)
Finds an element by key and returns an iterator.
Definition BaseTypes.h:896
void clear()
Clear all elements.
Definition BaseTypes.h:841
Represents an MNX object, encapsulating property access.
Definition BaseTypes.h:421
MNX_OPTIONAL_PROPERTY(std::string, _c)
An optional comment. This serves a similar function as XML or HTML comments.
Object(const std::shared_ptr< json > &root, json_pointer pointer)
Wraps an Object class around an existing JSON object node.
Definition BaseTypes.h:426
Object(Base &parent, const std::string_view &key)
Creates a new Object class as a child of a JSON node.
Definition BaseTypes.h:436
MNX_OPTIONAL_PROPERTY(std::string, id)
Uniquely identifies the object.
Allows access to a fundamental type (number, boolean, string) in a JSON node.
Definition BaseTypes.h:447
SimpleType(const std::shared_ptr< json > &root, json_pointer pointer)
Wraps a SimpleType class around an existing JSON object node.
Definition BaseTypes.h:456
bool operator==(const T &src) const
Equality comparison with value type.
Definition BaseTypes.h:475
T value_type
value type of this SimpleType
Definition BaseTypes.h:451
SimpleType & operator=(const T &src)
Allow assignment to underlying json reference.
Definition BaseTypes.h:468
object model for MNX format
std::function< void(const std::string &message, const Base &location)> ErrorHandler
Error handler type for reporting errors.
Definition BaseTypes.h:415
json::json_pointer json_pointer
JSON pointer class for MNX.
Definition BaseTypes.h:198
constexpr int MNX_VERSION
The MNX version for files generated by the DOM.
Definition BaseTypes.h:195
nlohmann::ordered_json json
JSON class for MNX.
Definition BaseTypes.h:197
Supplies enum string mappings to nlohmann json's serializer.
Definition BaseTypes.h:751
static const std::unordered_map< E, std::string > enumToString()
maps enum values to strings
Definition BaseTypes.h:755
static const std::unordered_map< std::string, E > stringToEnum()
maps strings to enum values