11#pragma once
22
3- #include < cstdint>
4- #include < cstddef>
53#include < algorithm>
6- #include < string>
74#include < cstddef>
5+ #include < cstdint>
86#include < format>
7+ #include < string>
98#include < unordered_map>
9+ #include < functional>
10+ #include < concepts>
1011
1112namespace cppjson
1213{
@@ -22,7 +23,7 @@ namespace cppjson
2223
2324 class JsonObject
2425 {
25- public:
26+ public:
2627 explicit JsonObject ();
2728 ~JsonObject ();
2829
@@ -31,52 +32,105 @@ namespace cppjson
3132
3233 template <typename T>
3334 const T& As () const noexcept (false );
34- private:
35+
36+ private:
3537 JsonType _dataType{};
3638 std::byte* _dataStorage{};
3739
3840 void Destroy ();
3941 template <typename T>
40- T& DangerousAs () noexcept { return *std::launder (reinterpret_cast <T*>(this ->_dataStorage )); }
42+ T& DangerousAs () noexcept
43+ {
44+ return *std::launder (reinterpret_cast <T*>(this ->_dataStorage ));
45+ }
4146 template <typename T>
42- const T& DangerousAs () const noexcept { return *std::launder (reinterpret_cast <T*>(this ->_dataStorage )); }
47+ const T& DangerousAs () const noexcept
48+ {
49+ return *std::launder (reinterpret_cast <T*>(this ->_dataStorage ));
50+ }
4351
4452 friend struct std ::formatter<cppjson::JsonObject>;
4553 };
4654
4755 class Object
4856 {
49- public:
57+ public:
5058 explicit Object () = default;
5159 Object (const Object&) = default ;
52- Object (Object&&) = default ;
60+ Object (Object&&) = default ;
5361 Object& operator =(const Object&) = default ;
5462 Object& operator =(Object&&) = default ;
5563 ~Object () = default ;
5664
57- template <typename T>
58- T& operator [](const std::string& key)
65+ class ObjectProxy
5966 {
60- return this ->_nodes [key].As <T>();
61- }
62- template <typename T>
63- const T& operator [](const std::string& key) const
67+ public:
68+ explicit ObjectProxy (JsonObject& object) : _object(std::ref(object)) {}
69+
70+ template <typename T>
71+ operator T&()
72+ {
73+ return this ->_object .get ().As <T>();
74+ }
75+
76+ template <typename T>
77+ operator const T&() const
78+ {
79+ return this ->_object .get ().As <T>();
80+ }
81+
82+ template <typename T>
83+ T& operator =(T&& assignment)
84+ {
85+ return static_cast <T&>(*this ) = std::forward<T>(assignment);
86+ }
87+
88+ template <std::size_t N>
89+ std::string& operator =(const char (&str)[N])
90+ {
91+ return static_cast <std::string&>(*this ) = std::string{ str };
92+ }
93+ private:
94+ std::reference_wrapper<JsonObject> _object;
95+ };
96+
97+
98+ class ConstObjectProxy
99+ {
100+ public:
101+ explicit ConstObjectProxy (const JsonObject& object) : _object(std::ref(object)) {}
102+ template <typename T>
103+ operator const T&() const
104+ {
105+ return this ->_object .get ().As <T>();
106+ }
107+ private:
108+ std::reference_wrapper<const JsonObject> _object;
109+ };
110+
111+ ObjectProxy operator [](const std::string& key)
112+ {
113+ return ObjectProxy{ this ->_nodes [key] };
114+ }
115+
116+ ConstObjectProxy operator [](const std::string& key) const
64117 {
65118 if (!this ->_nodes .contains (key)) throw std::logic_error (" Invalid key" + key);
66- return this ->_nodes .at (key).As <T>();
119+
120+ return ConstObjectProxy{ this ->_nodes .at (key) };
67121 }
68- private:
122+
123+ private:
69124 std::unordered_map<std::string, JsonObject> _nodes{};
125+
126+ friend struct std ::formatter<cppjson::Object>;
70127 };
71- }
128+ } // namespace cppjson
72129
73- template <>
130+ template <>
74131struct std ::formatter<cppjson::JsonObject>
75132{
76- constexpr auto parse (std::format_parse_context& context)
77- {
78- return context.begin ();
79- }
133+ constexpr auto parse (std::format_parse_context& context) { return context.begin (); }
80134
81135 auto format (const cppjson::JsonObject& object, std::format_context& context) const
82136 {
@@ -85,9 +139,32 @@ struct std::formatter<cppjson::JsonObject>
85139 case cppjson::JsonType::Null: return std::format_to (context.out (), " null" );
86140 case cppjson::JsonType::Bool: return std::format_to (context.out (), " {}" , object.DangerousAs <bool >());
87141 case cppjson::JsonType::Number: return std::format_to (context.out (), " {}" , object.DangerousAs <double >());
88- case cppjson::JsonType::String: return std::format_to (context.out (), " {} " , object.DangerousAs <std::string>());
142+ case cppjson::JsonType::String: return std::format_to (context.out (), " \" {} \" " , object.DangerousAs <std::string>());
89143 }
90144
91145 throw std::logic_error (" Unknown type" );
92146 }
93147};
148+
149+ template <>
150+ struct std ::formatter<cppjson::Object>
151+ {
152+ constexpr auto parse (std::format_parse_context& context) { return context.begin (); }
153+
154+ auto format (const cppjson::Object& object, std::format_context& context) const
155+ {
156+ std::string built = " { " ;
157+ for (const auto & [key, value] : object._nodes )
158+ built += std::format (" \" {}\" : {}, " , key, value);
159+
160+ if (!object._nodes .empty ()) // remove trailing commas
161+ {
162+ built.pop_back ();
163+ built.pop_back ();
164+ built += " }" ;
165+ }
166+ else built += " }" ;
167+
168+ return std::format_to (context.out (), " {}" , built);
169+ }
170+ };
0 commit comments