oj 3.13.11 → 3.15.0

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.
Files changed (158) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +74 -0
  3. data/README.md +4 -2
  4. data/ext/oj/buf.h +11 -6
  5. data/ext/oj/cache.c +25 -24
  6. data/ext/oj/cache8.c +10 -9
  7. data/ext/oj/circarray.c +8 -6
  8. data/ext/oj/circarray.h +2 -2
  9. data/ext/oj/code.c +17 -24
  10. data/ext/oj/code.h +2 -2
  11. data/ext/oj/compat.c +17 -44
  12. data/ext/oj/custom.c +70 -141
  13. data/ext/oj/debug.c +3 -9
  14. data/ext/oj/dump.c +128 -118
  15. data/ext/oj/dump.h +12 -8
  16. data/ext/oj/dump_compat.c +564 -641
  17. data/ext/oj/dump_leaf.c +17 -63
  18. data/ext/oj/dump_object.c +70 -199
  19. data/ext/oj/dump_strict.c +22 -46
  20. data/ext/oj/encoder.c +1 -1
  21. data/ext/oj/err.c +2 -13
  22. data/ext/oj/err.h +9 -12
  23. data/ext/oj/extconf.rb +14 -5
  24. data/ext/oj/fast.c +75 -103
  25. data/ext/oj/intern.c +52 -50
  26. data/ext/oj/intern.h +4 -8
  27. data/ext/oj/mem.c +318 -0
  28. data/ext/oj/mem.h +53 -0
  29. data/ext/oj/mimic_json.c +75 -47
  30. data/ext/oj/object.c +49 -66
  31. data/ext/oj/odd.c +89 -67
  32. data/ext/oj/odd.h +15 -15
  33. data/ext/oj/oj.c +140 -99
  34. data/ext/oj/oj.h +80 -51
  35. data/ext/oj/parse.c +162 -184
  36. data/ext/oj/parse.h +7 -10
  37. data/ext/oj/parser.c +89 -34
  38. data/ext/oj/parser.h +18 -7
  39. data/ext/oj/rails.c +82 -146
  40. data/ext/oj/rails.h +1 -1
  41. data/ext/oj/reader.c +11 -12
  42. data/ext/oj/reader.h +4 -2
  43. data/ext/oj/resolve.c +3 -4
  44. data/ext/oj/rxclass.c +6 -5
  45. data/ext/oj/rxclass.h +1 -1
  46. data/ext/oj/saj.c +20 -31
  47. data/ext/oj/saj2.c +329 -93
  48. data/ext/oj/saj2.h +23 -0
  49. data/ext/oj/scp.c +3 -14
  50. data/ext/oj/sparse.c +26 -70
  51. data/ext/oj/stream_writer.c +12 -22
  52. data/ext/oj/strict.c +20 -52
  53. data/ext/oj/string_writer.c +21 -21
  54. data/ext/oj/trace.h +31 -4
  55. data/ext/oj/usual.c +105 -150
  56. data/ext/oj/usual.h +68 -0
  57. data/ext/oj/util.h +1 -1
  58. data/ext/oj/val_stack.c +1 -1
  59. data/ext/oj/val_stack.h +8 -7
  60. data/ext/oj/validate.c +21 -26
  61. data/ext/oj/wab.c +31 -68
  62. data/lib/oj/active_support_helper.rb +0 -1
  63. data/lib/oj/bag.rb +7 -1
  64. data/lib/oj/easy_hash.rb +4 -5
  65. data/lib/oj/error.rb +0 -1
  66. data/lib/oj/json.rb +4 -2
  67. data/lib/oj/mimic.rb +4 -2
  68. data/lib/oj/saj.rb +20 -6
  69. data/lib/oj/state.rb +9 -6
  70. data/lib/oj/version.rb +1 -2
  71. data/lib/oj.rb +2 -0
  72. data/pages/Compatibility.md +1 -1
  73. data/pages/InstallOptions.md +20 -0
  74. data/pages/Options.md +10 -0
  75. data/test/_test_active.rb +8 -9
  76. data/test/_test_active_mimic.rb +7 -8
  77. data/test/_test_mimic_rails.rb +17 -20
  78. data/test/activerecord/result_test.rb +5 -6
  79. data/test/{activesupport5 → activesupport7}/abstract_unit.rb +16 -12
  80. data/test/{activesupport5 → activesupport7}/decoding_test.rb +2 -10
  81. data/test/{activesupport5 → activesupport7}/encoding_test.rb +20 -34
  82. data/test/{activesupport5 → activesupport7}/encoding_test_cases.rb +6 -0
  83. data/test/{activesupport5 → activesupport7}/time_zone_test_helpers.rb +8 -0
  84. data/test/files.rb +15 -15
  85. data/test/foo.rb +9 -71
  86. data/test/helper.rb +11 -8
  87. data/test/isolated/shared.rb +3 -2
  88. data/test/json_gem/json_addition_test.rb +2 -2
  89. data/test/json_gem/json_common_interface_test.rb +4 -4
  90. data/test/json_gem/json_encoding_test.rb +0 -0
  91. data/test/json_gem/json_ext_parser_test.rb +1 -0
  92. data/test/json_gem/json_fixtures_test.rb +3 -2
  93. data/test/json_gem/json_generator_test.rb +48 -36
  94. data/test/json_gem/json_generic_object_test.rb +11 -11
  95. data/test/json_gem/json_parser_test.rb +54 -47
  96. data/test/json_gem/json_string_matching_test.rb +9 -9
  97. data/test/json_gem/test_helper.rb +7 -3
  98. data/test/mem.rb +13 -12
  99. data/test/perf.rb +21 -26
  100. data/test/perf_compat.rb +31 -33
  101. data/test/perf_dump.rb +50 -0
  102. data/test/perf_fast.rb +80 -82
  103. data/test/perf_file.rb +27 -29
  104. data/test/perf_object.rb +65 -69
  105. data/test/perf_once.rb +12 -11
  106. data/test/perf_parser.rb +42 -48
  107. data/test/perf_saj.rb +46 -54
  108. data/test/perf_scp.rb +57 -69
  109. data/test/perf_simple.rb +41 -39
  110. data/test/perf_strict.rb +68 -70
  111. data/test/perf_wab.rb +67 -69
  112. data/test/prec.rb +3 -3
  113. data/test/sample/change.rb +0 -1
  114. data/test/sample/dir.rb +0 -1
  115. data/test/sample/doc.rb +0 -1
  116. data/test/sample/file.rb +0 -1
  117. data/test/sample/group.rb +0 -1
  118. data/test/sample/hasprops.rb +0 -1
  119. data/test/sample/layer.rb +0 -1
  120. data/test/sample/rect.rb +0 -1
  121. data/test/sample/shape.rb +0 -1
  122. data/test/sample/text.rb +0 -1
  123. data/test/sample.rb +16 -16
  124. data/test/sample_json.rb +8 -8
  125. data/test/test_compat.rb +76 -42
  126. data/test/test_custom.rb +72 -51
  127. data/test/test_debian.rb +7 -10
  128. data/test/test_fast.rb +86 -90
  129. data/test/test_file.rb +41 -30
  130. data/test/test_gc.rb +16 -5
  131. data/test/test_generate.rb +5 -5
  132. data/test/test_hash.rb +4 -4
  133. data/test/test_integer_range.rb +9 -9
  134. data/test/test_null.rb +20 -20
  135. data/test/test_object.rb +85 -96
  136. data/test/test_parser.rb +6 -22
  137. data/test/test_parser_debug.rb +27 -0
  138. data/test/test_parser_saj.rb +115 -23
  139. data/test/test_parser_usual.rb +6 -6
  140. data/test/test_rails.rb +2 -2
  141. data/test/test_saj.rb +10 -8
  142. data/test/test_scp.rb +37 -39
  143. data/test/test_strict.rb +30 -32
  144. data/test/test_various.rb +147 -99
  145. data/test/test_wab.rb +48 -44
  146. data/test/test_writer.rb +47 -47
  147. data/test/tests.rb +13 -4
  148. data/test/tests_mimic.rb +12 -3
  149. data/test/tests_mimic_addition.rb +12 -3
  150. metadata +33 -144
  151. data/test/activesupport4/decoding_test.rb +0 -108
  152. data/test/activesupport4/encoding_test.rb +0 -531
  153. data/test/activesupport4/test_helper.rb +0 -41
  154. data/test/activesupport5/test_helper.rb +0 -72
  155. data/test/bar.rb +0 -16
  156. data/test/baz.rb +0 -16
  157. data/test/bug.rb +0 -16
  158. data/test/zoo.rb +0 -13
data/ext/oj/object.c CHANGED
@@ -67,9 +67,9 @@ static VALUE str_to_value(ParseInfo pi, const char *str, size_t len, const char
67
67
 
68
68
  // The much faster approach (4x faster)
69
69
  static int parse_num(const char *str, const char *end, int cnt) {
70
- int n = 0;
70
+ int n = 0;
71
71
  char c;
72
- int i;
72
+ int i;
73
73
 
74
74
  for (i = cnt; 0 < i; i--, str++) {
75
75
  c = *str;
@@ -83,9 +83,9 @@ static int parse_num(const char *str, const char *end, int cnt) {
83
83
 
84
84
  VALUE
85
85
  oj_parse_xml_time(const char *str, int len) {
86
- VALUE args[8];
86
+ VALUE args[8];
87
87
  const char *end = str + len;
88
- int n;
88
+ int n;
89
89
 
90
90
  // year
91
91
  if (0 > (n = parse_num(str, end, 4))) {
@@ -269,19 +269,10 @@ static int hat_num(ParseInfo pi, Val parent, Val kval, NumInfo ni) {
269
269
  // match the expected value.
270
270
  parent->val = rb_funcall2(parent->val, oj_utc_id, 0, 0);
271
271
  } else if (ni->has_exp) {
272
- int64_t t = (int64_t)(ni->i + ni->exp);
273
- struct _timeInfo ti;
274
- VALUE args[8];
275
-
276
- sec_as_time(t, &ti);
277
- args[0] = LONG2NUM((long)(ti.year));
278
- args[1] = LONG2NUM(ti.mon);
279
- args[2] = LONG2NUM(ti.day);
280
- args[3] = LONG2NUM(ti.hour);
281
- args[4] = LONG2NUM(ti.min);
282
- args[5] = rb_float_new((double)ti.sec + ((double)nsec + 0.5) / 1000000000.0);
283
- args[6] = LONG2NUM(ni->exp);
284
- 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);
285
276
  } else {
286
277
  parent->val = rb_time_nano_new(ni->i, (long)nsec);
287
278
  }
@@ -317,7 +308,7 @@ static int hat_value(ParseInfo pi, Val parent, const char *key, size_t klen, vol
317
308
  oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "Invalid struct data");
318
309
  return 1;
319
310
  }
320
- e1 = *RARRAY_PTR(value);
311
+ e1 = *RARRAY_CONST_PTR(value);
321
312
  // check for anonymous Struct
322
313
  if (T_ARRAY == rb_type(e1)) {
323
314
  VALUE args[1024];
@@ -331,40 +322,44 @@ static int hat_value(ParseInfo pi, Val parent, const char *key, size_t klen, vol
331
322
  sc = rb_funcall2(rb_cStruct, oj_new_id, cnt, args);
332
323
  } else {
333
324
  // If struct is not defined then we let this fail and raise an exception.
334
- sc = oj_name2struct(pi, *RARRAY_PTR(value), rb_eArgError);
325
+ sc = oj_name2struct(pi, *RARRAY_CONST_PTR(value), rb_eArgError);
335
326
  }
336
- // Create a properly initialized struct instance without calling the initialize method.
337
- parent->val = rb_obj_alloc(sc);
338
- // If the JSON array has more entries than the struct class allows, we record an error.
327
+ if (sc == rb_cRange) {
328
+ parent->val = rb_class_new_instance(len - 1, RARRAY_CONST_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.
339
333
  #ifdef RSTRUCT_LEN
340
334
  #if RSTRUCT_LEN_RETURNS_INTEGER_OBJECT
341
- slen = (int)NUM2LONG(RSTRUCT_LEN(parent->val));
335
+ slen = (int)NUM2LONG(RSTRUCT_LEN(parent->val));
342
336
  #else // RSTRUCT_LEN_RETURNS_INTEGER_OBJECT
343
- slen = (int)RSTRUCT_LEN(parent->val);
337
+ slen = (int)RSTRUCT_LEN(parent->val);
344
338
  #endif // RSTRUCT_LEN_RETURNS_INTEGER_OBJECT
345
339
  #else
346
- slen = FIX2INT(rb_funcall2(parent->val, oj_length_id, 0, 0));
340
+ slen = FIX2INT(rb_funcall2(parent->val, oj_length_id, 0, 0));
347
341
  #endif
348
- // MRI >= 1.9
349
- if (len - 1 > slen) {
350
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "Invalid struct data");
351
- } else {
352
- int i;
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;
353
347
 
354
- for (i = 0; i < len - 1; i++) {
355
- rb_struct_aset(parent->val, INT2FIX(i), RARRAY_PTR(value)[i + 1]);
348
+ for (i = 0; i < len - 1; i++) {
349
+ rb_struct_aset(parent->val, INT2FIX(i), RARRAY_CONST_PTR(value)[i + 1]);
350
+ }
356
351
  }
357
352
  }
358
353
  return 1;
359
354
  } else if (3 <= klen && '#' == key[1]) {
360
- volatile VALUE *a;
355
+ volatile const VALUE *a;
361
356
 
362
357
  if (2 != len) {
363
358
  oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid hash pair");
364
359
  return 1;
365
360
  }
366
361
  parent->val = rb_hash_new();
367
- a = RARRAY_PTR(value);
362
+ a = RARRAY_CONST_PTR(value);
368
363
  rb_hash_aset(parent->val, *a, a[1]);
369
364
 
370
365
  return 1;
@@ -374,11 +369,17 @@ static int hat_value(ParseInfo pi, Val parent, const char *key, size_t klen, vol
374
369
  }
375
370
 
376
371
  void oj_set_obj_ivar(Val parent, Val kval, VALUE value) {
377
- rb_ivar_set(parent->val, oj_attr_intern(kval->key, kval->klen), value);
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
+ }
378
379
  }
379
380
 
380
381
  static void hash_set_cstr(ParseInfo pi, Val kval, const char *str, size_t len, const char *orig) {
381
- const char * key = kval->key;
382
+ const char *key = kval->key;
382
383
  int klen = kval->klen;
383
384
  Val parent = stack_peek(&pi->stack);
384
385
  volatile VALUE rval = Qnil;
@@ -445,13 +446,11 @@ WHICH_TYPE:
445
446
  rb_class2name(rb_obj_class(parent->val)));
446
447
  return;
447
448
  }
448
- if (Yes == pi->options.trace) {
449
- oj_trace_parse_call("set_string", pi, __FILE__, __LINE__, rval);
450
- }
449
+ TRACE_PARSE_CALL(pi->options.trace, "set_string", pi, rval);
451
450
  }
452
451
 
453
452
  static void hash_set_num(ParseInfo pi, Val kval, NumInfo ni) {
454
- const char * key = kval->key;
453
+ const char *key = kval->key;
455
454
  int klen = kval->klen;
456
455
  Val parent = stack_peek(&pi->stack);
457
456
  volatile VALUE rval = Qnil;
@@ -516,9 +515,7 @@ WHICH_TYPE:
516
515
  rb_class2name(rb_obj_class(parent->val)));
517
516
  return;
518
517
  }
519
- if (Yes == pi->options.trace) {
520
- oj_trace_parse_call("add_number", pi, __FILE__, __LINE__, rval);
521
- }
518
+ TRACE_PARSE_CALL(pi->options.trace, "add_number", pi, rval);
522
519
  }
523
520
 
524
521
  static void hash_set_value(ParseInfo pi, Val kval, VALUE value) {
@@ -544,8 +541,8 @@ WHICH_TYPE:
544
541
  }
545
542
  } else {
546
543
  if (3 <= klen && '^' == *key && '#' == key[1] && T_ARRAY == rb_type(value)) {
547
- long len = RARRAY_LEN(value);
548
- volatile VALUE *a = RARRAY_PTR(value);
544
+ long len = RARRAY_LEN(value);
545
+ volatile const VALUE *a = RARRAY_CONST_PTR(value);
549
546
 
550
547
  if (2 != len) {
551
548
  oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid hash pair");
@@ -602,15 +599,11 @@ WHICH_TYPE:
602
599
  rb_class2name(rb_obj_class(parent->val)));
603
600
  return;
604
601
  }
605
- if (Yes == pi->options.trace) {
606
- oj_trace_parse_call("add_value", pi, __FILE__, __LINE__, value);
607
- }
602
+ TRACE_PARSE_CALL(pi->options.trace, "add_value", pi, value);
608
603
  }
609
604
 
610
605
  static VALUE start_hash(ParseInfo pi) {
611
- if (Yes == pi->options.trace) {
612
- oj_trace_parse_in("start_hash", pi, __FILE__, __LINE__);
613
- }
606
+ TRACE_PARSE_IN(pi->options.trace, "start_hash", pi);
614
607
  return Qnil;
615
608
  }
616
609
 
@@ -626,9 +619,7 @@ static void end_hash(ParseInfo pi) {
626
619
  oj_odd_free(oa);
627
620
  parent->odd_args = NULL;
628
621
  }
629
- if (Yes == pi->options.trace) {
630
- oj_trace_parse_hash_end(pi, __FILE__, __LINE__);
631
- }
622
+ TRACE_PARSE_HASH_END(pi->options.trace, pi);
632
623
  }
633
624
 
634
625
  static void array_append_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
@@ -654,32 +645,24 @@ static void array_append_cstr(ParseInfo pi, const char *str, size_t len, const c
654
645
  }
655
646
  rval = str_to_value(pi, str, len, orig);
656
647
  rb_ary_push(stack_peek(&pi->stack)->val, rval);
657
- if (Yes == pi->options.trace) {
658
- oj_trace_parse_call("append_string", pi, __FILE__, __LINE__, rval);
659
- }
648
+ TRACE_PARSE_CALL(pi->options.trace, "append_string", pi, rval);
660
649
  }
661
650
 
662
651
  static void array_append_num(ParseInfo pi, NumInfo ni) {
663
652
  volatile VALUE rval = oj_num_as_value(ni);
664
653
 
665
654
  rb_ary_push(stack_peek(&pi->stack)->val, rval);
666
- if (Yes == pi->options.trace) {
667
- oj_trace_parse_call("append_number", pi, __FILE__, __LINE__, rval);
668
- }
655
+ TRACE_PARSE_CALL(pi->options.trace, "append_number", pi, rval);
669
656
  }
670
657
 
671
658
  static void add_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
672
659
  pi->stack.head->val = str_to_value(pi, str, len, orig);
673
- if (Yes == pi->options.trace) {
674
- oj_trace_parse_call("add_string", pi, __FILE__, __LINE__, pi->stack.head->val);
675
- }
660
+ TRACE_PARSE_CALL(pi->options.trace, "add_string", pi, pi->stack.head->val);
676
661
  }
677
662
 
678
663
  static void add_num(ParseInfo pi, NumInfo ni) {
679
664
  pi->stack.head->val = oj_num_as_value(ni);
680
- if (Yes == pi->options.trace) {
681
- oj_trace_parse_call("add_num", pi, __FILE__, __LINE__, pi->stack.head->val);
682
- }
665
+ TRACE_PARSE_CALL(pi->options.trace, "add_num", pi, pi->stack.head->val);
683
666
  }
684
667
 
685
668
  void oj_set_object_callbacks(ParseInfo pi) {
data/ext/oj/odd.c CHANGED
@@ -5,28 +5,29 @@
5
5
 
6
6
  #include <string.h>
7
7
 
8
- static struct _odd _odds[4]; // bump up if new initial Odd classes are added
9
- static struct _odd *odds = _odds;
10
- static long odd_cnt = 0;
11
- static ID sec_id;
12
- static ID sec_fraction_id;
13
- static ID to_f_id;
14
- static ID numerator_id;
15
- static ID denominator_id;
16
- static ID rational_id;
17
- static VALUE rational_class;
8
+ #include "mem.h"
9
+
10
+ static Odd odds = NULL;
11
+ static ID sec_id;
12
+ static ID sec_fraction_id;
13
+ static ID to_f_id;
14
+ static ID numerator_id;
15
+ static ID denominator_id;
16
+ static ID rational_id;
18
17
 
19
18
  static void set_class(Odd odd, const char *classname) {
20
19
  const char **np;
21
- ID * idp;
20
+ ID *idp;
22
21
 
23
- odd->classname = classname;
24
- odd->clen = strlen(classname);
25
- odd->clas = rb_const_get(rb_cObject, rb_intern(classname));
22
+ odd->classname = classname;
23
+ odd->clen = strlen(classname);
24
+ odd->clas = rb_const_get(rb_cObject, rb_intern(classname));
25
+ rb_gc_register_mark_object(odd->clas);
26
26
  odd->create_obj = odd->clas;
27
- odd->create_op = rb_intern("new");
28
- odd->is_module = (T_MODULE == rb_type(odd->clas));
29
- odd->raw = 0;
27
+ rb_gc_register_mark_object(odd->create_obj);
28
+ odd->create_op = rb_intern("new");
29
+ odd->is_module = (T_MODULE == rb_type(odd->clas));
30
+ odd->raw = 0;
30
31
  for (np = odd->attr_names, idp = odd->attrs; 0 != *np; np++, idp++) {
31
32
  *idp = rb_intern(*np);
32
33
  }
@@ -37,15 +38,48 @@ static VALUE get_datetime_secs(VALUE obj) {
37
38
  volatile VALUE rsecs = rb_funcall(obj, sec_id, 0);
38
39
  volatile VALUE rfrac = rb_funcall(obj, sec_fraction_id, 0);
39
40
  long sec = NUM2LONG(rsecs);
40
- long long num = rb_num2ll(rb_funcall(rfrac, numerator_id, 0));
41
- long long den = rb_num2ll(rb_funcall(rfrac, denominator_id, 0));
41
+ long long num = NUM2LL(rb_funcall(rfrac, numerator_id, 0));
42
+ long long den = NUM2LL(rb_funcall(rfrac, denominator_id, 0));
42
43
 
43
44
  num += sec * den;
44
45
 
45
46
  return rb_funcall(rb_cObject, rational_id, 2, rb_ll2inum(num), rb_ll2inum(den));
46
47
  }
47
48
 
48
- void oj_odd_init() {
49
+ static void print_odd(Odd odd) {
50
+ const char **np;
51
+ int i;
52
+
53
+ printf(" %s {\n", odd->classname);
54
+ printf(" attr_cnt: %d %p\n", odd->attr_cnt, (void *)odd->attr_names);
55
+ printf(" attr_names: %p\n", (void *)*odd->attr_names);
56
+ printf(" attr_names: %c\n", **odd->attr_names);
57
+ for (i = odd->attr_cnt, np = odd->attr_names; 0 < i; i--, np++) {
58
+ printf(" %d %s\n", i, *np);
59
+ }
60
+ printf(" }\n");
61
+ }
62
+
63
+ void print_all_odds(const char *label) {
64
+ Odd odd;
65
+ printf("@ %s {\n", label);
66
+ for (odd = odds; NULL != odd; odd = odd->next) {
67
+ print_odd(odd);
68
+ }
69
+ printf("}\n");
70
+ }
71
+
72
+ static Odd odd_create(void) {
73
+ Odd odd = OJ_R_ALLOC(struct _odd);
74
+
75
+ memset(odd, 0, sizeof(struct _odd));
76
+ odd->next = odds;
77
+ odds = odd;
78
+
79
+ return odd;
80
+ }
81
+
82
+ void oj_odd_init(void) {
49
83
  Odd odd;
50
84
  const char **np;
51
85
 
@@ -55,11 +89,9 @@ void oj_odd_init() {
55
89
  numerator_id = rb_intern("numerator");
56
90
  denominator_id = rb_intern("denominator");
57
91
  rational_id = rb_intern("Rational");
58
- rational_class = rb_const_get(rb_cObject, rational_id);
59
92
 
60
- memset(_odds, 0, sizeof(_odds));
61
- odd = odds;
62
93
  // Rational
94
+ odd = odd_create();
63
95
  np = odd->attr_names;
64
96
  *np++ = "numerator";
65
97
  *np++ = "denominator";
@@ -68,8 +100,9 @@ void oj_odd_init() {
68
100
  odd->create_obj = rb_cObject;
69
101
  odd->create_op = rational_id;
70
102
  odd->attr_cnt = 2;
103
+
71
104
  // Date
72
- odd++;
105
+ odd = odd_create();
73
106
  np = odd->attr_names;
74
107
  *np++ = "year";
75
108
  *np++ = "month";
@@ -78,8 +111,9 @@ void oj_odd_init() {
78
111
  *np++ = 0;
79
112
  set_class(odd, "Date");
80
113
  odd->attr_cnt = 4;
114
+
81
115
  // DateTime
82
- odd++;
116
+ odd = odd_create();
83
117
  np = odd->attr_names;
84
118
  *np++ = "year";
85
119
  *np++ = "month";
@@ -93,8 +127,9 @@ void oj_odd_init() {
93
127
  set_class(odd, "DateTime");
94
128
  odd->attr_cnt = 8;
95
129
  odd->attrFuncs[5] = get_datetime_secs;
130
+
96
131
  // Range
97
- odd++;
132
+ odd = odd_create();
98
133
  np = odd->attr_names;
99
134
  *np++ = "begin";
100
135
  *np++ = "end";
@@ -102,15 +137,13 @@ void oj_odd_init() {
102
137
  *np++ = 0;
103
138
  set_class(odd, "Range");
104
139
  odd->attr_cnt = 3;
105
-
106
- odd_cnt = odd - odds + 1;
107
140
  }
108
141
 
109
142
  Odd oj_get_odd(VALUE clas) {
110
143
  Odd odd;
111
144
  const char *classname = NULL;
112
145
 
113
- for (odd = odds + odd_cnt - 1; odds <= odd; odd--) {
146
+ for (odd = odds; NULL != odd; odd = odd->next) {
114
147
  if (clas == odd->clas) {
115
148
  return odd;
116
149
  }
@@ -129,21 +162,20 @@ Odd oj_get_odd(VALUE clas) {
129
162
  Odd oj_get_oddc(const char *classname, size_t len) {
130
163
  Odd odd;
131
164
 
132
- for (odd = odds + odd_cnt - 1; odds <= odd; odd--) {
165
+ for (odd = odds; NULL != odd; odd = odd->next) {
133
166
  if (len == odd->clen && 0 == strncmp(classname, odd->classname, len)) {
134
167
  return odd;
135
168
  }
136
- if (odd->is_module && 0 == strncmp(odd->classname, classname, odd->clen) &&
137
- ':' == classname[odd->clen]) {
169
+ if (odd->is_module && 0 == strncmp(odd->classname, classname, odd->clen) && ':' == classname[odd->clen]) {
138
170
  return odd;
139
171
  }
140
172
  }
141
- return 0;
173
+ return NULL;
142
174
  }
143
175
 
144
176
  OddArgs oj_odd_alloc_args(Odd odd) {
145
- OddArgs oa = ALLOC_N(struct _oddArgs, 1);
146
- VALUE * a;
177
+ OddArgs oa = OJ_R_ALLOC_N(struct _oddArgs, 1);
178
+ VALUE *a;
147
179
  int i;
148
180
 
149
181
  oa->odd = odd;
@@ -154,16 +186,15 @@ OddArgs oj_odd_alloc_args(Odd odd) {
154
186
  }
155
187
 
156
188
  void oj_odd_free(OddArgs args) {
157
- xfree(args);
189
+ OJ_R_FREE(args);
158
190
  }
159
191
 
160
192
  int oj_odd_set_arg(OddArgs args, const char *key, size_t klen, VALUE value) {
161
193
  const char **np;
162
- VALUE * vp;
194
+ VALUE *vp;
163
195
  int i;
164
196
 
165
- for (i = args->odd->attr_cnt, np = args->odd->attr_names, vp = args->args; 0 < i;
166
- i--, np++, vp++) {
197
+ for (i = args->odd->attr_cnt, np = args->odd->attr_names, vp = args->args; 0 < i; i--, np++, vp++) {
167
198
  if (0 == strncmp(key, *np, klen) && '\0' == *((*np) + klen)) {
168
199
  *vp = value;
169
200
  return 0;
@@ -172,52 +203,43 @@ int oj_odd_set_arg(OddArgs args, const char *key, size_t klen, VALUE value) {
172
203
  return -1;
173
204
  }
174
205
 
175
- void oj_reg_odd(VALUE clas,
176
- VALUE create_object,
177
- VALUE create_method,
178
- int mcnt,
179
- VALUE *members,
180
- bool raw) {
206
+ void oj_reg_odd(VALUE clas, VALUE create_object, VALUE create_method, int mcnt, VALUE *members, bool raw) {
181
207
  Odd odd;
182
208
  const char **np;
183
- ID * ap;
209
+ ID *ap;
184
210
  AttrGetFunc *fp;
185
211
 
186
- if (_odds == odds) {
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;
212
+ odd = odd_create();
194
213
  odd->clas = clas;
195
- if (NULL == (odd->classname = strdup(rb_class2name(clas)))) {
196
- rb_raise(rb_eNoMemError, "for attribute name.");
214
+ rb_gc_register_mark_object(odd->clas);
215
+ if (NULL == (odd->classname = OJ_STRDUP(rb_class2name(clas)))) {
216
+ rb_raise(rb_eNoMemError, "for class name.");
197
217
  }
198
218
  odd->clen = strlen(odd->classname);
199
219
  odd->create_obj = create_object;
200
- odd->create_op = SYM2ID(create_method);
201
- odd->attr_cnt = mcnt;
202
- odd->is_module = (T_MODULE == rb_type(clas));
203
- odd->raw = raw;
204
- for (ap = odd->attrs, np = odd->attr_names, fp = odd->attrFuncs; 0 < mcnt;
205
- mcnt--, ap++, np++, members++, fp++) {
220
+ rb_gc_register_mark_object(odd->create_obj);
221
+ odd->create_op = SYM2ID(create_method);
222
+ odd->attr_cnt = mcnt;
223
+ odd->is_module = (T_MODULE == rb_type(clas));
224
+ odd->raw = raw;
225
+ for (ap = odd->attrs, np = odd->attr_names, fp = odd->attrFuncs; 0 < mcnt; mcnt--, ap++, np++, members++, fp++) {
206
226
  *fp = 0;
207
227
  switch (rb_type(*members)) {
208
228
  case T_STRING:
209
- if (NULL == (*np = strdup(RSTRING_PTR(*members)))) {
229
+ if (NULL == (*np = OJ_STRDUP(RSTRING_PTR(*members)))) {
210
230
  rb_raise(rb_eNoMemError, "for attribute name.");
211
231
  }
212
232
  break;
213
- case T_SYMBOL: *np = rb_id2name(SYM2ID(*members)); break;
214
- default:
215
- rb_raise(rb_eArgError, "registered member identifiers must be Strings or Symbols.");
233
+ case T_SYMBOL:
234
+ // The symbol can move and invalidate the name so make a copy.
235
+ if (NULL == (*np = OJ_STRDUP(rb_id2name(SYM2ID(*members))))) {
236
+ rb_raise(rb_eNoMemError, "for attribute name.");
237
+ }
216
238
  break;
239
+ default: rb_raise(rb_eArgError, "registered member identifiers must be Strings or Symbols."); break;
217
240
  }
218
241
  *ap = rb_intern(*np);
219
242
  }
220
243
  *np = 0;
221
244
  *ap = 0;
222
- odd_cnt++;
223
245
  }
data/ext/oj/odd.h CHANGED
@@ -13,23 +13,24 @@
13
13
  typedef VALUE (*AttrGetFunc)(VALUE obj);
14
14
 
15
15
  typedef struct _odd {
16
- const char *classname;
17
- size_t clen;
18
- VALUE clas; // Ruby class or module
19
- VALUE create_obj;
20
- ID create_op;
21
- int attr_cnt;
22
- bool is_module;
23
- bool raw;
24
- const char *attr_names[MAX_ODD_ARGS]; // NULL terminated attr names
25
- ID attrs[MAX_ODD_ARGS]; // 0 terminated attr IDs
26
- AttrGetFunc attrFuncs[MAX_ODD_ARGS];
27
- } * Odd;
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];
28
+ } *Odd;
28
29
 
29
30
  typedef struct _oddArgs {
30
31
  Odd odd;
31
32
  VALUE args[MAX_ODD_ARGS];
32
- } * OddArgs;
33
+ } *OddArgs;
33
34
 
34
35
  extern void oj_odd_init(void);
35
36
  extern Odd oj_get_odd(VALUE clas);
@@ -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 */