|
28 | 28 |
|
29 | 29 | #include <cstddef>
|
30 | 30 | #include <iostream>
|
| 31 | +#include <sstream> |
31 | 32 | #include <stack>
|
32 | 33 | #include <type_traits>
|
33 | 34 |
|
34 | 35 |
|
| 36 | +namespace jpr { |
| 37 | + |
| 38 | + |
35 | 39 | class json_printer {
|
36 | 40 | public:
|
37 | 41 | enum container_type { object, array };
|
38 | 42 |
|
39 | 43 | json_printer(std::ostream &os = std::cout, bool pretty = false,
|
40 |
| - int indent = 2) |
41 |
| - : os_(os), pretty_(pretty), indent_(indent), have_separator_(true) |
| 44 | + int indent = 2, int base_nesting = 0) |
| 45 | + : os_(os), pretty_(pretty), indent_(indent), |
| 46 | + base_nesting_(base_nesting), have_separator_(true) |
42 | 47 | {
|
43 | 48 | print(object);
|
44 | 49 | }
|
@@ -90,6 +95,8 @@ class json_printer {
|
90 | 95 | return *this;
|
91 | 96 | }
|
92 | 97 |
|
| 98 | + std::ostream &ostream() noexcept { return os_; } |
| 99 | + |
93 | 100 | private:
|
94 | 101 | void start_print()
|
95 | 102 | {
|
@@ -129,37 +136,98 @@ class json_printer {
|
129 | 136 | }
|
130 | 137 |
|
131 | 138 | template <typename T>
|
132 |
| - typename std::enable_if<!std::is_integral<T>::value && |
133 |
| - !std::is_floating_point<T>::value>::type |
134 |
| - escape_and_print(const T &value) |
135 |
| - { |
136 |
| - os_ << '"' << value << '"'; |
137 |
| - } |
138 |
| - |
139 |
| - template <typename T> |
140 |
| - typename std::enable_if<std::is_integral<T>::value || |
141 |
| - std::is_floating_point<T>::value>::type |
142 |
| - escape_and_print(const T &value) |
143 |
| - { |
144 |
| - os_ << value; |
145 |
| - } |
146 |
| - |
147 |
| - void escape_and_print(bool value) { os_ << (value ? "true" : "false"); } |
148 |
| - |
149 |
| - void escape_and_print(nullptr_t) { os_ << "null"; } |
150 |
| - |
151 |
| - void escape_and_print(container_type t) |
152 |
| - { |
153 |
| - os_ << (t == object ? '{' : '['); |
154 |
| - } |
| 139 | + inline void escape_and_print(const T &value); |
155 | 140 |
|
156 | 141 | std::ostream &os_;
|
157 | 142 | bool pretty_;
|
158 | 143 | int indent_;
|
| 144 | + int base_nesting_; |
159 | 145 | bool have_separator_;
|
160 | 146 | bool need_newline_;
|
161 | 147 | std::stack<container_type> nesting_info_;
|
162 | 148 | };
|
163 | 149 |
|
164 | 150 |
|
| 151 | +namespace detail { |
| 152 | + |
| 153 | + |
| 154 | +template <typename T> |
| 155 | +typename std::enable_if<std::is_integral<T>::value || |
| 156 | + std::is_floating_point<T>::value>::type |
| 157 | +print_as_json(json_printer &printer, T value) |
| 158 | +{ |
| 159 | + printer.ostream() << value; |
| 160 | +} |
| 161 | + |
| 162 | +void print_as_json(json_printer &printer, const std::string &value) |
| 163 | +{ |
| 164 | + auto &os = printer.ostream(); |
| 165 | + os << '"'; |
| 166 | + for (const auto c : value) { |
| 167 | + switch (c) { |
| 168 | + case '\\': os << "\\\\"; break; |
| 169 | + case '\"': os << "\\\""; break; |
| 170 | + default: os << c; |
| 171 | + } |
| 172 | + } |
| 173 | + os << '"'; |
| 174 | +} |
| 175 | + |
| 176 | +void print_as_json(json_printer &printer, const char *value) |
| 177 | +{ |
| 178 | + print_as_json(printer, std::string(value)); |
| 179 | +} |
| 180 | + |
| 181 | +void print_as_json(json_printer &printer, bool value) |
| 182 | +{ printer.ostream() << (value ? "true" : "false"); } |
| 183 | + |
| 184 | +void print_as_json(json_printer &printer, std::nullptr_t) { printer.ostream() << "null"; } |
| 185 | + |
| 186 | +void print_as_json(json_printer &printer, json_printer::container_type t) |
| 187 | +{ |
| 188 | + printer.ostream() << (t == json_printer::object ? '{' : '['); |
| 189 | +} |
| 190 | + |
| 191 | + |
| 192 | +template <typename...> |
| 193 | +using void_t = void; |
| 194 | + |
| 195 | + |
| 196 | +template <typename T, typename = void> |
| 197 | +struct have_custom_printer : std::false_type {}; |
| 198 | + |
| 199 | +template <typename T> |
| 200 | +struct have_custom_printer<T, void_t<decltype(print_as_json(std::declval<json_printer&>(), std::declval<T>()))>> : std::true_type {}; |
| 201 | + |
| 202 | + |
| 203 | +template <typename T> |
| 204 | +typename std::enable_if<have_custom_printer<T>::value>::type |
| 205 | +escape_and_print_impl(json_printer &printer, const T &value) |
| 206 | +{ |
| 207 | + print_as_json(printer, value); |
| 208 | +} |
| 209 | + |
| 210 | +template <typename T> |
| 211 | +typename std::enable_if<!have_custom_printer<T>::value>::type |
| 212 | +escape_and_print_impl(json_printer &printer, const T &value) |
| 213 | +{ |
| 214 | + std::ostringstream ss; |
| 215 | + ss << value; |
| 216 | + print_as_json(printer, ss.str()); |
| 217 | +} |
| 218 | + |
| 219 | + |
| 220 | +} // namespace detail |
| 221 | + |
| 222 | + |
| 223 | +template <typename T> |
| 224 | +void json_printer::escape_and_print(const T &value) |
| 225 | +{ |
| 226 | + detail::escape_and_print_impl(*this, value); |
| 227 | +} |
| 228 | + |
| 229 | + |
| 230 | +} // namespace jpr |
| 231 | + |
| 232 | + |
165 | 233 | #endif // JSON_PRINTER_HPP_
|
0 commit comments