Branch data Line data Source code
1 : : /*
2 : : * The MIT License (MIT)
3 : : *
4 : : * Copyright (c) 2024 Yaroslav Riabtsev <yaroslav.riabtsev@rwth-aachen.de>
5 : : *
6 : : * Permission is hereby granted, free of charge, to any person obtaining a copy
7 : : * of this software and associated documentation files (the "Software"), to deal
8 : : * in the Software without restriction, including without limitation the rights
9 : : * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 : : * copies of the Software, and to permit persons to whom the Software is
11 : : * furnished to do so, subject to the following conditions:
12 : : *
13 : : * The above copyright notice and this permission notice shall be included
14 : : * in all copies or substantial portions of the Software.
15 : : *
16 : : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 : : * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 : : * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
19 : : * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 : : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 : : * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 : : * SOFTWARE.
23 : : */
24 : :
25 : : #include "reference.hpp"
26 : :
27 : : #include <ranges>
28 : :
29 : 96 : reference_lib::json_reference::json_reference(const ref_head_type type)
30 [ + - ]: 96 : : head_type(type) { }
31 : :
32 : 182 : reference_lib::json_reference::json_reference(const std::shared_ptr<json>& head)
33 : 182 : : head_type(ref_head_type::object)
34 [ + - ]: 182 : , head(head) { }
35 : :
36 : 8 : reference_lib::json_set::json_set(
37 : : const std::vector<std::shared_ptr<json_reference>>& elements
38 : 8 : )
39 [ + - ]: 8 : : elements(elements) {
40 : 8 : _reference_type = json_reference_type::set_json;
41 : 8 : set_head_type(ref_head_type::accessor);
42 : 8 : }
43 : :
44 : 12 : reference_lib::json_function::json_function(std::string name)
45 : 12 : : name(std::move(name)) {
46 : 12 : _reference_type = json_reference_type::function_json;
47 : 12 : }
48 : :
49 : 179 : json_lib::json_type reference_lib::json_reference::type() const {
50 : 179 : return json_lib::json_type::reference_json;
51 : : }
52 : :
53 : 68 : std::string reference_lib::json_reference::indented_string(
54 : : const size_t indent_level, const bool pretty
55 : : ) const {
56 : 68 : std::string result;
57 [ + + + + ]: 68 : switch (head_type) {
58 : 29 : case ref_head_type::object:
59 [ + - + - ]: 29 : result += head->indented_string(indent_level, pretty);
60 : 29 : break;
61 : 1 : case ref_head_type::local:
62 [ + - ]: 1 : result += "@";
63 : 1 : break;
64 : 28 : case ref_head_type::root:
65 [ + - ]: 28 : result += "$";
66 : 28 : break;
67 : 68 : default:;
68 : : // result += "+";
69 : : }
70 [ + - + - ]: 68 : result += tail_to_string();
71 : 68 : return result;
72 : 0 : }
73 : :
74 : 8 : std::string reference_lib::json_set::indented_string(size_t, bool) const {
75 : 8 : std::string result;
76 [ + + ]: 39 : for (const auto& element : elements) {
77 [ + + ]: 31 : if (!result.empty()) {
78 [ + - ]: 23 : result += ", ";
79 : : }
80 [ + - + - ]: 31 : result += element->to_string();
81 : : }
82 [ + + ]: 8 : if (get_head_type() == ref_head_type::set) {
83 [ + - + - ]: 6 : result = '[' + result + ']';
84 : : } else {
85 [ + - + - ]: 2 : result = '{' + result + '}';
86 : : }
87 [ + - + - ]: 8 : result += tail_to_string();
88 : 8 : return result;
89 : 0 : }
90 : :
91 : 9 : std::string reference_lib::json_function::indented_string(size_t, bool) const {
92 : 9 : std::string result;
93 [ + + ]: 25 : for (const auto& arg : args) {
94 [ + + ]: 16 : if (!result.empty()) {
95 [ + - ]: 8 : result += ", ";
96 : : }
97 [ + - + - ]: 16 : result += arg->to_string();
98 : : }
99 [ + - + - : 9 : result = name + '(' + result + ')';
+ - ]
100 [ + - + - ]: 9 : result += tail_to_string();
101 : 9 : return result;
102 : 0 : }
103 : :
104 : 85 : std::string reference_lib::json_reference::tail_to_string() const {
105 : 85 : std::string result;
106 [ + + ]: 154 : for (const auto& accessor : tail) {
107 [ + - ]: 69 : std::string suffix = accessor->to_string();
108 [ + - + + ]: 69 : if (accessor->type() == json_lib::json_type::reference_json) {
109 [ + + ]: 20 : if (std::dynamic_pointer_cast<json_reference>(accessor)
110 [ + - ]: 10 : ->reference_type()
111 : 10 : == json_reference_type::set_json) {
112 [ + - ]: 2 : result += suffix;
113 : 2 : continue;
114 : : }
115 : : }
116 [ + - + - : 67 : result += "[" + suffix + ']';
+ - ]
117 [ + + ]: 69 : }
118 : 85 : return result;
119 : 0 : }
120 : :
121 : 8 : void reference_lib::json_reference::touch() {
122 [ - + ]: 8 : if (head_type == ref_head_type::object) {
123 : 0 : head->touch();
124 : : }
125 [ + + ]: 11 : for (const auto& accessor : tail) {
126 [ + - ]: 3 : accessor->touch();
127 : : }
128 : 8 : }
129 : :
130 : 0 : void reference_lib::json_set::touch() {
131 [ # # ]: 0 : for (const auto& element : elements) {
132 [ # # ]: 0 : element->touch();
133 : : }
134 : 0 : }
135 : :
136 : 19 : void reference_lib::json_reference::set_root(const std::shared_ptr<json>& item
137 : : ) {
138 [ + + ]: 68 : for (const auto& accessor : tail) {
139 [ + - ]: 49 : accessor->set_root(item);
140 : : }
141 [ + + ]: 19 : if (head_type == ref_head_type::root) {
142 : 12 : head = item;
143 : 12 : head_type = ref_head_type::object;
144 : 12 : simplify();
145 : : }
146 : 19 : }
147 : :
148 : 2 : void reference_lib::json_set::set_root(const std::shared_ptr<json>& item) {
149 [ + + ]: 8 : for (const auto& element : elements) {
150 [ + - ]: 6 : element->set_root(item);
151 : : }
152 : 2 : }
153 : :
154 : 4 : void reference_lib::json_function::set_root(const std::shared_ptr<json>& item) {
155 [ + + ]: 9 : for (const auto& arg : args) {
156 [ + - ]: 5 : arg->set_root(item);
157 : : }
158 : 4 : }
159 : :
160 : : reference_lib::json_reference_type
161 : 30 : reference_lib::json_reference::reference_type() const {
162 : 30 : return _reference_type;
163 : : }
164 : :
165 : 166 : void reference_lib::json_reference::emplace_back(
166 : : const std::shared_ptr<json>& accessor
167 : : ) {
168 [ + + - + ]: 166 : const bool abstract = head_type != ref_head_type::object || length() > 0;
169 : 166 : tail.emplace_back(accessor);
170 [ + + ]: 166 : if (!abstract) {
171 : 47 : simplify();
172 : : }
173 : 160 : }
174 : :
175 : 5 : void reference_lib::json_set::emplace_back(const std::shared_ptr<json>& item) {
176 [ + + ]: 23 : for (const auto& element : elements) {
177 [ + - ]: 18 : element->emplace_back(item);
178 : : }
179 : 5 : }
180 : :
181 : 12 : void reference_lib::json_function::set_args(
182 : : const std::vector<std::shared_ptr<json>>& args
183 : : ) {
184 [ + + ]: 35 : for (const auto& arg : args) {
185 [ + - + + ]: 23 : if (arg->type() == json_lib::json_type::reference_json) {
186 : 7 : if (const auto ref_arg
187 : 7 : = std::dynamic_pointer_cast<json_reference>(arg);
188 [ + - ]: 7 : ref_arg->length() == 0
189 [ + + - + : 7 : && ref_arg->get_head_type() == ref_head_type::local) {
- + ]
190 [ # # ]: 0 : throw std::invalid_argument("recursive function");
191 : 7 : }
192 : : }
193 : : }
194 : 12 : this->args = args;
195 : 12 : }
196 : :
197 : 20 : std::shared_ptr<json_lib::json> reference_lib::json_function::value() {
198 [ + + ]: 20 : if (name == "size") {
199 [ + + ]: 8 : if (args.size() != 1) {
200 [ + - ]: 1 : return std::make_shared<json_lib::json_integer>(args.size());
201 : : }
202 [ + + ]: 7 : if (args[0]->type() == json_lib::json_type::reference_json) {
203 : 6 : args[0]
204 [ + - ]: 12 : = std::dynamic_pointer_cast<json_reference>(args[0])->value();
205 : : }
206 [ + + ]: 7 : if (args[0]->type() == json_lib::json_type::array_json) {
207 : 2 : return std::make_shared<json_lib::json_integer>(
208 [ + - + - ]: 4 : std::dynamic_pointer_cast<json_lib::json_array>(args[0])->size()
209 : 2 : );
210 : : }
211 [ + + ]: 5 : if (args[0]->type() == json_lib::json_type::object_json) {
212 : 1 : return std::make_shared<json_lib::json_integer>(
213 [ + - + - ]: 2 : std::dynamic_pointer_cast<json_lib::json_object>(args[0])->size(
214 : : )
215 : 1 : );
216 : : }
217 [ + + + + : 12 : } else if (name == "min" || name == "max") {
+ + ]
218 [ - + ]: 7 : if (args.empty()) {
219 : : throw std::invalid_argument(
220 [ # # ]: 0 : "trying to calculate `" + name + "()` of empty array"
221 [ # # # # ]: 0 : );
222 : : }
223 [ + - ]: 7 : const bool is_max = (name == "max");
224 : 7 : int result = -1;
225 [ + + ]: 7 : if (args.size() == 1) {
226 [ + - + - ]: 3 : if (args[0]->type() == json_lib::json_type::reference_json) {
227 : 3 : args[0]
228 [ + - ]: 6 : = std::dynamic_pointer_cast<json_reference>(args[0])->value(
229 : 3 : );
230 : : }
231 [ + - + + ]: 3 : if (args[0]->type() == json_lib::json_type::reference_json) {
232 [ + - ]: 2 : return shared_from_this();
233 : : }
234 [ + - + - ]: 1 : if (args[0]->type() == json_lib::json_type::array_json) {
235 : : const auto arr
236 : 1 : = std::dynamic_pointer_cast<json_lib::json_array>(args[0]);
237 [ + - ]: 1 : const int sz = static_cast<int>(arr->size());
238 [ - + ]: 1 : if (sz == 0) {
239 : : throw std::invalid_argument(
240 [ # # ]: 0 : "trying to calculate `" + name + "()` of empty array"
241 [ # # # # ]: 0 : );
242 : : }
243 [ + + ]: 3 : for (int i = 0; i < sz; ++i) {
244 [ + - ]: 2 : auto item = arr->at(i);
245 [ + - - + ]: 2 : if (item->type() == json_lib::json_type::reference_json) {
246 : 0 : item = std::dynamic_pointer_cast<json_reference>(item)
247 [ # # ]: 0 : ->value();
248 : : }
249 [ + - - + ]: 2 : if (item->type() == json_lib::json_type::reference_json) {
250 [ # # ]: 0 : return shared_from_this();
251 : : }
252 [ + - - + ]: 2 : if (item->type() != json_lib::json_type::integer_json) {
253 : : throw std::invalid_argument(
254 : 0 : "trying to calculate `" + name
255 [ # # ]: 0 : + "()` of not integer"
256 [ # # # # ]: 0 : );
257 : : }
258 : : const int val
259 : 2 : = std::dynamic_pointer_cast<json_lib::json_integer>(item
260 : : )
261 [ + - ]: 2 : ->as_index();
262 [ + + - + : 2 : if (i == 0 || (is_max && val > result)
- - ]
263 [ + - - + ]: 1 : || (!is_max && val < result)) {
264 : 1 : result = val;
265 : : }
266 [ + - ]: 2 : }
267 [ + - ]: 1 : }
268 : : } else {
269 [ + + ]: 8 : for (size_t i = 0; i < args.size(); ++i) {
270 : 6 : auto item = args[i];
271 [ + - + + ]: 6 : if (item->type() == json_lib::json_type::reference_json) {
272 : 8 : item = std::dynamic_pointer_cast<json_reference>(item)
273 [ + - ]: 8 : ->value();
274 : : }
275 [ + - + + ]: 6 : if (item->type() == json_lib::json_type::reference_json) {
276 [ + - ]: 2 : return shared_from_this();
277 : : }
278 [ + - - + ]: 4 : if (item->type() != json_lib::json_type::integer_json) {
279 : : throw std::invalid_argument(
280 [ # # ]: 0 : "trying to calculate `" + name + "()` of not integer"
281 [ # # # # ]: 0 : );
282 : : }
283 : : const int val
284 : 4 : = std::dynamic_pointer_cast<json_lib::json_integer>(item)
285 [ + - ]: 4 : ->as_index();
286 [ + + + - : 4 : if (i == 0 || (is_max && val > result)
- + ]
287 [ # # # # ]: 0 : || (!is_max && val < result)) {
288 : 4 : result = val;
289 : : }
290 [ + + ]: 6 : }
291 : : }
292 [ + - ]: 3 : return std::make_shared<json_lib::json_integer>(result);
293 : : }
294 : 9 : return shared_from_this();
295 : : }
296 : :
297 : 40 : void reference_lib::json_reference::set_parent(
298 : : const std::shared_ptr<json>& local
299 : : ) {
300 [ + + ]: 40 : if (head_type == ref_head_type::local
301 [ + + ]: 31 : || head_type == ref_head_type::accessor) {
302 : : // todo: update_head(local);
303 : 30 : head = local;
304 : 30 : head_type = ref_head_type::object;
305 : 30 : simplify();
306 : : }
307 : 40 : }
308 : :
309 : 6 : void reference_lib::json_set::set_parent(const std::shared_ptr<json>& local) {
310 [ + + ]: 27 : for (const auto& element : elements) {
311 [ + - ]: 21 : element->set_parent(local);
312 : : }
313 : 6 : set_head_type(ref_head_type::set);
314 : 6 : }
315 : :
316 : 4 : void reference_lib::json_function::set_parent(const std::shared_ptr<json>& local
317 : : ) {
318 [ + + ]: 9 : for (auto& arg : args) {
319 [ + - + - ]: 5 : if (arg->type() == json_lib::json_type::reference_json) {
320 : 5 : const auto ref_arg = std::dynamic_pointer_cast<json_reference>(arg);
321 [ + - ]: 5 : ref_arg->set_parent(local);
322 [ + - ]: 5 : arg = ref_arg->value();
323 : 5 : }
324 : : }
325 : 4 : }
326 : :
327 : 537 : size_t reference_lib::json_reference::length() const { return tail.size(); }
328 : :
329 : 270 : std::shared_ptr<json_lib::json> reference_lib::json_reference::value() {
330 [ + + + + : 270 : if (length() > 0 || head_type != ref_head_type::object) {
+ + ]
331 : 81 : return shared_from_this();
332 : : }
333 [ + + ]: 189 : if (head->type() != json_lib::json_type::reference_json) {
334 : 183 : return head;
335 : : }
336 [ + - ]: 6 : return std::dynamic_pointer_cast<json_reference>(head)->value();
337 : : }
338 : :
339 : : reference_lib::ref_head_type
340 : 18 : reference_lib::json_reference::get_head_type() const {
341 : 18 : return head_type;
342 : : }
343 : :
344 : 89 : void reference_lib::json_reference::simplify() {
345 [ + - + + : 193 : while (head_type == ref_head_type::object && length() > 0) {
+ + ]
346 : 116 : auto accessor = tail.front();
347 [ + - + + ]: 116 : if (head->type() == json_lib::json_type::reference_json) {
348 : 6 : tail.pop_front();
349 : : const auto ref_head
350 : 6 : = std::dynamic_pointer_cast<json_reference>(head);
351 [ + - ]: 6 : ref_head->emplace_back(accessor);
352 [ + - ]: 6 : head = ref_head->value();
353 : 6 : } else {
354 [ + - + + ]: 110 : if (accessor->type() == json_lib::json_type::reference_json) {
355 : : const auto ref_accessor
356 : 15 : = std::dynamic_pointer_cast<json_reference>(accessor);
357 [ + - + + : 15 : switch (ref_accessor->reference_type()) {
- - ]
358 : 9 : case json_reference_type::reference_json: {
359 [ + + ]: 9 : if (ref_accessor->get_head_type() == ref_head_type::root) {
360 : 6 : return;
361 : : }
362 [ + - ]: 3 : ref_accessor->set_parent(head);
363 [ + - ]: 3 : tail.front() = ref_accessor->value();
364 : 3 : break;
365 : : }
366 : 6 : case json_reference_type::set_json: {
367 : 12 : std::dynamic_pointer_cast<json_set>(ref_accessor)
368 [ + - ]: 6 : ->set_parent(head);
369 [ + - ]: 6 : head = ref_accessor->value();
370 : 6 : tail.pop_front();
371 : 6 : break;
372 : : }
373 : 0 : case json_reference_type::function_json: {
374 : : // todo
375 : 0 : return;
376 : : }
377 : 0 : default: {
378 [ # # ]: 0 : throw std::runtime_error("unsupported accessor type");
379 : : }
380 : : }
381 [ + + ]: 15 : } else {
382 [ + + ]: 95 : head = head->by(accessor);
383 : 89 : tail.pop_front();
384 : : }
385 : : }
386 [ + + ]: 116 : }
387 : : }
388 : :
389 : 14 : void reference_lib::json_reference::set_head_type(const ref_head_type type) {
390 : 14 : head_type = type;
391 : 14 : }
|