1 | #ifndef SIMDJSON_SERIALIZATION_H |
2 | #define SIMDJSON_SERIALIZATION_H |
3 | |
4 | #include "simdjson/common_defs.h" |
5 | #include "simdjson/dom/document.h" |
6 | #include "simdjson/error.h" |
7 | #include "simdjson/internal/dom_parser_implementation.h" |
8 | #include "simdjson/internal/tape_ref.h" |
9 | #include "simdjson/padded_string.h" |
10 | #include "simdjson/portability.h" |
11 | #include <vector> |
12 | |
13 | namespace simdjson { |
14 | |
15 | /** |
16 | * The string_builder template and mini_formatter class |
17 | * are not part of our public API and are subject to change |
18 | * at any time! |
19 | */ |
20 | namespace internal { |
21 | |
22 | class mini_formatter; |
23 | |
24 | /** |
25 | * @private The string_builder template allows us to construct |
26 | * a string from a document element. It is parametrized |
27 | * by a "formatter" which handles the details. Thus |
28 | * the string_builder template could support both minification |
29 | * and prettification, and various other tradeoffs. |
30 | */ |
31 | template <class formatter = mini_formatter> |
32 | class string_builder { |
33 | public: |
34 | /** Construct an initially empty builder, would print the empty string **/ |
35 | string_builder() = default; |
36 | /** Append an element to the builder (to be printed) **/ |
37 | inline void append(simdjson::dom::element value); |
38 | /** Append an array to the builder (to be printed) **/ |
39 | inline void append(simdjson::dom::array value); |
40 | /** Append an object to the builder (to be printed) **/ |
41 | inline void append(simdjson::dom::object value); |
42 | /** Reset the builder (so that it would print the empty string) **/ |
43 | simdjson_inline void clear(); |
44 | /** |
45 | * Get access to the string. The string_view is owned by the builder |
46 | * and it is invalid to use it after the string_builder has been |
47 | * destroyed. |
48 | * However you can make a copy of the string_view on memory that you |
49 | * own. |
50 | */ |
51 | simdjson_inline std::string_view str() const; |
52 | /** Append a key_value_pair to the builder (to be printed) **/ |
53 | simdjson_inline void append(simdjson::dom::key_value_pair value); |
54 | private: |
55 | formatter format{}; |
56 | }; |
57 | |
58 | /** |
59 | * @private This is the class that we expect to use with the string_builder |
60 | * template. It tries to produce a compact version of the JSON element |
61 | * as quickly as possible. |
62 | */ |
63 | class mini_formatter { |
64 | public: |
65 | mini_formatter() = default; |
66 | /** Add a comma **/ |
67 | simdjson_inline void comma(); |
68 | /** Start an array, prints [ **/ |
69 | simdjson_inline void start_array(); |
70 | /** End an array, prints ] **/ |
71 | simdjson_inline void end_array(); |
72 | /** Start an array, prints { **/ |
73 | simdjson_inline void start_object(); |
74 | /** Start an array, prints } **/ |
75 | simdjson_inline void end_object(); |
76 | /** Prints a true **/ |
77 | simdjson_inline void true_atom(); |
78 | /** Prints a false **/ |
79 | simdjson_inline void false_atom(); |
80 | /** Prints a null **/ |
81 | simdjson_inline void null_atom(); |
82 | /** Prints a number **/ |
83 | simdjson_inline void number(int64_t x); |
84 | /** Prints a number **/ |
85 | simdjson_inline void number(uint64_t x); |
86 | /** Prints a number **/ |
87 | simdjson_inline void number(double x); |
88 | /** Prints a key (string + colon) **/ |
89 | simdjson_inline void key(std::string_view unescaped); |
90 | /** Prints a string. The string is escaped as needed. **/ |
91 | simdjson_inline void string(std::string_view unescaped); |
92 | /** Clears out the content. **/ |
93 | simdjson_inline void clear(); |
94 | /** |
95 | * Get access to the buffer, it is owned by the instance, but |
96 | * the user can make a copy. |
97 | **/ |
98 | simdjson_inline std::string_view str() const; |
99 | |
100 | private: |
101 | // implementation details (subject to change) |
102 | /** Prints one character **/ |
103 | simdjson_inline void one_char(char c); |
104 | /** Backing buffer **/ |
105 | std::vector<char> buffer{}; // not ideal! |
106 | }; |
107 | |
108 | } // internal |
109 | |
110 | namespace dom { |
111 | |
112 | /** |
113 | * Print JSON to an output stream. |
114 | * |
115 | * @param out The output stream. |
116 | * @param value The element. |
117 | * @throw if there is an error with the underlying output stream. simdjson itself will not throw. |
118 | */ |
119 | inline std::ostream& operator<<(std::ostream& out, simdjson::dom::element value) { |
120 | simdjson::internal::string_builder<> sb; |
121 | sb.append(value); |
122 | return (out << sb.str()); |
123 | } |
124 | #if SIMDJSON_EXCEPTIONS |
125 | inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::dom::element> x) { |
126 | if (x.error()) { throw simdjson::simdjson_error(x.error()); } |
127 | return (out << x.value()); |
128 | } |
129 | #endif |
130 | /** |
131 | * Print JSON to an output stream. |
132 | * |
133 | * @param out The output stream. |
134 | * @param value The array. |
135 | * @throw if there is an error with the underlying output stream. simdjson itself will not throw. |
136 | */ |
137 | inline std::ostream& operator<<(std::ostream& out, simdjson::dom::array value) { |
138 | simdjson::internal::string_builder<> sb; |
139 | sb.append(value); |
140 | return (out << sb.str()); |
141 | } |
142 | #if SIMDJSON_EXCEPTIONS |
143 | inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::dom::array> x) { |
144 | if (x.error()) { throw simdjson::simdjson_error(x.error()); } |
145 | return (out << x.value()); |
146 | } |
147 | #endif |
148 | /** |
149 | * Print JSON to an output stream. |
150 | * |
151 | * @param out The output stream. |
152 | * @param value The object. |
153 | * @throw if there is an error with the underlying output stream. simdjson itself will not throw. |
154 | */ |
155 | inline std::ostream& operator<<(std::ostream& out, simdjson::dom::object value) { |
156 | simdjson::internal::string_builder<> sb; |
157 | sb.append(value); |
158 | return (out << sb.str()); |
159 | } |
160 | #if SIMDJSON_EXCEPTIONS |
161 | inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::dom::object> x) { |
162 | if (x.error()) { throw simdjson::simdjson_error(x.error()); } |
163 | return (out << x.value()); |
164 | } |
165 | #endif |
166 | } // namespace dom |
167 | |
168 | /** |
169 | * Converts JSON to a string. |
170 | * |
171 | * dom::parser parser; |
172 | * element doc = parser.parse(" [ 1 , 2 , 3 ] "_padded); |
173 | * cout << to_string(doc) << endl; // prints [1,2,3] |
174 | * |
175 | */ |
176 | template <class T> |
177 | std::string to_string(T x) { |
178 | // in C++, to_string is standard: http://www.cplusplus.com/reference/string/to_string/ |
179 | // Currently minify and to_string are identical but in the future, they may |
180 | // differ. |
181 | simdjson::internal::string_builder<> sb; |
182 | sb.append(x); |
183 | std::string_view answer = sb.str(); |
184 | return std::string(answer.data(), answer.size()); |
185 | } |
186 | #if SIMDJSON_EXCEPTIONS |
187 | template <class T> |
188 | std::string to_string(simdjson_result<T> x) { |
189 | if (x.error()) { throw simdjson_error(x.error()); } |
190 | return to_string(x.value()); |
191 | } |
192 | #endif |
193 | |
194 | /** |
195 | * Minifies a JSON element or document, printing the smallest possible valid JSON. |
196 | * |
197 | * dom::parser parser; |
198 | * element doc = parser.parse(" [ 1 , 2 , 3 ] "_padded); |
199 | * cout << minify(doc) << endl; // prints [1,2,3] |
200 | * |
201 | */ |
202 | template <class T> |
203 | std::string minify(T x) { |
204 | return to_string(x); |
205 | } |
206 | |
207 | #if SIMDJSON_EXCEPTIONS |
208 | template <class T> |
209 | std::string minify(simdjson_result<T> x) { |
210 | if (x.error()) { throw simdjson_error(x.error()); } |
211 | return to_string(x.value()); |
212 | } |
213 | #endif |
214 | |
215 | |
216 | } // namespace simdjson |
217 | |
218 | |
219 | #endif |
220 | |