oj 0.8.0 → 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of oj might be problematic. Click here for more details.
- data/LICENSE +1 -1
- data/README.md +163 -104
- data/ext/oj/cache8.c +130 -0
- data/ext/oj/cache8.h +46 -0
- data/ext/oj/dump.c +270 -106
- data/ext/oj/load.c +266 -77
- data/ext/oj/oj.c +7 -0
- data/ext/oj/oj.h +3 -0
- data/lib/oj/version.rb +1 -1
- data/test/perf_obj.rb +3 -3
- data/test/perf_strict.rb +105 -35
- data/test/tests.rb +108 -7
- metadata +4 -2
data/ext/oj/cache8.h
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
/* cache8.h
|
2
|
+
* Copyright (c) 2011, Peter Ohler
|
3
|
+
* All rights reserved.
|
4
|
+
*
|
5
|
+
* Redistribution and use in source and binary forms, with or without
|
6
|
+
* modification, are permitted provided that the following conditions are met:
|
7
|
+
*
|
8
|
+
* - Redistributions of source code must retain the above copyright notice, this
|
9
|
+
* list of conditions and the following disclaimer.
|
10
|
+
*
|
11
|
+
* - Redistributions in binary form must reproduce the above copyright notice,
|
12
|
+
* this list of conditions and the following disclaimer in the documentation
|
13
|
+
* and/or other materials provided with the distribution.
|
14
|
+
*
|
15
|
+
* - Neither the name of Peter Ohler nor the names of its contributors may be
|
16
|
+
* used to endorse or promote products derived from this software without
|
17
|
+
* specific prior written permission.
|
18
|
+
*
|
19
|
+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
20
|
+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
21
|
+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
22
|
+
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
23
|
+
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
24
|
+
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
25
|
+
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
26
|
+
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
27
|
+
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
28
|
+
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
29
|
+
*/
|
30
|
+
|
31
|
+
#ifndef __OJ_CACHE8_H__
|
32
|
+
#define __OJ_CACHE8_H__
|
33
|
+
|
34
|
+
#include "ruby.h"
|
35
|
+
|
36
|
+
typedef struct _Cache8 *Cache8;
|
37
|
+
typedef unsigned long slot_t;
|
38
|
+
|
39
|
+
extern void oj_cache8_new(Cache8 *cache);
|
40
|
+
extern void oj_cache8_delete(Cache8 cache);
|
41
|
+
|
42
|
+
extern slot_t oj_cache8_get(Cache8 cache, VALUE key, slot_t **slot);
|
43
|
+
|
44
|
+
extern void oj_cache8_print(Cache8 cache);
|
45
|
+
|
46
|
+
#endif /* __OJ_CACHE8_H__ */
|
data/ext/oj/dump.c
CHANGED
@@ -41,35 +41,20 @@
|
|
41
41
|
#include "st.h"
|
42
42
|
#endif
|
43
43
|
|
44
|
-
|
45
|
-
|
46
|
-
typedef struct _Str {
|
47
|
-
const char *str;
|
48
|
-
size_t len;
|
49
|
-
} *Str;
|
44
|
+
#include "cache8.h"
|
50
45
|
|
51
|
-
typedef
|
52
|
-
struct _Str clas;
|
53
|
-
struct _Str attr;
|
54
|
-
unsigned long id;
|
55
|
-
int indent; // < 0 indicates no \n
|
56
|
-
int closed;
|
57
|
-
char type;
|
58
|
-
} *Element;
|
46
|
+
typedef unsigned long ulong;
|
59
47
|
|
60
48
|
typedef struct _Out {
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
int depth; // used by dumpHash
|
71
|
-
Options opts;
|
72
|
-
uint32_t hash_cnt;
|
49
|
+
char *buf;
|
50
|
+
char *end;
|
51
|
+
char *cur;
|
52
|
+
Cache8 circ_cache;
|
53
|
+
slot_t circ_cnt;
|
54
|
+
int indent;
|
55
|
+
int depth; // used by dump_hash
|
56
|
+
Options opts;
|
57
|
+
uint32_t hash_cnt;
|
73
58
|
} *Out;
|
74
59
|
|
75
60
|
static void dump_obj_to_json(VALUE obj, Options copts, Out out);
|
@@ -81,7 +66,7 @@ static void dump_false(Out out);
|
|
81
66
|
static void dump_fixnum(VALUE obj, Out out);
|
82
67
|
static void dump_bignum(VALUE obj, Out out);
|
83
68
|
static void dump_float(VALUE obj, Out out);
|
84
|
-
static void dump_cstr(const char *str, size_t cnt, int is_sym, Out out);
|
69
|
+
static void dump_cstr(const char *str, size_t cnt, int is_sym, int escape1, Out out);
|
85
70
|
static void dump_hex(u_char c, Out out);
|
86
71
|
static void dump_str_comp(VALUE obj, Out out);
|
87
72
|
static void dump_str_obj(VALUE obj, Out out);
|
@@ -98,8 +83,10 @@ static void dump_data_comp(VALUE obj, Out out);
|
|
98
83
|
static void dump_data_obj(VALUE obj, Out out);
|
99
84
|
static void dump_obj_comp(VALUE obj, int depth, Out out);
|
100
85
|
static void dump_obj_obj(VALUE obj, int depth, Out out);
|
86
|
+
static void dump_struct_comp(VALUE obj, int depth, Out out);
|
87
|
+
static void dump_struct_obj(VALUE obj, int depth, Out out);
|
101
88
|
static int dump_attr_cb(ID key, VALUE value, Out out);
|
102
|
-
static void dump_obj_attrs(VALUE obj, int with_class, int depth, Out out);
|
89
|
+
static void dump_obj_attrs(VALUE obj, int with_class, slot_t id, int depth, Out out);
|
103
90
|
|
104
91
|
static void grow(Out out, size_t len);
|
105
92
|
static int is_json_friendly(const u_char *str, size_t len);
|
@@ -154,6 +141,39 @@ fill_indent(Out out, int cnt) {
|
|
154
141
|
}
|
155
142
|
}
|
156
143
|
|
144
|
+
inline static const char*
|
145
|
+
ulong2str(uint32_t num, char *end) {
|
146
|
+
char *b;
|
147
|
+
|
148
|
+
*end-- = '\0';
|
149
|
+
for (b = end; 0 < num || b == end; num /= 10, b--) {
|
150
|
+
*b = (num % 10) + '0';
|
151
|
+
}
|
152
|
+
b++;
|
153
|
+
|
154
|
+
return b;
|
155
|
+
}
|
156
|
+
|
157
|
+
inline static void
|
158
|
+
dump_ulong(unsigned long num, Out out) {
|
159
|
+
char buf[32];
|
160
|
+
char *b = buf + sizeof(buf) - 1;
|
161
|
+
|
162
|
+
*b-- = '\0';
|
163
|
+
if (0 < num) {
|
164
|
+
for (; 0 < num; num /= 10, b--) {
|
165
|
+
*b = (num % 10) + '0';
|
166
|
+
}
|
167
|
+
b++;
|
168
|
+
} else {
|
169
|
+
*b = '0';
|
170
|
+
}
|
171
|
+
for (; '\0' != *b; b++) {
|
172
|
+
*out->cur++ = *b;
|
173
|
+
}
|
174
|
+
*out->cur = '\0';
|
175
|
+
}
|
176
|
+
|
157
177
|
static void
|
158
178
|
grow(Out out, size_t len) {
|
159
179
|
size_t size = out->end - out->buf;
|
@@ -181,6 +201,34 @@ dump_hex(u_char c, Out out) {
|
|
181
201
|
*out->cur++ = hex_chars[d];
|
182
202
|
}
|
183
203
|
|
204
|
+
// returns 0 if not using circular references, -1 if not further writing is
|
205
|
+
// needed (duplicate), and a positive value if the object was added to the cache.
|
206
|
+
static long
|
207
|
+
check_circular(VALUE obj, Out out) {
|
208
|
+
slot_t id = 0;
|
209
|
+
slot_t *slot;
|
210
|
+
|
211
|
+
if (ObjectMode == out->opts->mode && Yes == out->opts->circular) {
|
212
|
+
if (0 == (id = oj_cache8_get(out->circ_cache, obj, &slot))) {
|
213
|
+
out->circ_cnt++;
|
214
|
+
id = out->circ_cnt;
|
215
|
+
*slot = id;
|
216
|
+
} else {
|
217
|
+
if (out->end - out->cur <= 18) {
|
218
|
+
grow(out, 18);
|
219
|
+
}
|
220
|
+
*out->cur++ = '"';
|
221
|
+
*out->cur++ = '^';
|
222
|
+
*out->cur++ = 'r';
|
223
|
+
dump_ulong(id, out);
|
224
|
+
*out->cur++ = '"';
|
225
|
+
|
226
|
+
return -1;
|
227
|
+
}
|
228
|
+
}
|
229
|
+
return (long)id;
|
230
|
+
}
|
231
|
+
|
184
232
|
static void
|
185
233
|
dump_nil(Out out) {
|
186
234
|
size_t size = 4;
|
@@ -286,15 +334,25 @@ dump_float(VALUE obj, Out out) {
|
|
286
334
|
}
|
287
335
|
|
288
336
|
static void
|
289
|
-
dump_cstr(const char *str, size_t cnt, int is_sym, Out out) {
|
337
|
+
dump_cstr(const char *str, size_t cnt, int is_sym, int escape1, Out out) {
|
290
338
|
size_t size = json_friendly_size((u_char*)str, cnt);
|
291
339
|
|
340
|
+
if (out->end - out->cur <= (long)size + 10) { // extra 10 for escaped first char, quotes, and sym
|
341
|
+
grow(out, size + 10);
|
342
|
+
}
|
343
|
+
*out->cur++ = '"';
|
344
|
+
if (escape1) {
|
345
|
+
*out->cur++ = '\\';
|
346
|
+
*out->cur++ = 'u';
|
347
|
+
*out->cur++ = '0';
|
348
|
+
*out->cur++ = '0';
|
349
|
+
dump_hex((u_char)*str, out);
|
350
|
+
cnt--;
|
351
|
+
size--;
|
352
|
+
str++;
|
353
|
+
is_sym = 0; // just to make sure
|
354
|
+
}
|
292
355
|
if (cnt == size) {
|
293
|
-
cnt += 2 + is_sym;
|
294
|
-
if (out->end - out->cur <= (long)cnt) {
|
295
|
-
grow(out, cnt);
|
296
|
-
}
|
297
|
-
*out->cur++ = '"';
|
298
356
|
if (is_sym) {
|
299
357
|
*out->cur++ = ':';
|
300
358
|
}
|
@@ -303,11 +361,6 @@ dump_cstr(const char *str, size_t cnt, int is_sym, Out out) {
|
|
303
361
|
}
|
304
362
|
*out->cur++ = '"';
|
305
363
|
} else {
|
306
|
-
size += 2;
|
307
|
-
if (out->end - out->cur <= (long)size) {
|
308
|
-
grow(out, size);
|
309
|
-
}
|
310
|
-
*out->cur++ = '"';
|
311
364
|
if (is_sym) {
|
312
365
|
*out->cur++ = ':';
|
313
366
|
}
|
@@ -352,37 +405,23 @@ dump_cstr(const char *str, size_t cnt, int is_sym, Out out) {
|
|
352
405
|
|
353
406
|
static void
|
354
407
|
dump_str_comp(VALUE obj, Out out) {
|
355
|
-
dump_cstr(StringValuePtr(obj), RSTRING_LEN(obj), 0, out);
|
408
|
+
dump_cstr(StringValuePtr(obj), RSTRING_LEN(obj), 0, 0, out);
|
356
409
|
}
|
357
410
|
|
358
411
|
static void
|
359
412
|
dump_str_obj(VALUE obj, Out out) {
|
360
413
|
const char *s = StringValuePtr(obj);
|
361
414
|
size_t len = RSTRING_LEN(obj);
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
grow(out, 6);
|
366
|
-
}
|
367
|
-
*out->cur++ = '{';
|
368
|
-
*out->cur++ = '"';
|
369
|
-
*out->cur++ = '^';
|
370
|
-
*out->cur++ = 's';
|
371
|
-
*out->cur++ = '"';
|
372
|
-
*out->cur++ = ':';
|
373
|
-
dump_cstr(s, len, 0, out);
|
374
|
-
*out->cur++ = '}';
|
375
|
-
*out->cur = '\0';
|
376
|
-
} else {
|
377
|
-
dump_cstr(s, len, 0, out);
|
378
|
-
}
|
415
|
+
char s1 = s[1];
|
416
|
+
|
417
|
+
dump_cstr(s, len, 0, (':' == *s || ('^' == *s && ('r' == s1 || 'i' == s1))), out);
|
379
418
|
}
|
380
419
|
|
381
420
|
static void
|
382
421
|
dump_sym_comp(VALUE obj, Out out) {
|
383
422
|
const char *sym = rb_id2name(SYM2ID(obj));
|
384
423
|
|
385
|
-
dump_cstr(sym, strlen(sym), 0, out);
|
424
|
+
dump_cstr(sym, strlen(sym), 0, 0, out);
|
386
425
|
}
|
387
426
|
|
388
427
|
static void
|
@@ -390,29 +429,14 @@ dump_sym_obj(VALUE obj, Out out) {
|
|
390
429
|
const char *sym = rb_id2name(SYM2ID(obj));
|
391
430
|
size_t len = strlen(sym);
|
392
431
|
|
393
|
-
|
394
|
-
if (out->end - out->cur <= 6) {
|
395
|
-
grow(out, 6);
|
396
|
-
}
|
397
|
-
*out->cur++ = '{';
|
398
|
-
*out->cur++ = '"';
|
399
|
-
*out->cur++ = '^';
|
400
|
-
*out->cur++ = 'm';
|
401
|
-
*out->cur++ = '"';
|
402
|
-
*out->cur++ = ':';
|
403
|
-
dump_cstr(sym, len, 0, out);
|
404
|
-
*out->cur++ = '}';
|
405
|
-
*out->cur = '\0';
|
406
|
-
} else {
|
407
|
-
dump_cstr(sym, len, 1, out);
|
408
|
-
}
|
432
|
+
dump_cstr(sym, len, 1, 0, out);
|
409
433
|
}
|
410
434
|
|
411
435
|
static void
|
412
436
|
dump_class_comp(VALUE obj, Out out) {
|
413
437
|
const char *s = rb_class2name(obj);
|
414
438
|
|
415
|
-
dump_cstr(s, strlen(s), 0, out);
|
439
|
+
dump_cstr(s, strlen(s), 0, 0, out);
|
416
440
|
}
|
417
441
|
|
418
442
|
static void
|
@@ -429,25 +453,47 @@ dump_class_obj(VALUE obj, Out out) {
|
|
429
453
|
*out->cur++ = 'c';
|
430
454
|
*out->cur++ = '"';
|
431
455
|
*out->cur++ = ':';
|
432
|
-
dump_cstr(s, len, 0, out);
|
456
|
+
dump_cstr(s, len, 0, 0, out);
|
433
457
|
*out->cur++ = '}';
|
434
458
|
*out->cur = '\0';
|
435
459
|
}
|
436
460
|
|
437
461
|
static void
|
438
462
|
dump_array(VALUE a, int depth, Out out) {
|
439
|
-
VALUE
|
440
|
-
size_t
|
441
|
-
int cnt
|
463
|
+
VALUE *np;
|
464
|
+
size_t size;
|
465
|
+
int cnt;
|
442
466
|
int d2 = depth + 1;
|
443
|
-
|
467
|
+
long id = check_circular(a, out);
|
468
|
+
|
469
|
+
if (id < 0) {
|
470
|
+
return;
|
471
|
+
}
|
472
|
+
np = RARRAY_PTR(a);
|
473
|
+
cnt = (int)RARRAY_LEN(a);
|
474
|
+
*out->cur++ = '[';
|
475
|
+
if (0 < id) {
|
476
|
+
size = d2 * out->indent + 16;
|
477
|
+
if (out->end - out->cur <= (long)size) {
|
478
|
+
grow(out, size);
|
479
|
+
}
|
480
|
+
fill_indent(out, d2);
|
481
|
+
*out->cur++ = '"';
|
482
|
+
*out->cur++ = '^';
|
483
|
+
*out->cur++ = 'i';
|
484
|
+
dump_ulong(id, out);
|
485
|
+
*out->cur++ = '"';
|
486
|
+
}
|
487
|
+
size = 2;
|
444
488
|
if (out->end - out->cur <= (long)size) {
|
445
489
|
grow(out, size);
|
446
490
|
}
|
447
|
-
*out->cur++ = '[';
|
448
491
|
if (0 == cnt) {
|
449
492
|
*out->cur++ = ']';
|
450
493
|
} else {
|
494
|
+
if (0 < id) {
|
495
|
+
*out->cur++ = ',';
|
496
|
+
}
|
451
497
|
size = d2 * out->indent + 2;
|
452
498
|
for (; 0 < cnt; cnt--, np++) {
|
453
499
|
if (out->end - out->cur <= (long)size) {
|
@@ -456,7 +502,6 @@ dump_array(VALUE a, int depth, Out out) {
|
|
456
502
|
fill_indent(out, d2);
|
457
503
|
dump_val(*np, d2, out);
|
458
504
|
if (1 < cnt) {
|
459
|
-
// TBD check size?
|
460
505
|
*out->cur++ = ',';
|
461
506
|
}
|
462
507
|
}
|
@@ -501,7 +546,6 @@ hash_cb_object(VALUE key, VALUE value, Out out) {
|
|
501
546
|
grow(out, size);
|
502
547
|
}
|
503
548
|
fill_indent(out, depth);
|
504
|
-
// TBD if key is a string else dump with unique key for and entry array
|
505
549
|
if (rb_type(key) == T_STRING) {
|
506
550
|
dump_str_obj(key, out);
|
507
551
|
*out->cur++ = ':';
|
@@ -558,17 +602,35 @@ hash_cb_object(VALUE key, VALUE value, Out out) {
|
|
558
602
|
|
559
603
|
static void
|
560
604
|
dump_hash(VALUE obj, int depth, int mode, Out out) {
|
561
|
-
int
|
605
|
+
int cnt = (int)RHASH_SIZE(obj);
|
606
|
+
size_t size = depth * out->indent + 2;
|
562
607
|
|
563
608
|
if (out->end - out->cur <= 2) {
|
564
609
|
grow(out, 2);
|
565
610
|
}
|
566
|
-
*out->cur++ = '{';
|
567
611
|
if (0 == cnt) {
|
612
|
+
*out->cur++ = '{';
|
568
613
|
*out->cur++ = '}';
|
569
614
|
} else {
|
570
|
-
|
615
|
+
long id = check_circular(obj, out);
|
571
616
|
|
617
|
+
if (0 > id) {
|
618
|
+
return;
|
619
|
+
}
|
620
|
+
*out->cur++ = '{';
|
621
|
+
if (0 < id) {
|
622
|
+
if (out->end - out->cur <= (long)size + 16) {
|
623
|
+
grow(out, size + 16);
|
624
|
+
}
|
625
|
+
fill_indent(out, depth + 1);
|
626
|
+
*out->cur++ = '"';
|
627
|
+
*out->cur++ = '^';
|
628
|
+
*out->cur++ = 'i';
|
629
|
+
*out->cur++ = '"';
|
630
|
+
*out->cur++ = ':';
|
631
|
+
dump_ulong(id, out);
|
632
|
+
*out->cur++ = ',';
|
633
|
+
}
|
572
634
|
out->depth = depth + 1;
|
573
635
|
if (ObjectMode == mode) {
|
574
636
|
rb_hash_foreach(obj, hash_cb_object, (VALUE)out);
|
@@ -656,6 +718,13 @@ dump_obj_comp(VALUE obj, int depth, Out out) {
|
|
656
718
|
rb_raise(rb_eTypeError, "%s.to_hash() did not return a Hash.\n", rb_class2name(rb_obj_class(obj)));
|
657
719
|
}
|
658
720
|
dump_hash(h, depth, out->opts->mode, out);
|
721
|
+
} else if (rb_respond_to(obj, oj_as_json_id)) {
|
722
|
+
VALUE h = rb_funcall(obj, oj_as_json_id, 0);
|
723
|
+
|
724
|
+
if (T_HASH != rb_type(h)) {
|
725
|
+
rb_raise(rb_eTypeError, "%s.as_json() did not return a Hash.\n", rb_class2name(rb_obj_class(obj)));
|
726
|
+
}
|
727
|
+
dump_hash(h, depth, out->opts->mode, out);
|
659
728
|
} else if (rb_respond_to(obj, oj_to_json_id)) {
|
660
729
|
VALUE rs = rb_funcall(obj, oj_to_json_id, 0);
|
661
730
|
const char *s = StringValuePtr(rs);
|
@@ -667,14 +736,18 @@ dump_obj_comp(VALUE obj, int depth, Out out) {
|
|
667
736
|
memcpy(out->cur, s, len);
|
668
737
|
out->cur += len;
|
669
738
|
} else {
|
670
|
-
dump_obj_attrs(obj, 0, depth, out);
|
739
|
+
dump_obj_attrs(obj, 0, 0, depth, out);
|
671
740
|
}
|
672
741
|
*out->cur = '\0';
|
673
742
|
}
|
674
743
|
|
675
744
|
inline static void
|
676
745
|
dump_obj_obj(VALUE obj, int depth, Out out) {
|
677
|
-
|
746
|
+
long id = check_circular(obj, out);
|
747
|
+
|
748
|
+
if (0 <= id) {
|
749
|
+
dump_obj_attrs(obj, 1, id, depth, out);
|
750
|
+
}
|
678
751
|
}
|
679
752
|
|
680
753
|
static int
|
@@ -689,14 +762,14 @@ dump_attr_cb(ID key, VALUE value, Out out) {
|
|
689
762
|
fill_indent(out, depth);
|
690
763
|
if ('@' == *attr) {
|
691
764
|
attr++;
|
692
|
-
dump_cstr(attr, strlen(attr), 0, out);
|
765
|
+
dump_cstr(attr, strlen(attr), 0, 0, out);
|
693
766
|
} else {
|
694
767
|
char buf[32];
|
695
768
|
|
696
769
|
*buf = '~';
|
697
770
|
strncpy(buf + 1, attr, sizeof(buf) - 2);
|
698
771
|
buf[sizeof(buf) - 1] = '\0';
|
699
|
-
dump_cstr(buf, strlen(buf), 0, out);
|
772
|
+
dump_cstr(buf, strlen(buf), 0, 0, out);
|
700
773
|
}
|
701
774
|
*out->cur++ = ':';
|
702
775
|
dump_val(value, depth, out);
|
@@ -707,7 +780,7 @@ dump_attr_cb(ID key, VALUE value, Out out) {
|
|
707
780
|
}
|
708
781
|
|
709
782
|
static void
|
710
|
-
dump_obj_attrs(VALUE obj, int with_class, int depth, Out out) {
|
783
|
+
dump_obj_attrs(VALUE obj, int with_class, slot_t id, int depth, Out out) {
|
711
784
|
size_t size;
|
712
785
|
int d2 = depth + 1;
|
713
786
|
|
@@ -729,7 +802,21 @@ dump_obj_attrs(VALUE obj, int with_class, int depth, Out out) {
|
|
729
802
|
*out->cur++ = 'o';
|
730
803
|
*out->cur++ = '"';
|
731
804
|
*out->cur++ = ':';
|
732
|
-
dump_cstr(class_name, clen, 0, out);
|
805
|
+
dump_cstr(class_name, clen, 0, 0, out);
|
806
|
+
}
|
807
|
+
if (0 < id) {
|
808
|
+
size = d2 * out->indent + 16;
|
809
|
+
if (out->end - out->cur <= (long)size) {
|
810
|
+
grow(out, size);
|
811
|
+
}
|
812
|
+
*out->cur++ = ',';
|
813
|
+
fill_indent(out, d2);
|
814
|
+
*out->cur++ = '"';
|
815
|
+
*out->cur++ = '^';
|
816
|
+
*out->cur++ = 'i';
|
817
|
+
*out->cur++ = '"';
|
818
|
+
*out->cur++ = ':';
|
819
|
+
dump_ulong(id, out);
|
733
820
|
}
|
734
821
|
{
|
735
822
|
int cnt;
|
@@ -763,14 +850,14 @@ dump_obj_attrs(VALUE obj, int with_class, int depth, Out out) {
|
|
763
850
|
attr = rb_id2name(vid);
|
764
851
|
if ('@' == *attr) {
|
765
852
|
attr++;
|
766
|
-
dump_cstr(attr, strlen(attr), 0, out);
|
853
|
+
dump_cstr(attr, strlen(attr), 0, 0, out);
|
767
854
|
} else {
|
768
855
|
char buf[32];
|
769
856
|
|
770
857
|
*buf = '~';
|
771
858
|
strncpy(buf + 1, attr, sizeof(buf) - 2);
|
772
859
|
buf[sizeof(buf) - 1] = '\0';
|
773
|
-
dump_cstr(buf, strlen(attr) + 1, 0, out);
|
860
|
+
dump_cstr(buf, strlen(attr) + 1, 0, 0, out);
|
774
861
|
}
|
775
862
|
*out->cur++ = ':';
|
776
863
|
dump_val(rb_ivar_get(obj, vid), d2, out);
|
@@ -788,6 +875,73 @@ dump_obj_attrs(VALUE obj, int with_class, int depth, Out out) {
|
|
788
875
|
*out->cur = '\0';
|
789
876
|
}
|
790
877
|
|
878
|
+
static void
|
879
|
+
dump_struct_comp(VALUE obj, int depth, Out out) {
|
880
|
+
if (rb_respond_to(obj, oj_to_hash_id)) {
|
881
|
+
VALUE h = rb_funcall(obj, oj_to_hash_id, 0);
|
882
|
+
|
883
|
+
if (T_HASH != rb_type(h)) {
|
884
|
+
rb_raise(rb_eTypeError, "%s.to_hash() did not return a Hash.\n", rb_class2name(rb_obj_class(obj)));
|
885
|
+
}
|
886
|
+
dump_hash(h, depth, out->opts->mode, out);
|
887
|
+
} else if (rb_respond_to(obj, oj_to_json_id)) {
|
888
|
+
VALUE rs = rb_funcall(obj, oj_to_json_id, 0);
|
889
|
+
const char *s = StringValuePtr(rs);
|
890
|
+
int len = (int)RSTRING_LEN(rs);
|
891
|
+
|
892
|
+
if (out->end - out->cur <= len) {
|
893
|
+
grow(out, len);
|
894
|
+
}
|
895
|
+
memcpy(out->cur, s, len);
|
896
|
+
out->cur += len;
|
897
|
+
} else {
|
898
|
+
dump_struct_obj(obj, depth, out);
|
899
|
+
}
|
900
|
+
}
|
901
|
+
|
902
|
+
static void
|
903
|
+
dump_struct_obj(VALUE obj, int depth, Out out) {
|
904
|
+
VALUE clas = rb_obj_class(obj);
|
905
|
+
const char *class_name = rb_class2name(clas);
|
906
|
+
VALUE *vp;
|
907
|
+
int i;
|
908
|
+
int d2 = depth + 1;
|
909
|
+
int d3 = d2 + 1;
|
910
|
+
size_t len = strlen(class_name);
|
911
|
+
size_t size = d2 * out->indent + d3 * out->indent + 10 + len;
|
912
|
+
|
913
|
+
if (out->end - out->cur <= (long)size) {
|
914
|
+
grow(out, size);
|
915
|
+
}
|
916
|
+
*out->cur++ = '{';
|
917
|
+
fill_indent(out, d2);
|
918
|
+
*out->cur++ = '"';
|
919
|
+
*out->cur++ = '^';
|
920
|
+
*out->cur++ = 'u';
|
921
|
+
*out->cur++ = '"';
|
922
|
+
*out->cur++ = ':';
|
923
|
+
*out->cur++ = '[';
|
924
|
+
fill_indent(out, d3);
|
925
|
+
*out->cur++ = '"';
|
926
|
+
memcpy(out->cur, class_name, len);
|
927
|
+
out->cur += len;
|
928
|
+
*out->cur++ = '"';
|
929
|
+
*out->cur++ = ',';
|
930
|
+
size = d3 * out->indent + 2;
|
931
|
+
for (i = (int)RSTRUCT_LEN(obj), vp = RSTRUCT_PTR(obj); 0 < i; i--, vp++) {
|
932
|
+
if (out->end - out->cur <= (long)size) {
|
933
|
+
grow(out, size);
|
934
|
+
}
|
935
|
+
fill_indent(out, d3);
|
936
|
+
dump_val(*vp, d3, out);
|
937
|
+
*out->cur++ = ',';
|
938
|
+
}
|
939
|
+
out->cur--;
|
940
|
+
*out->cur++ = ']';
|
941
|
+
*out->cur++ = '}';
|
942
|
+
*out->cur = '\0';
|
943
|
+
}
|
944
|
+
|
791
945
|
static void
|
792
946
|
raise_strict(VALUE obj) {
|
793
947
|
rb_raise(rb_eTypeError, "Failed to dump %s Object to JSON in strict mode.\n", rb_class2name(rb_obj_class(obj)));
|
@@ -850,6 +1004,14 @@ dump_val(VALUE obj, int depth, Out out) {
|
|
850
1004
|
}
|
851
1005
|
break;
|
852
1006
|
case T_STRUCT: // for Range
|
1007
|
+
switch (out->opts->mode) {
|
1008
|
+
case StrictMode: raise_strict(obj); break;
|
1009
|
+
case NullMode: dump_nil(out); break;
|
1010
|
+
case CompatMode: dump_struct_comp(obj, depth, out); break;
|
1011
|
+
case ObjectMode:
|
1012
|
+
default: dump_struct_obj(obj, depth, out); break;
|
1013
|
+
}
|
1014
|
+
break;
|
853
1015
|
#if (defined T_COMPLEX && defined RCOMPLEX)
|
854
1016
|
case T_COMPLEX:
|
855
1017
|
#endif
|
@@ -857,9 +1019,13 @@ dump_val(VALUE obj, int depth, Out out) {
|
|
857
1019
|
case T_RATIONAL:
|
858
1020
|
#endif
|
859
1021
|
case T_REGEXP:
|
860
|
-
|
861
|
-
|
862
|
-
|
1022
|
+
switch (out->opts->mode) {
|
1023
|
+
case StrictMode: raise_strict(obj); break;
|
1024
|
+
case NullMode: dump_nil(out); break;
|
1025
|
+
case CompatMode:
|
1026
|
+
case ObjectMode:
|
1027
|
+
default: dump_obj_comp(obj, depth, out); break;
|
1028
|
+
}
|
863
1029
|
break;
|
864
1030
|
default:
|
865
1031
|
rb_raise(rb_eNotImpError, "Failed to dump '%s' Object (%02x)\n",
|
@@ -873,19 +1039,17 @@ dump_obj_to_json(VALUE obj, Options copts, Out out) {
|
|
873
1039
|
out->buf = (char*)malloc(65336);
|
874
1040
|
out->end = out->buf + 65325; // 1 less than end plus extra for possible errors
|
875
1041
|
out->cur = out->buf;
|
876
|
-
|
877
|
-
// out->circ_cnt = 0;
|
1042
|
+
out->circ_cnt = 0;
|
878
1043
|
out->opts = copts;
|
879
1044
|
out->hash_cnt = 0;
|
880
|
-
|
881
|
-
|
882
|
-
|
1045
|
+
if (Yes == copts->circular) {
|
1046
|
+
oj_cache8_new(&out->circ_cache);
|
1047
|
+
}
|
883
1048
|
out->indent = copts->indent;
|
884
1049
|
dump_val(obj, 0, out);
|
885
|
-
|
886
|
-
|
887
|
-
|
888
|
-
}*/
|
1050
|
+
if (Yes == copts->circular) {
|
1051
|
+
oj_cache8_delete(out->circ_cache);
|
1052
|
+
}
|
889
1053
|
}
|
890
1054
|
|
891
1055
|
char*
|