-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathjson_object.cpp
More file actions
209 lines (174 loc) · 6.29 KB
/
json_object.cpp
File metadata and controls
209 lines (174 loc) · 6.29 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
/*
* JsonObject
**/
#include <string>
#include <iostream>
#include <list>
#include <map>
#include <vector>
#include <variant>
#include <sstream>
#include <cassert>
using tName = std::string;
using tElementPos = long;
using tElementString = std::string;
using tElementNumber = long;
using tElementBool = bool;
/**
* Json Object Class
*/
class JsonObject {
struct tElement;
using tElements = std::map<tName, tElement>;
/*
* tElement node storage
*/
struct tElement { //FF collapse JsonObject and tElement
using tElementData = std::variant<tElementNumber, tElementString, tElementBool, tElements>;
//Construct from { x : y, z : { a: b} } format
tElement(std::initializer_list<std::pair<tName, tElement>> il) : node{ std::in_place_type<tElements> } {
tElements& t = std::get<tElements>(node);
for ( const auto& p : il )
t.insert(p);
}
template<typename T>
tElement(const T& x) : node(x) {} //forward this? not reference
tElement& operator[](const tName& name) {
if (std::holds_alternative<tElements>(node)) {
return std::get<tElements>(node).at(name);
}
throw std::invalid_argument(name); //empty/null or error?
}
tElementData node;
};
/**
* Helper to visit variant and return string from element
*/
struct StringifyVistor {
std::string operator()(const tElementNumber x) const {
return std::to_string(x);
}
std::string operator()(const tElementBool x) const {
return std::string((x ? "true" : "false"));
}
std::string operator()(const tElementString& x) const {
std::stringstream ss;
ss << '"' << x << '"';
return ss.str();
}
std::string operator()(const tElements& x) const {
std::stringstream ss;
ss << "{ ";
for( bool first{true}; const auto& [k,v] : x ) { //c++20 init stateuemnt
ss << (first ? first=false, " " : ", ") << k << ": " << std::visit(*this, v.node);
}
ss << " }";
return ss.str();
}
};
public:
JsonObject() {}
JsonObject(std::initializer_list<std::pair<tName, tElement>> il) { //Note best practice to pass IL by value
for ( const auto& p : il )
elements.insert(p);
}
void add(std::initializer_list<std::pair<tName, tElement>> il) {
for ( const auto& p : il )
elements.insert(p);
}
void add(const tName& name,std::initializer_list<std::pair<tName, tElement>> il) {
tElements e;
for ( const auto& p : il )
e.insert(p);
elements.emplace(name, std::move(e));
}
template<typename T>
void add(const tName& name, T&& value) { //Note && is forwarding reference because T is template type
elements.emplace(name, tElement{std::forward<T>(value)}); //avoiding copy / move - emplace directly into right memory location
}
//Get element for edit print
tElement& operator[](const tName& name) {
return elements.at(name);
}
const tElement& operator[](const tName& name) const {
return elements.at(name);
}
//ostream support friends
friend std::ostream& operator<<(std::ostream& o, const JsonObject& j);
friend std::ostream& operator<<(std::ostream& o, const tElement& j);
private:
tElements elements;
};
//Friend of JsonObject
std::ostream& operator<<(std::ostream& o, const JsonObject& j) {
o << "jsonObject: {";
for( bool first{true}; const auto& [k,v] : j.elements ) {
o << (first ? first=false, " " : ", ") << k << ": " << std::visit(JsonObject::StringifyVistor{}, v.node);
}
o << " }";
return o;
}
//Friend of JsonObject
std::ostream& operator<<(std::ostream& o, const JsonObject::tElement& e) {
o << std::visit(JsonObject::StringifyVistor{}, e.node);
return o;
}
/**
* main
*/
int main() {
//Test A
std::cout << "\n*** Test A - add, alter, print" << std::endl;
{
//Create and add values of various types
JsonObject a;
a.add("myelement0", 123L);
a.add("myelement1", 456L);
a.add("myelement2", std::string{"myvalue1"});
a.add("myelement3", false);
std::cout << "Lookup with []: " << a["myelement0"] << "," << a["myelement1"] << ","
<< a["myelement2"] << "," << a["myelement3"] << std::endl;
std::cout << "Json object to string: " << a << std::endl;
std::cout << "Alter elements:" << std::endl;
a["myelement3"] = 10L;
a["myelement0"] = "convert";
std::cout << a << std::endl;
auto s = std::string{"myvalue1"};
a.add("myelement4", s); //test L-value passing to move
}
//Test B
std::cout << "\n*** Test B - initialiser list ctor" << std::endl;
{
JsonObject b = {
{"mylong", 1234L}, {"mybool", false}, {"mystring", "test"}, {"mystring2", "test2"}
};
std::cout << "Json object to string: " << b << std::endl;
}
//Test C
std::cout << "\n*** Test C - deeper structures" << std::endl;
{
//construct with sub-elements
JsonObject c = {
{"mylong", 1234L},
{ "subnode1", { { "sub1", 1L }, { "sub2", "blah" }, { "sub3", false } } },
{"mybool", false},
};
//access sub-elements
std::cout << "Get subelement using []: " << c["subnode1"]["sub1"] << std::endl;
std::cout << "Get subelement using []: " << c["subnode1"]["sub2"] << std::endl;
//assert(c["subnode1"]["sub2"] == "blah"); can't compare yet
//update sub-elements
c["subnode1"]["sub3"] = true;
//auto x = c["subnode1"]["sub3"];
//assert(std::get<bool>(x.node)=="true"); //BUG returning 1 not true
//add node using full IL
c.add({{"sn1", { { "se1A", 1L }, { "se1B", false } }}});
//add node using name and IL
c.add("sn2", { { "se2A", "blah" }, { "se2B", false } });
std::cout << "Json object to string: " << c << std::endl;
//Next thing: JSON array [][][] (vector)
//
//Next: Serialise and Deserliase multi-nested levels - "Recursive descent parser" good approach
//
}
}