oj 3.13.7 → 3.13.23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +75 -0
- data/README.md +11 -0
- data/ext/oj/buf.h +4 -0
- data/ext/oj/circarray.c +1 -1
- data/ext/oj/code.c +15 -22
- data/ext/oj/compat.c +10 -10
- data/ext/oj/custom.c +66 -112
- data/ext/oj/dump.c +147 -184
- data/ext/oj/dump.h +25 -8
- data/ext/oj/dump_compat.c +47 -89
- data/ext/oj/dump_leaf.c +14 -58
- data/ext/oj/dump_object.c +72 -188
- data/ext/oj/dump_strict.c +19 -31
- data/ext/oj/encoder.c +43 -0
- data/ext/oj/extconf.rb +5 -4
- data/ext/oj/fast.c +36 -24
- data/ext/oj/intern.c +22 -12
- data/ext/oj/intern.h +1 -1
- data/ext/oj/mimic_json.c +74 -73
- data/ext/oj/object.c +54 -72
- data/ext/oj/odd.c +83 -63
- data/ext/oj/odd.h +13 -13
- data/ext/oj/oj.c +166 -175
- data/ext/oj/oj.h +25 -3
- data/ext/oj/parse.c +123 -79
- data/ext/oj/parse.h +2 -0
- data/ext/oj/parser.c +77 -21
- data/ext/oj/parser.h +12 -0
- data/ext/oj/rails.c +46 -70
- data/ext/oj/rails.h +1 -1
- data/ext/oj/reader.c +2 -0
- data/ext/oj/saj.c +11 -23
- data/ext/oj/saj2.c +333 -85
- data/ext/oj/saj2.h +23 -0
- data/ext/oj/sparse.c +4 -0
- data/ext/oj/stream_writer.c +3 -1
- data/ext/oj/strict.c +13 -13
- data/ext/oj/string_writer.c +12 -5
- data/ext/oj/usual.c +86 -131
- data/ext/oj/usual.h +68 -0
- data/ext/oj/val_stack.c +1 -1
- data/ext/oj/validate.c +21 -26
- data/ext/oj/wab.c +22 -27
- data/lib/oj/saj.rb +20 -6
- data/lib/oj/state.rb +1 -1
- data/lib/oj/version.rb +1 -1
- data/pages/Compatibility.md +1 -1
- data/pages/JsonGem.md +15 -0
- data/pages/Modes.md +6 -3
- data/pages/Options.md +6 -0
- data/pages/Rails.md +12 -0
- data/test/activesupport7/abstract_unit.rb +49 -0
- data/test/activesupport7/decoding_test.rb +125 -0
- data/test/activesupport7/encoding_test.rb +486 -0
- data/test/activesupport7/encoding_test_cases.rb +104 -0
- data/test/activesupport7/time_zone_test_helpers.rb +47 -0
- data/test/bar.rb +3 -8
- data/test/bug.rb +16 -0
- data/test/foo.rb +71 -7
- data/test/helper.rb +8 -2
- data/test/json_gem/json_generator_test.rb +5 -4
- data/test/json_gem/json_parser_test.rb +8 -1
- data/test/json_gem/test_helper.rb +7 -3
- data/test/perf_dump.rb +50 -0
- data/test/test_compat.rb +25 -0
- data/test/test_custom.rb +13 -2
- data/test/test_fast.rb +37 -7
- data/test/test_file.rb +23 -7
- data/test/test_gc.rb +11 -0
- data/test/test_object.rb +8 -10
- data/test/test_parser.rb +3 -19
- data/test/test_parser_debug.rb +27 -0
- data/test/test_parser_saj.rb +92 -2
- data/test/test_saj.rb +1 -1
- data/test/test_scp.rb +2 -4
- data/test/test_strict.rb +2 -0
- data/test/test_various.rb +32 -2
- data/test/test_wab.rb +2 -0
- data/test/tests.rb +9 -1
- data/test/tests_mimic.rb +9 -0
- data/test/tests_mimic_addition.rb +9 -0
- metadata +15 -115
data/ext/oj/object.c
CHANGED
@@ -35,7 +35,7 @@ static VALUE calc_hash_key(ParseInfo pi, Val kval, char k1) {
|
|
35
35
|
return ID2SYM(rb_intern3(kval->key + 1, kval->klen - 1, oj_utf8_encoding));
|
36
36
|
}
|
37
37
|
if (Yes == pi->options.sym_key) {
|
38
|
-
|
38
|
+
return ID2SYM(rb_intern3(kval->key, kval->klen, oj_utf8_encoding));
|
39
39
|
}
|
40
40
|
#if HAVE_RB_ENC_INTERNED_STR
|
41
41
|
rkey = rb_enc_interned_str(kval->key, kval->klen, oj_utf8_encoding);
|
@@ -60,16 +60,11 @@ static VALUE str_to_value(ParseInfo pi, const char *str, size_t len, const char
|
|
60
60
|
}
|
61
61
|
rstr = oj_circ_array_get(pi->circ_array, i);
|
62
62
|
} else {
|
63
|
-
|
63
|
+
rstr = rb_utf8_str_new(str, len);
|
64
64
|
}
|
65
65
|
return rstr;
|
66
66
|
}
|
67
67
|
|
68
|
-
#if (RUBY_VERSION_MAJOR == 1 && RUBY_VERSION_MINOR == 8)
|
69
|
-
static VALUE oj_parse_xml_time(const char *str, int len) {
|
70
|
-
return rb_funcall(rb_cTime, oj_parse_id, 1, rb_str_new(str, len));
|
71
|
-
}
|
72
|
-
#else
|
73
68
|
// The much faster approach (4x faster)
|
74
69
|
static int parse_num(const char *str, const char *end, int cnt) {
|
75
70
|
int n = 0;
|
@@ -201,7 +196,6 @@ oj_parse_xml_time(const char *str, int len) {
|
|
201
196
|
}
|
202
197
|
return rb_funcall2(rb_cTime, oj_new_id, 7, args);
|
203
198
|
}
|
204
|
-
#endif
|
205
199
|
|
206
200
|
static int hat_cstr(ParseInfo pi, Val parent, Val kval, const char *str, size_t len) {
|
207
201
|
const char *key = kval->key;
|
@@ -226,13 +220,10 @@ static int hat_cstr(ParseInfo pi, Val parent, Val kval, const char *str, size_t
|
|
226
220
|
}
|
227
221
|
parent->val = odd->clas;
|
228
222
|
parent->odd_args = oj_odd_alloc_args(odd);
|
229
|
-
} break;
|
230
|
-
case 'm':
|
231
|
-
parent->val = ID2SYM(rb_intern3(str + 1, len - 1, oj_utf8_encoding));
|
232
|
-
break;
|
233
|
-
case 's':
|
234
|
-
parent->val = rb_utf8_str_new(str, len);
|
235
223
|
break;
|
224
|
+
}
|
225
|
+
case 'm': parent->val = ID2SYM(rb_intern3(str + 1, len - 1, oj_utf8_encoding)); break;
|
226
|
+
case 's': parent->val = rb_utf8_str_new(str, len); break;
|
236
227
|
case 'c': // class
|
237
228
|
{
|
238
229
|
VALUE clas = oj_name2class(pi, str, len, Yes == pi->options.auto_define, rb_eArgError);
|
@@ -242,7 +233,8 @@ static int hat_cstr(ParseInfo pi, Val parent, Val kval, const char *str, size_t
|
|
242
233
|
} else {
|
243
234
|
parent->val = clas;
|
244
235
|
}
|
245
|
-
|
236
|
+
break;
|
237
|
+
}
|
246
238
|
case 't': // time
|
247
239
|
parent->val = oj_parse_xml_time(str, (int)len);
|
248
240
|
break;
|
@@ -277,27 +269,17 @@ static int hat_num(ParseInfo pi, Val parent, Val kval, NumInfo ni) {
|
|
277
269
|
// match the expected value.
|
278
270
|
parent->val = rb_funcall2(parent->val, oj_utc_id, 0, 0);
|
279
271
|
} else if (ni->has_exp) {
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
sec_as_time(t, &ti);
|
285
|
-
args[0] = LONG2NUM((long)(ti.year));
|
286
|
-
args[1] = LONG2NUM(ti.mon);
|
287
|
-
args[2] = LONG2NUM(ti.day);
|
288
|
-
args[3] = LONG2NUM(ti.hour);
|
289
|
-
args[4] = LONG2NUM(ti.min);
|
290
|
-
args[5] = rb_float_new((double)ti.sec + ((double)nsec + 0.5) / 1000000000.0);
|
291
|
-
args[6] = LONG2NUM(ni->exp);
|
292
|
-
parent->val = rb_funcall2(rb_cTime, oj_new_id, 7, args);
|
272
|
+
struct timespec ts;
|
273
|
+
ts.tv_sec = ni->i;
|
274
|
+
ts.tv_nsec = nsec;
|
275
|
+
parent->val = rb_time_timespec_new(&ts, (int)ni->exp);
|
293
276
|
} else {
|
294
277
|
parent->val = rb_time_nano_new(ni->i, (long)nsec);
|
295
278
|
}
|
296
279
|
}
|
297
280
|
break;
|
298
|
-
case 'i':
|
299
|
-
if (!ni->infinity && !ni->neg && 1 == ni->div && 0 == ni->exp &&
|
300
|
-
0 != pi->circ_array) { // fixnum
|
281
|
+
case 'i': // circular index
|
282
|
+
if (!ni->infinity && !ni->neg && 1 == ni->div && 0 == ni->exp && 0 != pi->circ_array) { // fixnum
|
301
283
|
if (Qnil == parent->val) {
|
302
284
|
parent->val = rb_hash_new();
|
303
285
|
}
|
@@ -334,7 +316,7 @@ static int hat_value(ParseInfo pi, Val parent, const char *key, size_t klen, vol
|
|
334
316
|
int i, cnt = (int)RARRAY_LEN(e1);
|
335
317
|
|
336
318
|
for (i = 0; i < cnt; i++) {
|
337
|
-
rstr =
|
319
|
+
rstr = RARRAY_AREF(e1, i);
|
338
320
|
args[i] = rb_funcall(rstr, oj_to_sym_id, 0);
|
339
321
|
}
|
340
322
|
sc = rb_funcall2(rb_cStruct, oj_new_id, cnt, args);
|
@@ -342,26 +324,30 @@ static int hat_value(ParseInfo pi, Val parent, const char *key, size_t klen, vol
|
|
342
324
|
// If struct is not defined then we let this fail and raise an exception.
|
343
325
|
sc = oj_name2struct(pi, *RARRAY_PTR(value), rb_eArgError);
|
344
326
|
}
|
345
|
-
|
346
|
-
|
347
|
-
|
327
|
+
if (sc == rb_cRange) {
|
328
|
+
parent->val = rb_class_new_instance(len - 1, RARRAY_PTR(value) + 1, rb_cRange);
|
329
|
+
} else {
|
330
|
+
// Create a properly initialized struct instance without calling the initialize method.
|
331
|
+
parent->val = rb_obj_alloc(sc);
|
332
|
+
// If the JSON array has more entries than the struct class allows, we record an error.
|
348
333
|
#ifdef RSTRUCT_LEN
|
349
334
|
#if RSTRUCT_LEN_RETURNS_INTEGER_OBJECT
|
350
335
|
slen = (int)NUM2LONG(RSTRUCT_LEN(parent->val));
|
351
336
|
#else // RSTRUCT_LEN_RETURNS_INTEGER_OBJECT
|
352
|
-
|
337
|
+
slen = (int)RSTRUCT_LEN(parent->val);
|
353
338
|
#endif // RSTRUCT_LEN_RETURNS_INTEGER_OBJECT
|
354
339
|
#else
|
355
|
-
|
340
|
+
slen = FIX2INT(rb_funcall2(parent->val, oj_length_id, 0, 0));
|
356
341
|
#endif
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
342
|
+
// MRI >= 1.9
|
343
|
+
if (len - 1 > slen) {
|
344
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "Invalid struct data");
|
345
|
+
} else {
|
346
|
+
int i;
|
362
347
|
|
363
|
-
|
364
|
-
|
348
|
+
for (i = 0; i < len - 1; i++) {
|
349
|
+
rb_struct_aset(parent->val, INT2FIX(i), RARRAY_PTR(value)[i + 1]);
|
350
|
+
}
|
365
351
|
}
|
366
352
|
}
|
367
353
|
return 1;
|
@@ -383,11 +369,17 @@ static int hat_value(ParseInfo pi, Val parent, const char *key, size_t klen, vol
|
|
383
369
|
}
|
384
370
|
|
385
371
|
void oj_set_obj_ivar(Val parent, Val kval, VALUE value) {
|
386
|
-
|
372
|
+
if (kval->klen == 5 && strncmp("~mesg", kval->key, 5) == 0 && rb_obj_is_kind_of(parent->val, rb_eException)) {
|
373
|
+
parent->val = rb_funcall(parent->val, rb_intern("exception"), 1, value);
|
374
|
+
} else if (kval->klen == 3 && strncmp("~bt", kval->key, 3) == 0 && rb_obj_is_kind_of(parent->val, rb_eException)) {
|
375
|
+
rb_funcall(parent->val, rb_intern("set_backtrace"), 1, value);
|
376
|
+
} else {
|
377
|
+
rb_ivar_set(parent->val, oj_attr_intern(kval->key, kval->klen), value);
|
378
|
+
}
|
387
379
|
}
|
388
380
|
|
389
381
|
static void hash_set_cstr(ParseInfo pi, Val kval, const char *str, size_t len, const char *orig) {
|
390
|
-
const char
|
382
|
+
const char *key = kval->key;
|
391
383
|
int klen = kval->klen;
|
392
384
|
Val parent = stack_peek(&pi->stack);
|
393
385
|
volatile VALUE rval = Qnil;
|
@@ -402,9 +394,7 @@ WHICH_TYPE:
|
|
402
394
|
}
|
403
395
|
break;
|
404
396
|
case T_HASH:
|
405
|
-
rb_hash_aset(parent->val,
|
406
|
-
calc_hash_key(pi, kval, parent->k1),
|
407
|
-
str_to_value(pi, str, len, orig));
|
397
|
+
rb_hash_aset(parent->val, calc_hash_key(pi, kval, parent->k1), str_to_value(pi, str, len, orig));
|
408
398
|
break;
|
409
399
|
case T_STRING:
|
410
400
|
rval = str_to_value(pi, str, len, orig);
|
@@ -456,13 +446,13 @@ WHICH_TYPE:
|
|
456
446
|
rb_class2name(rb_obj_class(parent->val)));
|
457
447
|
return;
|
458
448
|
}
|
459
|
-
if (Yes == pi->options.trace) {
|
449
|
+
if (RB_UNLIKELY(Yes == pi->options.trace)) {
|
460
450
|
oj_trace_parse_call("set_string", pi, __FILE__, __LINE__, rval);
|
461
451
|
}
|
462
452
|
}
|
463
453
|
|
464
454
|
static void hash_set_num(ParseInfo pi, Val kval, NumInfo ni) {
|
465
|
-
const char
|
455
|
+
const char *key = kval->key;
|
466
456
|
int klen = kval->klen;
|
467
457
|
Val parent = stack_peek(&pi->stack);
|
468
458
|
volatile VALUE rval = Qnil;
|
@@ -481,8 +471,8 @@ WHICH_TYPE:
|
|
481
471
|
rb_hash_aset(parent->val, calc_hash_key(pi, kval, parent->k1), rval);
|
482
472
|
break;
|
483
473
|
case T_OBJECT:
|
484
|
-
if (2 == klen && '^' == *key && 'i' == key[1] && !ni->infinity && !ni->neg &&
|
485
|
-
|
474
|
+
if (2 == klen && '^' == *key && 'i' == key[1] && !ni->infinity && !ni->neg && 1 == ni->div && 0 == ni->exp &&
|
475
|
+
0 != pi->circ_array) { // fixnum
|
486
476
|
oj_circ_array_set(pi->circ_array, parent->val, ni->i);
|
487
477
|
} else {
|
488
478
|
rval = oj_num_as_value(ni);
|
@@ -527,7 +517,7 @@ WHICH_TYPE:
|
|
527
517
|
rb_class2name(rb_obj_class(parent->val)));
|
528
518
|
return;
|
529
519
|
}
|
530
|
-
if (Yes == pi->options.trace) {
|
520
|
+
if (RB_UNLIKELY(Yes == pi->options.trace)) {
|
531
521
|
oj_trace_parse_call("add_number", pi, __FILE__, __LINE__, rval);
|
532
522
|
}
|
533
523
|
}
|
@@ -559,11 +549,7 @@ WHICH_TYPE:
|
|
559
549
|
volatile VALUE *a = RARRAY_PTR(value);
|
560
550
|
|
561
551
|
if (2 != len) {
|
562
|
-
oj_set_error_at(pi,
|
563
|
-
oj_parse_error_class,
|
564
|
-
__FILE__,
|
565
|
-
__LINE__,
|
566
|
-
"invalid hash pair");
|
552
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid hash pair");
|
567
553
|
return;
|
568
554
|
}
|
569
555
|
rb_hash_aset(parent->val, *a, a[1]);
|
@@ -617,13 +603,13 @@ WHICH_TYPE:
|
|
617
603
|
rb_class2name(rb_obj_class(parent->val)));
|
618
604
|
return;
|
619
605
|
}
|
620
|
-
if (Yes == pi->options.trace) {
|
606
|
+
if (RB_UNLIKELY(Yes == pi->options.trace)) {
|
621
607
|
oj_trace_parse_call("add_value", pi, __FILE__, __LINE__, value);
|
622
608
|
}
|
623
609
|
}
|
624
610
|
|
625
611
|
static VALUE start_hash(ParseInfo pi) {
|
626
|
-
if (Yes == pi->options.trace) {
|
612
|
+
if (RB_UNLIKELY(Yes == pi->options.trace)) {
|
627
613
|
oj_trace_parse_in("start_hash", pi, __FILE__, __LINE__);
|
628
614
|
}
|
629
615
|
return Qnil;
|
@@ -637,14 +623,11 @@ static void end_hash(ParseInfo pi) {
|
|
637
623
|
} else if (NULL != parent->odd_args) {
|
638
624
|
OddArgs oa = parent->odd_args;
|
639
625
|
|
640
|
-
parent->val = rb_funcall2(oa->odd->create_obj,
|
641
|
-
oa->odd->create_op,
|
642
|
-
oa->odd->attr_cnt,
|
643
|
-
oa->args);
|
626
|
+
parent->val = rb_funcall2(oa->odd->create_obj, oa->odd->create_op, oa->odd->attr_cnt, oa->args);
|
644
627
|
oj_odd_free(oa);
|
645
628
|
parent->odd_args = NULL;
|
646
629
|
}
|
647
|
-
if (Yes == pi->options.trace) {
|
630
|
+
if (RB_UNLIKELY(Yes == pi->options.trace)) {
|
648
631
|
oj_trace_parse_hash_end(pi, __FILE__, __LINE__);
|
649
632
|
}
|
650
633
|
}
|
@@ -653,8 +636,7 @@ static void array_append_cstr(ParseInfo pi, const char *str, size_t len, const c
|
|
653
636
|
volatile VALUE rval = Qnil;
|
654
637
|
|
655
638
|
// orig lets us know whether the string was ^r1 or \u005er1
|
656
|
-
if (3 <= len && 0 != pi->circ_array && '^' == orig[0] &&
|
657
|
-
0 == rb_array_len(stack_peek(&pi->stack)->val)) {
|
639
|
+
if (3 <= len && 0 != pi->circ_array && '^' == orig[0] && 0 == rb_array_len(stack_peek(&pi->stack)->val)) {
|
658
640
|
if ('i' == str[1]) {
|
659
641
|
long i = read_long(str + 2, len - 2);
|
660
642
|
|
@@ -673,7 +655,7 @@ static void array_append_cstr(ParseInfo pi, const char *str, size_t len, const c
|
|
673
655
|
}
|
674
656
|
rval = str_to_value(pi, str, len, orig);
|
675
657
|
rb_ary_push(stack_peek(&pi->stack)->val, rval);
|
676
|
-
if (Yes == pi->options.trace) {
|
658
|
+
if (RB_UNLIKELY(Yes == pi->options.trace)) {
|
677
659
|
oj_trace_parse_call("append_string", pi, __FILE__, __LINE__, rval);
|
678
660
|
}
|
679
661
|
}
|
@@ -682,21 +664,21 @@ static void array_append_num(ParseInfo pi, NumInfo ni) {
|
|
682
664
|
volatile VALUE rval = oj_num_as_value(ni);
|
683
665
|
|
684
666
|
rb_ary_push(stack_peek(&pi->stack)->val, rval);
|
685
|
-
if (Yes == pi->options.trace) {
|
667
|
+
if (RB_UNLIKELY(Yes == pi->options.trace)) {
|
686
668
|
oj_trace_parse_call("append_number", pi, __FILE__, __LINE__, rval);
|
687
669
|
}
|
688
670
|
}
|
689
671
|
|
690
672
|
static void add_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
|
691
673
|
pi->stack.head->val = str_to_value(pi, str, len, orig);
|
692
|
-
if (Yes == pi->options.trace) {
|
674
|
+
if (RB_UNLIKELY(Yes == pi->options.trace)) {
|
693
675
|
oj_trace_parse_call("add_string", pi, __FILE__, __LINE__, pi->stack.head->val);
|
694
676
|
}
|
695
677
|
}
|
696
678
|
|
697
679
|
static void add_num(ParseInfo pi, NumInfo ni) {
|
698
680
|
pi->stack.head->val = oj_num_as_value(ni);
|
699
|
-
if (Yes == pi->options.trace) {
|
681
|
+
if (RB_UNLIKELY(Yes == pi->options.trace)) {
|
700
682
|
oj_trace_parse_call("add_num", pi, __FILE__, __LINE__, pi->stack.head->val);
|
701
683
|
}
|
702
684
|
}
|
data/ext/oj/odd.c
CHANGED
@@ -5,28 +5,27 @@
|
|
5
5
|
|
6
6
|
#include <string.h>
|
7
7
|
|
8
|
-
static
|
9
|
-
static
|
10
|
-
static
|
11
|
-
static ID
|
12
|
-
static ID
|
13
|
-
static ID
|
14
|
-
static ID
|
15
|
-
static ID denominator_id;
|
16
|
-
static ID rational_id;
|
17
|
-
static VALUE rational_class;
|
8
|
+
static Odd odds = NULL;
|
9
|
+
static ID sec_id;
|
10
|
+
static ID sec_fraction_id;
|
11
|
+
static ID to_f_id;
|
12
|
+
static ID numerator_id;
|
13
|
+
static ID denominator_id;
|
14
|
+
static ID rational_id;
|
18
15
|
|
19
16
|
static void set_class(Odd odd, const char *classname) {
|
20
17
|
const char **np;
|
21
|
-
ID
|
18
|
+
ID *idp;
|
22
19
|
|
23
|
-
odd->classname
|
24
|
-
odd->clen
|
25
|
-
odd->clas
|
20
|
+
odd->classname = classname;
|
21
|
+
odd->clen = strlen(classname);
|
22
|
+
odd->clas = rb_const_get(rb_cObject, rb_intern(classname));
|
23
|
+
rb_gc_register_mark_object(odd->clas);
|
26
24
|
odd->create_obj = odd->clas;
|
27
|
-
odd->
|
28
|
-
odd->
|
29
|
-
odd->
|
25
|
+
rb_gc_register_mark_object(odd->create_obj);
|
26
|
+
odd->create_op = rb_intern("new");
|
27
|
+
odd->is_module = (T_MODULE == rb_type(odd->clas));
|
28
|
+
odd->raw = 0;
|
30
29
|
for (np = odd->attr_names, idp = odd->attrs; 0 != *np; np++, idp++) {
|
31
30
|
*idp = rb_intern(*np);
|
32
31
|
}
|
@@ -37,15 +36,48 @@ static VALUE get_datetime_secs(VALUE obj) {
|
|
37
36
|
volatile VALUE rsecs = rb_funcall(obj, sec_id, 0);
|
38
37
|
volatile VALUE rfrac = rb_funcall(obj, sec_fraction_id, 0);
|
39
38
|
long sec = NUM2LONG(rsecs);
|
40
|
-
long long num =
|
41
|
-
long long den =
|
39
|
+
long long num = NUM2LL(rb_funcall(rfrac, numerator_id, 0));
|
40
|
+
long long den = NUM2LL(rb_funcall(rfrac, denominator_id, 0));
|
42
41
|
|
43
42
|
num += sec * den;
|
44
43
|
|
45
44
|
return rb_funcall(rb_cObject, rational_id, 2, rb_ll2inum(num), rb_ll2inum(den));
|
46
45
|
}
|
47
46
|
|
48
|
-
void
|
47
|
+
static void print_odd(Odd odd) {
|
48
|
+
const char **np;
|
49
|
+
int i;
|
50
|
+
|
51
|
+
printf(" %s {\n", odd->classname);
|
52
|
+
printf(" attr_cnt: %d %p\n", odd->attr_cnt, (void *)odd->attr_names);
|
53
|
+
printf(" attr_names: %p\n", (void *)*odd->attr_names);
|
54
|
+
printf(" attr_names: %c\n", **odd->attr_names);
|
55
|
+
for (i = odd->attr_cnt, np = odd->attr_names; 0 < i; i--, np++) {
|
56
|
+
printf(" %d %s\n", i, *np);
|
57
|
+
}
|
58
|
+
printf(" }\n");
|
59
|
+
}
|
60
|
+
|
61
|
+
void print_all_odds(const char *label) {
|
62
|
+
Odd odd;
|
63
|
+
printf("@ %s {\n", label);
|
64
|
+
for (odd = odds; NULL != odd; odd = odd->next) {
|
65
|
+
print_odd(odd);
|
66
|
+
}
|
67
|
+
printf("}\n");
|
68
|
+
}
|
69
|
+
|
70
|
+
static Odd odd_create(void) {
|
71
|
+
Odd odd = ALLOC(struct _odd);
|
72
|
+
|
73
|
+
memset(odd, 0, sizeof(struct _odd));
|
74
|
+
odd->next = odds;
|
75
|
+
odds = odd;
|
76
|
+
|
77
|
+
return odd;
|
78
|
+
}
|
79
|
+
|
80
|
+
void oj_odd_init(void) {
|
49
81
|
Odd odd;
|
50
82
|
const char **np;
|
51
83
|
|
@@ -55,11 +87,9 @@ void oj_odd_init() {
|
|
55
87
|
numerator_id = rb_intern("numerator");
|
56
88
|
denominator_id = rb_intern("denominator");
|
57
89
|
rational_id = rb_intern("Rational");
|
58
|
-
rational_class = rb_const_get(rb_cObject, rational_id);
|
59
90
|
|
60
|
-
memset(_odds, 0, sizeof(_odds));
|
61
|
-
odd = odds;
|
62
91
|
// Rational
|
92
|
+
odd = odd_create();
|
63
93
|
np = odd->attr_names;
|
64
94
|
*np++ = "numerator";
|
65
95
|
*np++ = "denominator";
|
@@ -68,8 +98,9 @@ void oj_odd_init() {
|
|
68
98
|
odd->create_obj = rb_cObject;
|
69
99
|
odd->create_op = rational_id;
|
70
100
|
odd->attr_cnt = 2;
|
101
|
+
|
71
102
|
// Date
|
72
|
-
odd
|
103
|
+
odd = odd_create();
|
73
104
|
np = odd->attr_names;
|
74
105
|
*np++ = "year";
|
75
106
|
*np++ = "month";
|
@@ -78,8 +109,9 @@ void oj_odd_init() {
|
|
78
109
|
*np++ = 0;
|
79
110
|
set_class(odd, "Date");
|
80
111
|
odd->attr_cnt = 4;
|
112
|
+
|
81
113
|
// DateTime
|
82
|
-
odd
|
114
|
+
odd = odd_create();
|
83
115
|
np = odd->attr_names;
|
84
116
|
*np++ = "year";
|
85
117
|
*np++ = "month";
|
@@ -93,8 +125,9 @@ void oj_odd_init() {
|
|
93
125
|
set_class(odd, "DateTime");
|
94
126
|
odd->attr_cnt = 8;
|
95
127
|
odd->attrFuncs[5] = get_datetime_secs;
|
128
|
+
|
96
129
|
// Range
|
97
|
-
odd
|
130
|
+
odd = odd_create();
|
98
131
|
np = odd->attr_names;
|
99
132
|
*np++ = "begin";
|
100
133
|
*np++ = "end";
|
@@ -102,15 +135,13 @@ void oj_odd_init() {
|
|
102
135
|
*np++ = 0;
|
103
136
|
set_class(odd, "Range");
|
104
137
|
odd->attr_cnt = 3;
|
105
|
-
|
106
|
-
odd_cnt = odd - odds + 1;
|
107
138
|
}
|
108
139
|
|
109
140
|
Odd oj_get_odd(VALUE clas) {
|
110
141
|
Odd odd;
|
111
142
|
const char *classname = NULL;
|
112
143
|
|
113
|
-
for (odd = odds
|
144
|
+
for (odd = odds; NULL != odd; odd = odd->next) {
|
114
145
|
if (clas == odd->clas) {
|
115
146
|
return odd;
|
116
147
|
}
|
@@ -129,21 +160,20 @@ Odd oj_get_odd(VALUE clas) {
|
|
129
160
|
Odd oj_get_oddc(const char *classname, size_t len) {
|
130
161
|
Odd odd;
|
131
162
|
|
132
|
-
for (odd = odds
|
163
|
+
for (odd = odds; NULL != odd; odd = odd->next) {
|
133
164
|
if (len == odd->clen && 0 == strncmp(classname, odd->classname, len)) {
|
134
165
|
return odd;
|
135
166
|
}
|
136
|
-
if (odd->is_module && 0 == strncmp(odd->classname, classname, odd->clen) &&
|
137
|
-
':' == classname[odd->clen]) {
|
167
|
+
if (odd->is_module && 0 == strncmp(odd->classname, classname, odd->clen) && ':' == classname[odd->clen]) {
|
138
168
|
return odd;
|
139
169
|
}
|
140
170
|
}
|
141
|
-
return
|
171
|
+
return NULL;
|
142
172
|
}
|
143
173
|
|
144
174
|
OddArgs oj_odd_alloc_args(Odd odd) {
|
145
175
|
OddArgs oa = ALLOC_N(struct _oddArgs, 1);
|
146
|
-
VALUE
|
176
|
+
VALUE *a;
|
147
177
|
int i;
|
148
178
|
|
149
179
|
oa->odd = odd;
|
@@ -159,11 +189,10 @@ void oj_odd_free(OddArgs args) {
|
|
159
189
|
|
160
190
|
int oj_odd_set_arg(OddArgs args, const char *key, size_t klen, VALUE value) {
|
161
191
|
const char **np;
|
162
|
-
VALUE
|
192
|
+
VALUE *vp;
|
163
193
|
int i;
|
164
194
|
|
165
|
-
for (i = args->odd->attr_cnt, np = args->odd->attr_names, vp = args->args; 0 < i;
|
166
|
-
i--, np++, vp++) {
|
195
|
+
for (i = args->odd->attr_cnt, np = args->odd->attr_names, vp = args->args; 0 < i; i--, np++, vp++) {
|
167
196
|
if (0 == strncmp(key, *np, klen) && '\0' == *((*np) + klen)) {
|
168
197
|
*vp = value;
|
169
198
|
return 0;
|
@@ -172,37 +201,26 @@ int oj_odd_set_arg(OddArgs args, const char *key, size_t klen, VALUE value) {
|
|
172
201
|
return -1;
|
173
202
|
}
|
174
203
|
|
175
|
-
void oj_reg_odd(VALUE
|
176
|
-
VALUE create_object,
|
177
|
-
VALUE create_method,
|
178
|
-
int mcnt,
|
179
|
-
VALUE *members,
|
180
|
-
bool raw) {
|
204
|
+
void oj_reg_odd(VALUE clas, VALUE create_object, VALUE create_method, int mcnt, VALUE *members, bool raw) {
|
181
205
|
Odd odd;
|
182
206
|
const char **np;
|
183
|
-
ID
|
207
|
+
ID *ap;
|
184
208
|
AttrGetFunc *fp;
|
185
209
|
|
186
|
-
|
187
|
-
odds = ALLOC_N(struct _odd, odd_cnt + 1);
|
188
|
-
|
189
|
-
memcpy(odds, _odds, sizeof(struct _odd) * odd_cnt);
|
190
|
-
} else {
|
191
|
-
REALLOC_N(odds, struct _odd, odd_cnt + 1);
|
192
|
-
}
|
193
|
-
odd = odds + odd_cnt;
|
210
|
+
odd = odd_create();
|
194
211
|
odd->clas = clas;
|
212
|
+
rb_gc_register_mark_object(odd->clas);
|
195
213
|
if (NULL == (odd->classname = strdup(rb_class2name(clas)))) {
|
196
|
-
rb_raise(rb_eNoMemError, "for
|
214
|
+
rb_raise(rb_eNoMemError, "for class name.");
|
197
215
|
}
|
198
216
|
odd->clen = strlen(odd->classname);
|
199
217
|
odd->create_obj = create_object;
|
200
|
-
odd->
|
201
|
-
odd->
|
202
|
-
odd->
|
203
|
-
odd->
|
204
|
-
|
205
|
-
|
218
|
+
rb_gc_register_mark_object(odd->create_obj);
|
219
|
+
odd->create_op = SYM2ID(create_method);
|
220
|
+
odd->attr_cnt = mcnt;
|
221
|
+
odd->is_module = (T_MODULE == rb_type(clas));
|
222
|
+
odd->raw = raw;
|
223
|
+
for (ap = odd->attrs, np = odd->attr_names, fp = odd->attrFuncs; 0 < mcnt; mcnt--, ap++, np++, members++, fp++) {
|
206
224
|
*fp = 0;
|
207
225
|
switch (rb_type(*members)) {
|
208
226
|
case T_STRING:
|
@@ -210,14 +228,16 @@ void oj_reg_odd(VALUE clas,
|
|
210
228
|
rb_raise(rb_eNoMemError, "for attribute name.");
|
211
229
|
}
|
212
230
|
break;
|
213
|
-
case T_SYMBOL:
|
214
|
-
|
215
|
-
|
231
|
+
case T_SYMBOL:
|
232
|
+
// The symbol can move and invalidate the name so make a copy.
|
233
|
+
if (NULL == (*np = strdup(rb_id2name(SYM2ID(*members))))) {
|
234
|
+
rb_raise(rb_eNoMemError, "for attribute name.");
|
235
|
+
}
|
216
236
|
break;
|
237
|
+
default: rb_raise(rb_eArgError, "registered member identifiers must be Strings or Symbols."); break;
|
217
238
|
}
|
218
239
|
*ap = rb_intern(*np);
|
219
240
|
}
|
220
241
|
*np = 0;
|
221
242
|
*ap = 0;
|
222
|
-
odd_cnt++;
|
223
243
|
}
|
data/ext/oj/odd.h
CHANGED
@@ -13,17 +13,18 @@
|
|
13
13
|
typedef VALUE (*AttrGetFunc)(VALUE obj);
|
14
14
|
|
15
15
|
typedef struct _odd {
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
VALUE
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
bool
|
24
|
-
|
25
|
-
|
26
|
-
|
16
|
+
struct _odd *next;
|
17
|
+
const char * classname;
|
18
|
+
size_t clen;
|
19
|
+
VALUE clas; // Ruby class or module
|
20
|
+
VALUE create_obj;
|
21
|
+
ID create_op;
|
22
|
+
int attr_cnt;
|
23
|
+
bool is_module;
|
24
|
+
bool raw;
|
25
|
+
const char * attr_names[MAX_ODD_ARGS]; // NULL terminated attr names
|
26
|
+
ID attrs[MAX_ODD_ARGS]; // 0 terminated attr IDs
|
27
|
+
AttrGetFunc attrFuncs[MAX_ODD_ARGS];
|
27
28
|
} * Odd;
|
28
29
|
|
29
30
|
typedef struct _oddArgs {
|
@@ -37,7 +38,6 @@ extern Odd oj_get_oddc(const char *classname, size_t len);
|
|
37
38
|
extern OddArgs oj_odd_alloc_args(Odd odd);
|
38
39
|
extern void oj_odd_free(OddArgs args);
|
39
40
|
extern int oj_odd_set_arg(OddArgs args, const char *key, size_t klen, VALUE value);
|
40
|
-
extern void
|
41
|
-
oj_reg_odd(VALUE clas, VALUE create_object, VALUE create_method, int mcnt, VALUE *members, bool raw);
|
41
|
+
extern void oj_reg_odd(VALUE clas, VALUE create_object, VALUE create_method, int mcnt, VALUE *members, bool raw);
|
42
42
|
|
43
43
|
#endif /* OJ_ODD_H */
|