9 #include <initializer_list>
15 #include <string_view>
16 #include <system_error>
17 #include <unordered_map>
23 using JsonString
= std::string
;
24 using JsonFloat
= double;
25 using JsonNull
= std::nullptr_t
;
26 using JsonArray
= std::vector
<JsonValue
>;
27 using JsonMap
= std::vector
<std::pair
<std::string
, JsonValue
>>;
29 struct JsonValue final
31 std::variant
<JsonString
, JsonFloat
, JsonNull
, std::unique_ptr
<JsonArray
>,
32 std::unique_ptr
<JsonMap
>>
34 constexpr JsonValue() noexcept
: value(nullptr)
37 constexpr JsonValue(JsonNull
) noexcept
: value(nullptr)
40 constexpr JsonValue(JsonFloat value
) noexcept
: value(value
)
43 JsonValue(JsonString value
) noexcept
: value(std::move(value
))
46 JsonValue(std::unique_ptr
<JsonArray
> value
) noexcept
47 : value(std::move(value
))
50 JsonValue(JsonArray value
) noexcept
51 : value(std::make_unique
<JsonArray
>(std::move(value
)))
54 JsonValue(std::unique_ptr
<JsonMap
> value
) noexcept
55 : value(std::move(value
))
58 JsonValue(JsonMap value
) noexcept
59 : value(std::make_unique
<JsonMap
>(std::move(value
)))
62 /// decode a JsonString from WTF-8 to the encoding logically used in JSON:
63 /// WTF-16 aka. potentially ill-formed UTF-16
65 /// https://simonsapin.github.io/wtf-8/
66 class JsonStringDecoder final
69 std::string_view remaining
;
70 bool last_was_lead_surrogate
= false;
71 std::optional
<std::uint16_t> trail_surrogate
;
74 constexpr JsonStringDecoder() noexcept
: JsonStringDecoder("")
77 constexpr explicit JsonStringDecoder(
78 std::string_view json_string
) noexcept
79 : remaining(json_string
)
84 [[noreturn
]] void throw_wtf8_err()
86 *this = JsonStringDecoder();
87 throw std::ios_base::failure("Invalid WTF-8");
91 constexpr std::optional
<std::uint16_t> next()
95 auto retval
= *trail_surrogate
;
96 trail_surrogate
= std::nullopt
;
99 if (remaining
.empty())
103 std::uint32_t code_point
= 0;
106 std::uint8_t min
= 0x80;
107 std::uint8_t max
= 0xBF;
109 auto get
= [&]() -> std::uint8_t {
110 if (remaining
.empty())
114 std::uint8_t retval
= remaining
[0];
115 remaining
.remove_prefix(1);
118 auto cont
= [&](min_max min_max
= {}) {
119 std::uint8_t v
= get();
120 if (v
< min_max
.min
|| v
> min_max
.max
)
125 code_point
|= v
& 0x3F;
127 std::uint8_t initial
= get();
130 code_point
= initial
;
132 else if (initial
< 0xC2)
136 else if (initial
< 0xE0)
138 code_point
= initial
& 0x1F;
141 else if (initial
== 0xE0)
143 code_point
= initial
& 0xF;
147 else if (initial
< 0xF0)
149 code_point
= initial
& 0xF;
153 else if (initial
== 0xF0)
155 code_point
= initial
& 0x7;
160 else if (initial
< 0xF4)
162 code_point
= initial
& 0x7;
167 else if (initial
== 0xF4)
169 code_point
= initial
& 0x7;
178 if (last_was_lead_surrogate
&& code_point
>= 0xDC00 &&
179 code_point
<= 0xDFFF)
181 // got lead surrogate followed by trail surrogate --
185 last_was_lead_surrogate
=
186 (code_point
>= 0xD800 && code_point
<= 0xDBFF);
187 bool is_supplementary_code_point
= code_point
>= 0x10000;
188 if (is_supplementary_code_point
)
190 auto value
= code_point
- 0x10000;
191 std::uint16_t retval
= (value
>> 10) + 0xD800;
192 trail_surrogate
= (value
& 0x3FF) + 0xDC00;
201 template <typename WriteStringView
>
202 void write(WriteStringView
&&write_fn
) const
206 WriteStringView
&write_fn
;
207 void write(std::string_view str
)
213 write_fn(std::string_view(&ch
, 1));
215 void operator()(const JsonString
&value
)
218 JsonStringDecoder
decoder(value
);
219 while (auto value_opt
= decoder
.next())
221 std::uint16_t value
= *value_opt
;
227 write(static_cast<char>(value
));
245 if (value
>= 0x20 && value
<= 0x7E)
247 write(static_cast<char>(value
));
251 static constexpr char hex_digits
[] =
254 for (int i
= 0; i
< 4; i
++)
256 write(hex_digits
[value
>> 12]);
265 void operator()(JsonFloat value
)
267 if (std::isnan(value
))
272 if (std::signbit(value
))
277 if (std::isinf(value
))
287 using Buf
= std::array
<char, 32>;
288 auto try_format
= [&](Buf
&buf
, bool e_format
,
293 result
= std::snprintf(&buf
[0], buf
.size(), "%1.*e",
298 result
= std::snprintf(&buf
[0], buf
.size(), "%1.*f",
303 double parsed_value
= std::strtod(&buf
[0], nullptr);
304 if (parsed_value
!= value
)
306 // not precise enough
312 std::optional
<std::string_view
> final
;
313 std::size_t end_prec
= final_buf
.size();
314 for (std::size_t prec
= 0;
315 prec
< final_buf
.size() && prec
< end_prec
; prec
++)
318 if (try_format(buf
, true, prec
))
320 std::string_view
str(&buf
[0]);
321 if (!final
|| str
.size() < final
->size())
325 std::string_view(&final_buf
[0], str
.size());
329 if (try_format(buf
, false, prec
))
331 std::string_view
str(&buf
[0]);
332 if (!final
|| str
.size() < final
->size())
336 std::string_view(&final_buf
[0], str
.size());
341 if (final_buf
[0] == '.')
347 void operator()(JsonNull
)
351 void operator()(const std::unique_ptr
<JsonArray
> &value
)
354 std::string_view sep
{};
355 for (auto &i
: *value
)
359 std::visit(*this, i
.value
);
363 void operator()(const std::unique_ptr
<JsonMap
> &value
)
366 std::string_view sep
{};
367 for (auto &[k
, v
] : *value
)
373 std::visit(*this, v
.value
);
378 std::visit(Visitor
{.write_fn
= write_fn
}, value
);
380 friend std::ostream
&operator<<(std::ostream
&os
, const JsonValue
&self
)
382 self
.write([&](std::string_view str
) { os
<< str
; });