1 /*
2 * Copyright (c) 2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #ifndef API_UTIL_JSON_H
17 #define API_UTIL_JSON_H
18
19 #include <core/json/json.h>
20
21 #include <util/namespace.h>
22
23 UTIL_BEGIN_NAMESPACE()
24
25 constexpr int JSON_DEFAULT_INDENTATION = 2;
26
27 template<typename T>
28 BASE_NS::string to_formatted_string(const CORE_NS::json::value_t<T>& value,
29 const size_t indentation = JSON_DEFAULT_INDENTATION, const size_t currentIndentation = 0);
30
31 #ifdef JSON_IMPL
32 using namespace CORE_NS::json;
33
34 template<typename T>
append(BASE_NS::string& out, const typename value_t<T>::string& string)35 void append(BASE_NS::string& out, const typename value_t<T>::string& string)
36 {
37 out += '"';
38 out.append(escape(string));
39 out += '"';
40 }
41
42 template<typename T>
append(BASE_NS::string& out, const typename value_t<T>::object& object, const size_t indentation, size_t currentIndentation)43 void append(BASE_NS::string& out, const typename value_t<T>::object& object, const size_t indentation,
44 size_t currentIndentation)
45 {
46 if (object.empty()) {
47 // Keep empty objects on one row.
48 out.append("{}");
49 return;
50 }
51
52 out += "{\n";
53 currentIndentation += indentation;
54 out.append(currentIndentation, ' ');
55
56 int count = 0;
57 for (const auto& v : object) {
58 if (count++) {
59 out += ",\n";
60 out.append(currentIndentation, ' ');
61 }
62 append<T>(out, v.key);
63 out += ": ";
64 out += to_formatted_string(v.value, indentation, currentIndentation);
65 }
66 currentIndentation -= indentation;
67 out += '\n';
68 out.append(currentIndentation, ' ');
69 out += '}';
70 }
71
72 template<typename T>
append( BASE_NS::string& out, const typename value_t<T>::array& array, const size_t indentation, size_t currentIndentation)73 void append(
74 BASE_NS::string& out, const typename value_t<T>::array& array, const size_t indentation, size_t currentIndentation)
75 {
76 if (array.empty()) {
77 // Keep empty arrays on one row.
78 out.append("[]");
79 return;
80 }
81
82 out += "[\n";
83 currentIndentation += indentation;
84 out.append(currentIndentation, ' ');
85 int count = 0;
86 for (const auto& v : array) {
87 if (count++) {
88 out += ",\n";
89 out.append(currentIndentation, ' ');
90 }
91 out += to_formatted_string(v, indentation, currentIndentation);
92 }
93 currentIndentation -= indentation;
94 out += '\n';
95 out.append(currentIndentation, ' ');
96 out += ']';
97 }
98
99 template<typename T>
append(BASE_NS::string& out, const double floatingPoint)100 void append(BASE_NS::string& out, const double floatingPoint)
101 {
102 constexpr const char* FLOATING_FORMAT_STR = "%.17g";
103 const int size = snprintf(nullptr, 0, FLOATING_FORMAT_STR, floatingPoint);
104 const size_t oldSize = out.size();
105 out.resize(oldSize + size);
106 const size_t newSize = out.size();
107 // "At most bufsz - 1 characters are written." string has size() characters + 1 for null so use size() +
108 // 1 as the total size. If resize() failed string size() hasn't changed, buffer will point to the null
109 // character and bufsz will be 1 i.e. only the null character will be written.
110 }
111
112 template<typename T>
to_formatted_string(const value_t<T>& value, const size_t indentation, const size_t currentIndentation)113 BASE_NS::string to_formatted_string(const value_t<T>& value, const size_t indentation, const size_t currentIndentation)
114 {
115 BASE_NS::string out;
116 switch (value.type) {
117 case type::uninitialized:
118 out += "{}";
119 break;
120
121 case type::object:
122 append<T>(out, value.object_, indentation, currentIndentation);
123 break;
124
125 case type::array:
126 append<T>(out, value.array_, indentation, currentIndentation);
127 break;
128
129 case type::string:
130 append<T>(out, value.string_);
131 break;
132
133 case type::floating_point:
134 append<T>(out, value.float_);
135 break;
136
137 case type::signed_int:
138 out += BASE_NS::to_string(value.signed_);
139 break;
140
141 case type::unsigned_int:
142 out += BASE_NS::to_string(value.unsigned_);
143 break;
144
145 case type::boolean:
146 if (value.boolean_) {
147 out += "true";
148 } else {
149 out += "false";
150 }
151 break;
152
153 case type::null:
154 out += "null";
155 break;
156
157 default:
158 break;
159 }
160 return out;
161 }
162
163 // Explicit template instantiation for the needed types.
164 template BASE_NS::string to_formatted_string(
165 const value& value, const size_t indentation, const size_t currentIndentation);
166 template BASE_NS::string to_formatted_string(
167 const standalone_value& value, const size_t indentation, const size_t currentIndentation);
168
169 #endif // JSON_IMPL
170
171 UTIL_END_NAMESPACE()
172
173 #endif // API_UTIL_JSON_H
174