oj 3.13.11 → 3.15.0

Sign up to get free protection for your applications and to get access to all the features.
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 */