Skip to content

Commit 739185f

Browse files
committed
Some JSON-related updates.
1 parent 210fa96 commit 739185f

19 files changed

+496
-185
lines changed

simple-json/src/json-array.hpp

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,24 +15,24 @@ class array : public std::vector<value> {
1515
// inherited
1616
using vector::vector;
1717

18-
// from instance of base class
19-
array(const vector &from) : vector(from) { }
20-
array(vector &&from) : vector(std::move(from)) { }
18+
// from std::vector<value> (instance of base class)
19+
array(const vector &base) : vector(base) { }
20+
array(vector &&base) : vector(std::move(base)) { }
2121

2222
// from std::vector<T convertible to value>
2323
template<class T, class = require<convertible<T,value>>>
24-
array(const std::vector<T> &from) :
25-
vector(from.begin(), from.end())
24+
array(const std::vector<T> &vec) :
25+
vector(vec.begin(), vec.end())
2626
{ }
2727

2828
// ------------------------
2929
// Assignment
3030
// ------------------------
3131

32-
template<class T, class = require<assignable<vector, T &&>>>
33-
array &operator=(T &&from)
32+
template<class FROM, class = require<assignable<vector, FROM &&>>>
33+
array &operator=(FROM &&from)
3434
{
35-
return vector::operator=(std::forward<T>(from)), *this;
35+
return vector::operator=(std::forward<FROM>(from)), *this;
3636
}
3737

3838
// ------------------------

simple-json/src/json-atom.hpp

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
2+
// -----------------------------------------------------------------------------
3+
// atom
4+
// -----------------------------------------------------------------------------
5+
6+
#if defined(JSON_RAW)
7+
8+
// ------------------------
9+
// Raw pointer version
10+
// ------------------------
11+
12+
template<class T>
13+
class atom {
14+
static inline constexpr bool plain = sizeof(T) <= sizeof(std::shared_ptr<T>);
15+
std::conditional_t<plain, T, T *> val;
16+
17+
public:
18+
19+
// construction: default
20+
atom()
21+
{
22+
if constexpr ( plain) val = T();
23+
if constexpr (!plain) val = new T();
24+
}
25+
26+
// construction: from T (exactly)
27+
template<class FROM, class = require<same<FROM,T>>>
28+
atom(const FROM &from)
29+
{
30+
if constexpr ( plain) val = from;
31+
if constexpr (!plain) val = new T(from);
32+
}
33+
34+
// construction: copy
35+
atom(const atom &other)
36+
{
37+
if constexpr ( plain) val = other.val;
38+
if constexpr (!plain) val = new T(*other.val);
39+
}
40+
41+
// construction: move
42+
atom(atom &&other)
43+
{
44+
val = std::move(other.val);
45+
if constexpr (!plain)
46+
other.val = nullptr;
47+
}
48+
49+
// assignment: copy
50+
atom &operator=(const atom &other)
51+
{
52+
if constexpr ( plain) return val = other.val, *this;
53+
if constexpr (!plain) return *val = *other.val, *this;
54+
}
55+
56+
// assignment: move
57+
atom &operator=(atom &&other)
58+
{
59+
val = std::move(other.val);
60+
if constexpr ( plain) return *this;
61+
if constexpr (!plain) return other.val = nullptr, *this;
62+
}
63+
64+
// assignment: general
65+
template<class FROM, class = require<assignable<T &, FROM &&>>>
66+
atom &operator=(FROM &&from)
67+
{
68+
if constexpr ( plain) return val = std::move(from), *this;
69+
if constexpr (!plain) return *val = std::move(from), *this;
70+
}
71+
72+
// conversion: to T
73+
operator const T &() const
74+
{ if constexpr (plain) return val; else return *val; }
75+
operator T &()
76+
{ if constexpr (plain) return val; else return *val; }
77+
78+
// destructor
79+
~atom()
80+
{
81+
if constexpr (!plain)
82+
delete val;
83+
}
84+
};
85+
86+
// ------------------------
87+
// Shared pointer version
88+
// ------------------------
89+
90+
#elif defined(JSON_SHARED)
91+
92+
template<class T>
93+
class atom {
94+
static inline constexpr bool plain = sizeof(T) <= sizeof(std::shared_ptr<T>);
95+
std::conditional_t<plain, T, std::shared_ptr<T>> val;
96+
97+
public:
98+
99+
// construction: default
100+
atom()
101+
{
102+
if constexpr ( plain) val = T();
103+
if constexpr (!plain) val = std::make_shared<T>();
104+
}
105+
106+
// construction: from T (exactly)
107+
template<class FROM, class = require<same<FROM,T>>>
108+
atom(const FROM &from)
109+
{
110+
if constexpr ( plain) val = from;
111+
if constexpr (!plain) val = std::make_shared<T>(from);
112+
}
113+
114+
// conversion: to T
115+
operator const T &() const
116+
{ if constexpr (plain) return val; else return *val; }
117+
operator T &()
118+
{ if constexpr (plain) return val; else return *val; }
119+
120+
// assignment
121+
template<class FROM, class = require<assignable<T &, FROM &&>>>
122+
atom &operator=(FROM &&from)
123+
{
124+
if constexpr ( plain) return val = std::move(from), *this;
125+
if constexpr (!plain) return *val = std::move(from), *this;
126+
}
127+
};
128+
129+
// ------------------------
130+
// atom<T> == T
131+
// ------------------------
132+
133+
#else
134+
135+
template<class T>
136+
using atom = T;
137+
138+
#endif

simple-json/src/json-boolean.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@ class boolean {
1818
boolean() : b(false) { }
1919

2020
// from bool (exactly)
21-
template<class T, class = require<same<T,bool>>>
22-
boolean(const T &from) : b(from) { }
21+
template<class BOOL, class = require<same<BOOL,bool>>>
22+
boolean(const BOOL &from) : b(from) { }
2323

2424
// ------------------------
2525
// Conversion

simple-json/src/json-chars.hpp

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,17 +30,23 @@ class chars {
3030
) {
3131
std::to_chars_result res;
3232

33-
if constexpr (integral<T>)
33+
if constexpr (integral<T>) {
3434
res = same<T,unsigned char>
3535
? std::to_chars(buffer, buffer+SIZE, (unsigned short)from)
3636
: same<T, signed char>
3737
? std::to_chars(buffer, buffer+SIZE, ( signed short)from)
3838
: std::to_chars(buffer, buffer+SIZE, from);
39-
else {
39+
} else {
4040
#ifdef JSON_CHARS
4141
res = std::to_chars(buffer, buffer+SIZE, from, format);
4242
#else
43-
assert(false);
43+
error("Cannot construct a json::chars from a floating point "
44+
"value unless\nJSON_CHARS is #defined. This further "
45+
"requires that std::to_chars()\nbe available for "
46+
"floating points. (It isn't for some compilers.)");
47+
// error() throws; this return just suppresses warnings from
48+
// some compilers about res being uninitialized below.
49+
return;
4450
#endif
4551
}
4652

simple-json/src/json-detail-post.hpp

Lines changed: 113 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ struct variant2tuple<std::variant<As...>> { using type = std::tuple<As...>; };
1212
// Re: printing
1313
// -----------------------------------------------------------------------------
1414

15-
// name: general
15+
// name: specific cases
1616
#define JSON_NAME(type) \
1717
inline std::string name(const type &) { return #type; }
1818

@@ -39,6 +39,17 @@ JSON_NAME(literal)
3939

4040
#undef JSON_NAME
4141

42+
// name: for atom
43+
// Remark: If preprocessor directives are such that atom<T> == T, then name(),
44+
// as defined below, without the class = require<> SFINAE, would be infinitely
45+
// recursive. It presumably wouldn't be called, because, above, we define each
46+
// case we intend to use. To be exceedingly proper, though, we have the SFINAE.
47+
template<class T, class = require<!same<atom<T>,T>>>
48+
std::string name(const atom<T> &)
49+
{
50+
return name(T());
51+
}
52+
4253
// name: for number
4354
inline std::string name(const number &n)
4455
{
@@ -48,7 +59,7 @@ inline std::string name(const number &n)
4859
);
4960
}
5061

51-
// detail::print, for array and object
62+
// print, for array and object
5263
template<class ACTION, class T>
5364
void print(
5465
const T &obj, std::ostream &os,
@@ -62,7 +73,7 @@ void print(
6273
os << std::setw(0) << str + ch + (colors ? json::color::reset : "");
6374
}
6475

65-
// detail::print, for other types
76+
// print, for other types
6677
template<class ACTION, class T>
6778
void print(
6879
const T &obj, std::ostream &os, const std::string &content,
@@ -147,7 +158,7 @@ inline void expect(
147158
// nocasecmp
148159
// Case-insensitive std::string comparison.
149160
// The old C language strcasecmp() is nonstandard. A modern, true caseless
150-
// std::string comparison would depend on, e.g., locale; but the following
161+
// std::string comparison would depend on, e.g., locale, but the following
151162
// should suffice for our purposes.
152163
inline bool nocasecmp(const std::string &one, const std::string &two)
153164
{
@@ -207,4 +218,102 @@ literal many(
207218
return literal(flags & literal::self ? text+suffix : "");
208219
} // many
209220

221+
222+
// -----------------------------------------------------------------------------
223+
// Support for reading string escapes of the form \u####
224+
// -----------------------------------------------------------------------------
225+
226+
// ------------------------
227+
// Constants, functions
228+
// ------------------------
229+
230+
// Ranges for surrogates.
231+
// Remark: each of [himin..himax] and [lomin..lomax]
232+
// has 1024 values inclusive. Also, lomin == himax+1.
233+
inline constexpr int himin = 0xD800; // 0b 11011 000 00000000
234+
inline constexpr int himax = 0xDBFF; // 0b 11011 011 11111111
235+
inline constexpr int lomin = 0xDC00; // 0b 11011 100 00000000
236+
inline constexpr int lomax = 0xDFFF; // 0b 11011 111 11111111
237+
inline constexpr unsigned tweak =
238+
unsigned(himin << 10) + unsigned(lomin) - 0x10000u;
239+
240+
// High/low surrogate?
241+
inline bool hi(const int p) { return himin <= p && p <= himax; }
242+
inline bool lo(const int p) { return lomin <= p && p <= lomax; }
243+
244+
// ------------------------
245+
// codepoint
246+
// ------------------------
247+
248+
// \uabcd ==> (a << 12) + (b << 8) + (c << 4) + (d << 0)
249+
inline int codepoint(
250+
const std::string &context, std::istream &is,
251+
std::string &token // representation of hex number, for diagnostic printing
252+
) {
253+
int ret = 0, ch;
254+
token = "\\u";
255+
for (const unsigned shift : { 12u, 8u, 4u, 0u }) {
256+
if ((ch = is.get()) == EOF)
257+
error(context +
258+
"Expected 4-character hex code; reached EOF instead.", &is);
259+
else if ('0' <= ch && ch <= '9') ret += int((unsigned(ch)-48u) << shift);
260+
else if ('A' <= ch && ch <= 'F') ret += int((unsigned(ch)-55u) << shift);
261+
else if ('a' <= ch && ch <= 'f') ret += int((unsigned(ch)-87u) << shift);
262+
else
263+
error(context +
264+
"Invalid hex digit found while reading \\u####.", &is);
265+
token += ch;
266+
}
267+
return ret;
268+
}
269+
270+
// ------------------------
271+
// unicode
272+
// ------------------------
273+
274+
inline void unicode(
275+
const std::string &context, std::istream &is,
276+
std::string &str
277+
) {
278+
std::string one, two;
279+
int first = codepoint(context,is,one), second;
280+
281+
static const std::string
282+
hi_before_lo = "A high surrogate must precede the low surrogate",
283+
lo_follow_hi = "A low surrogate must follow the high surrogate";
284+
285+
if (lo(first))
286+
error(context + hi_before_lo + " " + one + ".\n" +
287+
"There was no such high surrogate.", &is);
288+
if (hi(first)) {
289+
if (is.get() != '\\' || is.get() != 'u')
290+
error(context + lo_follow_hi + " " + one + ".\n" +
291+
"There is no such low surrogate.", &is);
292+
if (!lo(second = codepoint(context,is,two)))
293+
error(context + lo_follow_hi + " " + one + ".\n" +
294+
two + " is not a low surrogate.", &is);
295+
first = (unsigned(first) << 10u) + unsigned(second) - tweak;
296+
}
297+
298+
if (first <= 127) {
299+
// 0bbbbbbb (ASCII case)
300+
str += int(first);
301+
} else if (first <= 2047) {
302+
// 110bbbbb 10bbbbbb
303+
str += int(0b11000000u | ((unsigned(first) >> 6u) ));
304+
str += int(0b10000000u | ((unsigned(first) ) & 0b00111111u));
305+
} else if (first <= 65535) {
306+
// 1110bbbb 10bbbbbb 10bbbbbb
307+
str += int(0b11100000u | ((unsigned(first) >> 12u) ));
308+
str += int(0b10000000u | ((unsigned(first) >> 6u) & 0b00111111u));
309+
str += int(0b10000000u | ((unsigned(first) ) & 0b00111111u));
310+
} else {
311+
// 11110bbb 10bbbbbb 10bbbbbb 10bbbbbb
312+
str += int(0b11110000u | ((unsigned(first) >> 18u) ));
313+
str += int(0b10000000u | ((unsigned(first) >> 12u) & 0b00111111u));
314+
str += int(0b10000000u | ((unsigned(first) >> 6u) & 0b00111111u));
315+
str += int(0b10000000u | ((unsigned(first) ) & 0b00111111u));
316+
}
317+
}
318+
210319
} // namespace detail

0 commit comments

Comments
 (0)