This repository was archived by the owner on Jun 17, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathnative_json.cpp
More file actions
464 lines (411 loc) · 9.98 KB
/
native_json.cpp
File metadata and controls
464 lines (411 loc) · 9.98 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
#include "native_json.h"
#include "json_stream.h"
#include "errors.h"
#include "native_json_helpers.h"
#include "rapidjson/writer.h"
#include "rapidjson/prettywriter.h"
#include "rapidjson/reader.h"
#define BOOST_KARMA_NUMERICS_LOOP_UNROLL 6
#include <boost/spirit/include/karma.hpp>
using namespace boost::spirit;
using boost::spirit::karma::int_;
using boost::spirit::karma::lit;
using namespace sofadb;
using namespace utils;
using namespace rapidjson;
static const bignum_t max_int_decimal("9223372036854775807"); //2^63
static const bignum_t min_int_decimal("-9223372036854775808"); //-(2^63)-1
const json_value json_value::empty_val;
std::string sofadb::int_to_string(int64_t in)
{
char buffer[64];
char *ptr = buffer;
karma::generate(ptr, int_, in);
*ptr = '\0';
return std::string(buffer, ptr-buffer);
}
void sofadb::append_int_to_string(int64_t in, jstring_t &out)
{
char buffer[64];
char *ptr = buffer;
karma::generate(ptr, int_, in);
*ptr = '\0';
out.append(buffer, ptr);
}
bool sofadb::operator < (const bignum_t &l, const bignum_t &r)
{
const bool lneg = l.digits_.at(0) == '-';
const bool rneg = r.digits_.at(0) == '-';
//Check for unequal signs
if(lneg && !rneg)
return true;
if (!lneg && rneg)
return false;
//Signs are equal.
if (l.digits_.size()!=r.digits_.size())
{
if (lneg)
return l.digits_.size()>r.digits_.size();
else
return l.digits_.size()<r.digits_.size();
}
//Use STRING comparison to find out the relation of numbers
//It's safe because the length of the left number is equal
//to the length of the right number so lexiographical string
//comparison (in all sane encodings) produces the same result
//as numerical one.
if (lneg)
return l.digits_ > r.digits_;
else
return l.digits_ < r.digits_;
}
bool sofadb::operator < (const graft_t &l, const graft_t &r)
{
return l.grafted() < r.grafted();
}
bool sofadb::operator == (const graft_t &l, const graft_t &r)
{
return l.grafted() == r.grafted();
}
graft_t::graft_t() :
graft_(&json_value::empty_val), deleter_()
{
}
json_value json_value::normalize_int() const
{
if (type()==int_d)
return *this;
else if (type()==big_int_d)
{
const bignum_t &num = get_big_int();
if ( (num>min_int_decimal || num==min_int_decimal) &&
(num<max_int_decimal || num==max_int_decimal) )
return json_value(int64_t(atoll(num.digits_.c_str())));
return *this;
} else
throw std::bad_cast();
}
template<template<class T> class Operator> bool do_operation(
const json_value &l, const json_value &r)
{
if (l.type()==big_int_d && r.type()==int_d ||
r.type()==big_int_d && l.type()==int_d)
{
const json_value &l1=l.normalize_int();
const json_value &l2=r.normalize_int();
if (l1.type()!=l2.type())
return Operator<json_disc>()(l1.type(), l2.type());
return Operator<int64_t>()(l1.get_int(), l2.get_int());
}
if (l.type()==graft_d && r.type()!=graft_d)
return Operator<json_value>()(l.get_graft().grafted(), r);
if (r.type()==graft_d && l.type()!=graft_d)
return Operator<json_value>()(l, r.get_graft().grafted());
if (l.type() != r.type())
return Operator<json_disc>()(l.type(), r.type());
switch(l.type())
{
case nil_d:
return Operator<int>()(1, 1);
case bool_d:
return Operator<bool>()(l.get_bool(), r.get_bool());
case int_d:
return Operator<int64_t>()(l.get_int(), r.get_int());
case double_d:
return Operator<double>()(l.get_double(), r.get_double());
case string_d:
return Operator<jstring_t>()(l.get_str(), r.get_str());
case big_int_d:
return Operator<bignum_t>()(l.get_big_int(), r.get_big_int());
case submap_d:
return Operator<submap_t>()(l.get_submap(), r.get_submap());
case sublist_d:
return Operator<sublist_t>()(l.get_sublist(), r.get_sublist());
case graft_d:
return Operator<graft_t>()(l.get_graft(), r.get_graft());
default:
assert(false);
}
}
bool sofadb::operator == (const json_value &l, const json_value &r)
{
return do_operation<std::equal_to>(l, r);
}
bool sofadb::operator < (const json_value &l, const json_value &r)
{
return do_operation<std::less>(l, r);
}
struct rapid_read_handler
{
std::vector<json_value*> values_;
jstring_t cur_key_;
bool first_;
rapid_read_handler() : first_(true) {}
json_value* advance(json_value && val)
{
json_value &cur_tip = *values_.back();
if (!cur_key_.empty())
{
auto res=cur_tip.get_submap().insert(
std::make_pair(std::move(cur_key_),
std::move(val)));
cur_key_.clear();
return &res.first->second;
} else
{
cur_tip.get_sublist().push_back(std::move(val));
return &cur_tip.get_sublist().back();
}
}
void Null()
{
advance(json_value());
}
void Bool(bool b)
{
advance(json_value(b));
}
void BigNum(const char *str, size_t length)
{
std::string digits(str, length);
if (digits.find_first_of("eE.")!=jstring_t::npos)
{
double val=0;
if (sscanf(digits.c_str(), "%lf", &val) == EOF)
throw std::bad_exception();
advance(json_value(val));
} else
{
json_value v(bignum_t(std::move(digits)));
advance(v.normalize_int());
}
}
void String(const char* str, size_t length, bool copy)
{
json_value &cur_val = *values_.back();
if (cur_key_.empty() && cur_val.type()==submap_d)
{
cur_key_ = jstring_t(str, length);
} else
{
advance(json_value(jstring_t(str, length)));
}
}
void StartObject()
{
if (first_)
{
first_ = false;
values_.back()->as_submap();
return;
}
json_value *val=advance(json_value(submap_d));
values_.push_back(val);
}
void EndObject(SizeType memberCount)
{
values_.pop_back();
}
void StartArray()
{
if (first_)
{
first_ = false;
values_.back()->as_sublist();
return;
}
json_value *val=advance(json_value(sublist_d));
values_.push_back(val);
}
void EndArray(SizeType elementCount)
{
values_.pop_back();
}
};
template<class Stream, unsigned Flags>
json_value parse_from_stream(Stream &istr)
{
char alloc_buf[8192];
MemoryPoolAllocator<> alloc(alloc_buf, 8192);
Reader reader(&alloc);
json_value res;
rapid_read_handler hndl;
hndl.values_.push_back(&res);
reader.Parse<Flags>(istr, hndl);
if (reader.HasParseError())
{
size_t offset=reader.GetErrorOffset();
if (offset>25)
offset-=25;
jstring_t str=istr.GetSubSequence(offset,40);
if (str.empty())
{
err(result_code_t::sWrongRevision)
<< reader.GetParseError() << " "
<< "(unknown location)";
}
//Replace all whitespace-y symbols with spaces
for(size_t f=0,fend=str.size();f<fend;++f)
if (str[f]=='\t' || str[f]=='\n' || str[f]=='\r')
str[f]=' ';
jstring_t pos_marker;
pos_marker.append(reader.GetErrorOffset()-offset , ' ');
err(result_code_t::sWrongRevision)
<< reader.GetParseError() << std::endl
<< "Near: " << str << std::endl
<< " " << pos_marker << "^(here)";
}
return std::move(res);
}
json_value sofadb::string_to_json(const jstring_t &str)
{
BufReadStream istr((char*)str.data(), str.size());
return parse_from_stream<BufReadStream, 0>(istr);
}
json_value sofadb::json_from_stream(std::istream &val)
{
StdStreamReadStream istr(val);
return parse_from_stream<StdStreamReadStream, kParseIgnoreTrailing>(istr);
}
template<class Writer> struct rapid_json_printer
{
Writer &writer_;
rapid_json_printer(Writer &writer) : writer_(writer) {}
void operator()()
{
writer_.Null();
}
void operator()(bool b)
{
writer_.Bool(b);
}
void operator()(int64_t i)
{
writer_.Int64(i);
}
void operator()(double d)
{
writer_.Double(d);
}
void operator()(const jstring_t &s)
{
writer_.String(s.data(), s.length());
}
void operator()(const bignum_t &b)
{
writer_.BigInt(b.digits_.data(), b.digits_.length());
}
void operator()(const submap_t &map)
{
writer_.StartObject();
for(auto i=map.begin(), iend=map.end();i!=iend;++i)
{
writer_.String(i->first.data(), i->first.length());
i->second.apply_visitor(*this);
}
writer_.EndObject();
}
void operator()(const sublist_t &lst)
{
writer_.StartArray();
for(auto i = lst.begin(), iend=lst.end(); i!=iend; ++i)
i->apply_visitor(*this);
writer_.EndArray();
}
void operator()(const graft_t &lst)
{
lst.grafted().apply_visitor(*this);
}
};
void sofadb::json_to_string(jstring_t &append_to,
const json_value &val, bool pretty)
{
char buf[8192];
MemoryPoolAllocator<> alloc(buf, 8192);
StringWriteStream stream(append_to);
if (pretty)
{
PrettyWriter<StringWriteStream> writer(stream, &alloc);
writer.SetIndent(' ', 2);
rapid_json_printer< PrettyWriter<StringWriteStream> > vis(writer);
val.apply_visitor(vis);
} else
{
Writer<StringWriteStream> writer(stream, &alloc);
rapid_json_printer< Writer<StringWriteStream> > vis(writer);
val.apply_visitor(vis);
}
alloc.Clear();
}
template <class Writer> class str_json_stream : public json_stream
{
jstring_t &str_;
StringWriteStream write_stream_;
Writer writer_;
public:
str_json_stream(jstring_t &str) :
str_(str), write_stream_(str), writer_(write_stream_)
{
}
virtual ~str_json_stream() {}
virtual void write_null()
{
writer_.Null();
}
virtual void write_bool(bool val)
{
writer_.Bool(val);
}
virtual void write_int(int64_t i)
{
writer_.Int64(i);
}
virtual void write_double(double d)
{
writer_.Double(d);
}
virtual void write_string(const char *str, size_t ln)
{
writer_.String(str, ln);
}
virtual void write_digits(const char *str, size_t ln)
{
writer_.BigInt(str, ln);
}
virtual void start_map()
{
writer_.StartObject();
}
virtual void end_map()
{
writer_.EndObject();
}
virtual void start_list()
{
writer_.StartArray();
}
virtual void end_list()
{
writer_.EndArray();
}
virtual void write_json(const json_value &val)
{
rapid_json_printer< Writer > p(writer_);
val.apply_visitor(p);
}
};
std::auto_ptr<json_stream> sofadb::make_stream(jstring_t &append_to,
bool pretty)
{
if (pretty)
{
json_stream *s=new str_json_stream< PrettyWriter<StringWriteStream> >(
append_to);
return std::auto_ptr<json_stream>(s);
} else
{
json_stream *s=new str_json_stream< Writer<StringWriteStream> >(
append_to);
return std::auto_ptr<json_stream>(s);
}
}