oj 3.17.7 → 3.17.8

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.
data/ext/oj/dump.c CHANGED
@@ -587,6 +587,9 @@ long oj_check_circular(VALUE obj, Out out) {
587
587
  slot_t *slot;
588
588
 
589
589
  if (Yes == out->opts->circular) {
590
+ if (NULL == out->circ_cache) {
591
+ oj_cache8_new(&out->circ_cache);
592
+ }
590
593
  if (0 == (id = oj_cache8_get(out->circ_cache, obj, &slot))) {
591
594
  out->circ_cnt++;
592
595
  id = out->circ_cnt;
@@ -831,28 +834,61 @@ void oj_dump_obj_to_json_using_params(VALUE obj, Options copts, Out out, int arg
831
834
  *out->cur = '\0';
832
835
  if (Yes == copts->circular) {
833
836
  oj_cache8_delete(out->circ_cache);
837
+ out->circ_cache = NULL;
834
838
  }
835
839
  }
836
840
 
837
- void oj_write_obj_to_file(VALUE obj, const char *path, Options copts) {
838
- struct _out out;
839
- size_t size;
840
- FILE *f;
841
- int ok;
841
+ struct dump_str_arg {
842
+ VALUE obj;
843
+ Options copts;
844
+ Out out;
845
+ int argc;
846
+ VALUE *argv;
847
+ };
842
848
 
843
- oj_out_init(&out);
849
+ static VALUE dump_str_body(VALUE a) {
850
+ struct dump_str_arg *arg = (struct dump_str_arg *)a;
844
851
 
845
- out.omit_nil = copts->dump_opts.omit_nil;
846
- oj_dump_obj_to_json(obj, copts, &out);
847
- size = out.cur - out.buf;
848
- if (0 == (f = fopen(path, "w"))) {
849
- oj_out_free(&out);
850
- rb_raise(rb_eIOError, "%s", strerror(errno));
852
+ oj_dump_obj_to_json_using_params(arg->obj, arg->copts, arg->out, arg->argc, arg->argv);
853
+ if (0 == arg->out->buf) {
854
+ rb_raise(rb_eNoMemError, "Not enough memory.");
851
855
  }
852
- ok = (size == fwrite(out.buf, 1, size, f));
856
+ return rb_utf8_str_new_cstr(arg->out->buf);
857
+ }
858
+
859
+ static VALUE out_free_ensure(VALUE out) {
860
+ oj_out_free((Out)out);
861
+
862
+ return Qnil;
863
+ }
853
864
 
854
- oj_out_free(&out);
865
+ VALUE oj_dump_obj_to_str(VALUE obj, Options copts, Out out, int argc, VALUE *argv) {
866
+ struct dump_str_arg arg = {obj, copts, out, argc, argv};
855
867
 
868
+ return rb_ensure(dump_str_body, (VALUE)&arg, out_free_ensure, (VALUE)out);
869
+ }
870
+
871
+ struct write_arg {
872
+ VALUE obj;
873
+ VALUE stream;
874
+ const char *path;
875
+ Options copts;
876
+ Out out;
877
+ };
878
+
879
+ static VALUE write_file_body(VALUE a) {
880
+ struct write_arg *arg = (struct write_arg *)a;
881
+ Out out = arg->out;
882
+ size_t size;
883
+ FILE *f;
884
+ int ok;
885
+
886
+ oj_dump_obj_to_json(arg->obj, arg->copts, out);
887
+ size = out->cur - out->buf;
888
+ if (0 == (f = fopen(arg->path, "w"))) {
889
+ rb_raise(rb_eIOError, "%s", strerror(errno));
890
+ }
891
+ ok = (size == fwrite(out->buf, 1, size, f));
856
892
  if (!ok) {
857
893
  int err = ferror(f);
858
894
  fclose(f);
@@ -860,6 +896,18 @@ void oj_write_obj_to_file(VALUE obj, const char *path, Options copts) {
860
896
  rb_raise(rb_eIOError, "Write failed. [%d:%s]", err, strerror(err));
861
897
  }
862
898
  fclose(f);
899
+
900
+ return Qnil;
901
+ }
902
+
903
+ void oj_write_obj_to_file(VALUE obj, const char *path, Options copts) {
904
+ struct _out out;
905
+ struct write_arg arg = {obj, Qnil, path, copts, &out};
906
+
907
+ oj_out_init(&out);
908
+
909
+ out.omit_nil = copts->dump_opts.omit_nil;
910
+ rb_ensure(write_file_body, (VALUE)&arg, out_free_ensure, (VALUE)&out);
863
911
  }
864
912
 
865
913
  #if !IS_WINDOWS
@@ -879,22 +927,21 @@ static void write_ready(int fd) {
879
927
  }
880
928
  #endif
881
929
 
882
- void oj_write_obj_to_stream(VALUE obj, VALUE stream, Options copts) {
883
- struct _out out;
884
- ssize_t size;
885
- VALUE clas = rb_obj_class(stream);
930
+ static VALUE write_stream_body(VALUE a) {
931
+ struct write_arg *arg = (struct write_arg *)a;
932
+ Out out = arg->out;
933
+ VALUE stream = arg->stream;
934
+ ssize_t size;
935
+ VALUE clas = rb_obj_class(stream);
886
936
  #if !IS_WINDOWS
887
937
  int fd;
888
938
  VALUE s;
889
939
  #endif
890
940
 
891
- oj_out_init(&out);
892
-
893
- out.omit_nil = copts->dump_opts.omit_nil;
894
- oj_dump_obj_to_json(obj, copts, &out);
895
- size = out.cur - out.buf;
941
+ oj_dump_obj_to_json(arg->obj, arg->copts, out);
942
+ size = out->cur - out->buf;
896
943
  if (oj_stringio_class == clas) {
897
- rb_funcall(stream, oj_write_id, 1, rb_str_new(out.buf, size));
944
+ rb_funcall(stream, oj_write_id, 1, rb_str_new(out->buf, size));
898
945
  #if !IS_WINDOWS
899
946
  } else if (rb_respond_to(stream, oj_fileno_id) && Qnil != (s = rb_funcall(stream, oj_fileno_id, 0)) &&
900
947
  0 != (fd = FIX2INT(s))) {
@@ -902,7 +949,7 @@ void oj_write_obj_to_stream(VALUE obj, VALUE stream, Options copts) {
902
949
  ssize_t total = 0;
903
950
 
904
951
  while (true) {
905
- if (0 > (cnt = write(fd, out.buf + total, size - total))) {
952
+ if (0 > (cnt = write(fd, out->buf + total, size - total))) {
906
953
  if (EAGAIN != errno) {
907
954
  rb_raise(rb_eIOError, "write failed. %d %s.", errno, strerror(errno));
908
955
  break;
@@ -917,22 +964,32 @@ void oj_write_obj_to_stream(VALUE obj, VALUE stream, Options copts) {
917
964
  }
918
965
  #endif
919
966
  } else if (rb_respond_to(stream, oj_write_id)) {
920
- rb_funcall(stream, oj_write_id, 1, rb_str_new(out.buf, size));
967
+ rb_funcall(stream, oj_write_id, 1, rb_str_new(out->buf, size));
921
968
  } else {
922
- oj_out_free(&out);
923
969
  rb_raise(rb_eArgError, "to_stream() expected an IO Object.");
924
970
  }
925
- oj_out_free(&out);
971
+ return Qnil;
972
+ }
973
+
974
+ void oj_write_obj_to_stream(VALUE obj, VALUE stream, Options copts) {
975
+ struct _out out;
976
+ struct write_arg arg = {obj, stream, NULL, copts, &out};
977
+
978
+ oj_out_init(&out);
979
+
980
+ out.omit_nil = copts->dump_opts.omit_nil;
981
+ rb_ensure(write_stream_body, (VALUE)&arg, out_free_ensure, (VALUE)&out);
926
982
  }
927
983
 
928
984
  void oj_dump_str(VALUE obj, int depth, Out out, bool as_ok) {
929
985
  int idx = RB_ENCODING_GET(obj);
930
986
 
931
- if (oj_utf8_encoding_index != idx) {
987
+ if (oj_utf8_encoding_index != idx && !rb_enc_str_asciionly_p(obj)) {
932
988
  rb_encoding *enc = rb_enc_from_index(idx);
933
989
  obj = rb_str_conv_enc(obj, enc, oj_utf8_encoding);
934
990
  }
935
991
  oj_dump_cstr(RSTRING_PTR(obj), RSTRING_LEN(obj), 0, 0, out);
992
+ RB_GC_GUARD(obj);
936
993
  }
937
994
 
938
995
  void oj_dump_sym(VALUE obj, int depth, Out out, bool as_ok) {
@@ -968,6 +1025,7 @@ void oj_dump_raw_json(VALUE obj, int depth, Out out) {
968
1025
  if (0 < len) {
969
1026
  len--;
970
1027
  }
1028
+ assure_size(out, len + 10);
971
1029
  oj_dump_raw(sw->out.buf, len, out);
972
1030
  } else {
973
1031
  volatile VALUE jv;
@@ -975,6 +1033,7 @@ void oj_dump_raw_json(VALUE obj, int depth, Out out) {
975
1033
  TRACE(out->opts->trace, "raw_json", obj, depth + 1, TraceRubyIn);
976
1034
  jv = rb_funcall(obj, oj_raw_json_id, 2, RB_INT2NUM(depth), RB_INT2NUM(out->indent));
977
1035
  TRACE(out->opts->trace, "raw_json", obj, depth + 1, TraceRubyOut);
1036
+ StringValue(jv);
978
1037
  oj_dump_raw(RSTRING_PTR(jv), (size_t)RSTRING_LEN(jv), out);
979
1038
  }
980
1039
  }
@@ -1461,12 +1520,17 @@ void oj_out_init(Out out) {
1461
1520
  out->end = out->buf + sizeof(out->stack_buffer) - BUFFER_EXTRA;
1462
1521
  out->allocated = false;
1463
1522
  out->key_filter_off = false;
1523
+ out->circ_cache = NULL;
1464
1524
  }
1465
1525
 
1466
1526
  void oj_out_free(Out out) {
1467
1527
  if (out->allocated) {
1468
1528
  OJ_R_FREE(out->buf); // TBD
1469
1529
  }
1530
+ if (NULL != out->circ_cache) {
1531
+ oj_cache8_delete(out->circ_cache);
1532
+ out->circ_cache = NULL;
1533
+ }
1470
1534
  }
1471
1535
 
1472
1536
  void oj_grow_out(Out out, size_t len) {
data/ext/oj/dump_compat.c CHANGED
@@ -321,7 +321,7 @@ static void exception_alt(VALUE obj, int depth, Out out) {
321
321
  if (0 < out->opts->dump_opts.after_size) {
322
322
  APPEND_CHARS(out->cur, out->opts->dump_opts.after_sep, out->opts->dump_opts.after_size);
323
323
  }
324
- oj_dump_str(rb_funcall(obj, message_id, 0), 0, out, false);
324
+ oj_dump_compat_val(rb_funcall(obj, message_id, 0), depth + 1, out, true);
325
325
  assure_size(out, size + sep_len + 6);
326
326
  *out->cur++ = ',';
327
327
  fill_indent(out, d3);
@@ -470,9 +470,6 @@ oj_add_to_json(int argc, VALUE *argv, VALUE self) {
470
470
 
471
471
  if (0 == argc) {
472
472
  for (a = oj_compat_codes; NULL != a->name; a++) {
473
- if (Qnil == a->clas || Qundef == a->clas) {
474
- a->clas = rb_const_get_at(rb_cObject, rb_intern(a->name));
475
- }
476
473
  a->active = true;
477
474
  }
478
475
  use_struct_alt = true;
@@ -503,10 +500,7 @@ oj_add_to_json(int argc, VALUE *argv, VALUE self) {
503
500
  continue;
504
501
  }
505
502
  for (a = oj_compat_codes; NULL != a->name; a++) {
506
- if (Qnil == a->clas || Qundef == a->clas) {
507
- a->clas = rb_const_get_at(rb_cObject, rb_intern(a->name));
508
- }
509
- if (*argv == a->clas) {
503
+ if (*argv == oj_code_class(a)) {
510
504
  a->active = true;
511
505
  break;
512
506
  }
@@ -563,12 +557,15 @@ static void dump_float(VALUE obj, int depth, Out out, bool as_ok) {
563
557
  size_t cnt = 0;
564
558
 
565
559
  if (0.0 == d) {
566
- b = buf;
560
+ b = buf;
561
+ if (signbit(d)) {
562
+ *b++ = '-';
563
+ }
567
564
  *b++ = '0';
568
565
  *b++ = '.';
569
566
  *b++ = '0';
570
- *b++ = '\0';
571
- cnt = 3;
567
+ *b = '\0';
568
+ cnt = b - buf;
572
569
  } else if (OJ_INFINITY == d) {
573
570
  if (WordNan == out->opts->dump_opts.nan_dump) {
574
571
  strcpy(buf, "Infinity");
data/ext/oj/dump_object.c CHANGED
@@ -143,6 +143,7 @@ static void dump_array_class(VALUE a, VALUE clas, int depth, Out out) {
143
143
  cnt--;
144
144
  for (i = 0; i <= cnt; i++) {
145
145
  if (out->opts->dump_opts.use) {
146
+ assure_size(out, size);
146
147
  if (0 < out->opts->dump_opts.array_size) {
147
148
  APPEND_CHARS(out->cur, out->opts->dump_opts.array_nl, out->opts->dump_opts.array_size);
148
149
  }
@@ -160,7 +161,7 @@ static void dump_array_class(VALUE a, VALUE clas, int depth, Out out) {
160
161
  *out->cur++ = ',';
161
162
  }
162
163
  }
163
- size = depth * out->indent + 1;
164
+ size = indent_len(out, depth, out->opts->dump_opts.array_size) + 1;
164
165
  assure_size(out, size);
165
166
  if (out->opts->dump_opts.use) {
166
167
  // printf("*** d2: %u indent: %u '%s'\n", d2, out->opts->dump_opts->indent_size,
@@ -350,7 +351,7 @@ static int dump_attr_cb(ID key, VALUE value, VALUE ov) {
350
351
  } else if (Yes == out->opts->ignore_under && '@' == *attr && '_' == attr[1]) {
351
352
  return ST_CONTINUE;
352
353
  }
353
- if (0 == strcmp("bt", attr) || 0 == strcmp("mesg", attr)) {
354
+ if ('@' != *attr && (0 == strcmp("bt", attr) || 0 == strcmp("mesg", attr) || 0 == strcmp("bt_locations", attr))) {
354
355
  return ST_CONTINUE;
355
356
  }
356
357
  assure_size(out, size);
@@ -611,6 +612,10 @@ static void dump_struct(VALUE obj, int depth, Out out, bool as_ok) {
611
612
  APPEND_CHARS(out->cur, name, len);
612
613
  *out->cur++ = '"';
613
614
  }
615
+ if (2 == cnt && rb_obj_is_kind_of(obj, rb_cRange)) {
616
+ assure_size(out, 8);
617
+ APPEND_CHARS(out->cur, ",\"excl\"", 7);
618
+ }
614
619
  *out->cur++ = ']';
615
620
  } else {
616
621
  fill_indent(out, d3);
@@ -644,6 +649,17 @@ static void dump_struct(VALUE obj, int depth, Out out, bool as_ok) {
644
649
  oj_dump_obj_val(v, d3, out);
645
650
  *out->cur++ = ',';
646
651
  }
652
+ if (2 == cnt && rb_obj_is_kind_of(obj, rb_cRange)) {
653
+ VALUE beg;
654
+ VALUE end;
655
+ int excl;
656
+
657
+ rb_range_values(obj, &beg, &end, &excl);
658
+ assure_size(out, size);
659
+ fill_indent(out, d3);
660
+ oj_dump_obj_val(excl ? Qtrue : Qfalse, d3, out);
661
+ *out->cur++ = ',';
662
+ }
647
663
  }
648
664
  #else
649
665
  {
data/ext/oj/dump_strict.c CHANGED
@@ -135,6 +135,7 @@ static void dump_array(VALUE a, int depth, Out out, bool as_ok) {
135
135
  cnt--;
136
136
  for (i = 0; i <= cnt; i++) {
137
137
  if (out->opts->dump_opts.use) {
138
+ assure_size(out, size);
138
139
  if (0 < out->opts->dump_opts.array_size) {
139
140
  APPEND_CHARS(out->cur, out->opts->dump_opts.array_nl, out->opts->dump_opts.array_size);
140
141
  }
@@ -156,7 +157,7 @@ static void dump_array(VALUE a, int depth, Out out, bool as_ok) {
156
157
  *out->cur++ = ',';
157
158
  }
158
159
  }
159
- size = depth * out->indent + 1;
160
+ size = indent_len(out, depth, out->opts->dump_opts.array_size) + 1;
160
161
  assure_size(out, size);
161
162
  if (out->opts->dump_opts.use) {
162
163
  // printf("*** d2: %u indent: %u '%s'\n", d2, out->opts->dump_opts->indent_size,
data/ext/oj/extconf.rb CHANGED
@@ -33,7 +33,6 @@ have_func('getrlimit', 'sys/resource.h')
33
33
  have_func('rb_enc_interned_str')
34
34
  have_func('rb_hash_new_capa', 'ruby.h')
35
35
  have_func('rb_ext_ractor_safe', 'ruby.h')
36
- have_func('rb_hash_start', 'ruby.h')
37
36
 
38
37
  dflags['OJ_DEBUG'] = true unless ENV['OJ_DEBUG'].nil?
39
38
 
data/ext/oj/fast.c CHANGED
@@ -838,8 +838,10 @@ static VALUE parse_json(VALUE clas, char *json, bool given) {
838
838
  // The doc is detached from its wrapper so the GC will not free it.
839
839
  // doc_free() releases both the doc and its json buffer (doc->json), so
840
840
  // the caller must not free json separately.
841
- DATA_PTR(doc->self) = NULL;
842
- doc_free(pi.doc);
841
+ if (NULL != DATA_PTR(self)) {
842
+ DATA_PTR(self) = NULL;
843
+ doc_free(doc);
844
+ }
843
845
  } else {
844
846
  result = doc->self;
845
847
  }
@@ -1034,8 +1036,8 @@ static int move_step(Doc doc, const char *path, int loc) {
1034
1036
  doc->where--;
1035
1037
  loc = move_step(doc, path, loc + 1);
1036
1038
  if (0 != loc) {
1037
- *doc->where = init;
1038
1039
  doc->where++;
1040
+ *doc->where = init;
1039
1041
  }
1040
1042
  } else if (COL_VAL == leaf->value_type && 0 != leaf->elements) {
1041
1043
  Leaf first = leaf->elements->next;
@@ -1179,19 +1181,24 @@ static VALUE doc_open_file(VALUE clas, VALUE filename) {
1179
1181
  volatile VALUE obj;
1180
1182
  int given = rb_block_given_p();
1181
1183
 
1182
- path = StringValuePtr(filename);
1184
+ path = StringValueCStr(filename);
1183
1185
  // Open in binary mode. On Windows a text mode read translates CRLF into LF
1184
1186
  // so fewer bytes are read than the file size reported by ftell().
1185
1187
  if (0 == (f = fopen(path, "rb"))) {
1186
1188
  rb_raise(rb_eIOError, "%s", strerror(errno));
1187
1189
  }
1188
1190
  fseek(f, 0, SEEK_END);
1189
- len = ftell(f);
1191
+ len = ftell(f);
1192
+ if ((size_t)-1 == len) {
1193
+ fclose(f);
1194
+ rb_raise(rb_const_get_at(Oj, rb_intern("LoadError")), "Failed to get the size of %s.", path);
1195
+ }
1190
1196
  json = OJ_R_ALLOC_N(char, len + 1);
1191
1197
 
1192
1198
  fseek(f, 0, SEEK_SET);
1193
1199
  if (len != fread(json, 1, len, f)) {
1194
1200
  fclose(f);
1201
+ OJ_R_FREE(json);
1195
1202
  rb_raise(rb_const_get_at(Oj, rb_intern("LoadError")),
1196
1203
  "Failed to read %lu bytes from %s.",
1197
1204
  (unsigned long)len,
@@ -1344,7 +1351,7 @@ static VALUE doc_home(VALUE self) {
1344
1351
  * Oj::Doc.open('[1,2]') { |doc| doc.type('/1') } #=> Fixnum
1345
1352
  */
1346
1353
  static VALUE doc_type(int argc, VALUE *argv, VALUE self) {
1347
- Doc doc = self_doc(self);
1354
+ Doc doc;
1348
1355
  Leaf leaf;
1349
1356
  const char *path = 0;
1350
1357
  VALUE type = Qnil;
@@ -1352,6 +1359,7 @@ static VALUE doc_type(int argc, VALUE *argv, VALUE self) {
1352
1359
  if (1 <= argc) {
1353
1360
  path = StringValuePtr(*argv);
1354
1361
  }
1362
+ doc = self_doc(self);
1355
1363
  if (0 != (leaf = get_doc_leaf(doc, path))) {
1356
1364
  switch (leaf->rtype) {
1357
1365
  case T_NIL: type = rb_cNilClass; break;
@@ -1387,13 +1395,13 @@ static VALUE doc_fetch(int argc, VALUE *argv, VALUE self) {
1387
1395
  volatile VALUE val = Qnil;
1388
1396
  const char *path = 0;
1389
1397
 
1390
- doc = self_doc(self);
1391
1398
  if (1 <= argc) {
1392
1399
  path = StringValuePtr(*argv);
1393
1400
  if (2 == argc) {
1394
1401
  val = argv[1];
1395
1402
  }
1396
1403
  }
1404
+ doc = self_doc(self);
1397
1405
  if (0 != (leaf = get_doc_leaf(doc, path))) {
1398
1406
  val = leaf_value(doc, leaf);
1399
1407
  }
@@ -1409,11 +1417,11 @@ static VALUE doc_fetch(int argc, VALUE *argv, VALUE self) {
1409
1417
  * Oj::Doc.open('[1,2]') { |doc| doc.exists?('/3') } #=> false
1410
1418
  */
1411
1419
  static VALUE doc_exists(VALUE self, VALUE str) {
1412
- Doc doc;
1413
- Leaf leaf;
1420
+ const char *path = StringValuePtr(str);
1421
+ Doc doc = self_doc(self);
1422
+ Leaf leaf;
1414
1423
 
1415
- doc = self_doc(self);
1416
- if (0 != (leaf = get_doc_leaf(doc, StringValuePtr(str)))) {
1424
+ if (0 != (leaf = get_doc_leaf(doc, path))) {
1417
1425
  if (NULL != leaf) {
1418
1426
  return Qtrue;
1419
1427
  }
@@ -1440,16 +1448,19 @@ static VALUE doc_exists(VALUE self, VALUE str) {
1440
1448
  static VALUE doc_each_leaf(int argc, VALUE *argv, VALUE self) {
1441
1449
  if (rb_block_given_p()) {
1442
1450
  Leaf save_path[MAX_STACK];
1443
- Doc doc = self_doc(self);
1451
+ Doc doc;
1444
1452
  const char *path = 0;
1445
1453
  size_t wlen;
1446
1454
 
1455
+ if (1 <= argc) {
1456
+ path = StringValuePtr(*argv);
1457
+ }
1458
+ doc = self_doc(self);
1447
1459
  wlen = doc->where - doc->where_path;
1448
1460
  if (0 < wlen) {
1449
1461
  memcpy(save_path, doc->where_path, sizeof(Leaf) * (wlen + 1));
1450
1462
  }
1451
- if (1 <= argc) {
1452
- path = StringValuePtr(*argv);
1463
+ if (0 != path) {
1453
1464
  if ('/' == *path) {
1454
1465
  doc->where = doc->where_path;
1455
1466
  path++;
@@ -1482,11 +1493,10 @@ static VALUE doc_each_leaf(int argc, VALUE *argv, VALUE self) {
1482
1493
  * "/one/2"
1483
1494
  */
1484
1495
  static VALUE doc_move(VALUE self, VALUE str) {
1485
- Doc doc = self_doc(self);
1486
- const char *path;
1496
+ const char *path = StringValuePtr(str);
1497
+ Doc doc = self_doc(self);
1487
1498
  int loc;
1488
1499
 
1489
- path = StringValuePtr(str);
1490
1500
  if ('/' == *path) {
1491
1501
  doc->where = doc->where_path;
1492
1502
  path++;
@@ -1517,17 +1527,21 @@ static VALUE doc_move(VALUE self, VALUE str) {
1517
1527
  static VALUE doc_each_child(int argc, VALUE *argv, VALUE self) {
1518
1528
  if (rb_block_given_p()) {
1519
1529
  Leaf save_path[MAX_STACK];
1520
- Doc doc = self_doc(self);
1530
+ Doc doc;
1521
1531
  const char *path = 0;
1522
1532
  size_t wlen;
1523
- Leaf *where_orig = doc->where;
1533
+ Leaf *where_orig;
1524
1534
 
1525
- wlen = doc->where - doc->where_path;
1535
+ if (1 <= argc) {
1536
+ path = StringValuePtr(*argv);
1537
+ }
1538
+ doc = self_doc(self);
1539
+ where_orig = doc->where;
1540
+ wlen = doc->where - doc->where_path;
1526
1541
  if (0 < wlen) {
1527
1542
  memcpy(save_path, doc->where_path, sizeof(Leaf) * (wlen + 1));
1528
1543
  }
1529
- if (1 <= argc) {
1530
- path = StringValuePtr(*argv);
1544
+ if (0 != path) {
1531
1545
  if ('/' == *path) {
1532
1546
  doc->where = doc->where_path;
1533
1547
  path++;
@@ -1595,13 +1609,14 @@ static VALUE doc_each_child(int argc, VALUE *argv, VALUE self) {
1595
1609
  */
1596
1610
  static VALUE doc_each_value(int argc, VALUE *argv, VALUE self) {
1597
1611
  if (rb_block_given_p()) {
1598
- Doc doc = self_doc(self);
1612
+ Doc doc;
1599
1613
  const char *path = 0;
1600
1614
  Leaf leaf;
1601
1615
 
1602
1616
  if (1 <= argc) {
1603
1617
  path = StringValuePtr(*argv);
1604
1618
  }
1619
+ doc = self_doc(self);
1605
1620
  if (0 != (leaf = get_doc_leaf(doc, path))) {
1606
1621
  each_value(doc, leaf, self);
1607
1622
  }
@@ -1624,19 +1639,23 @@ static VALUE doc_each_value(int argc, VALUE *argv, VALUE self) {
1624
1639
  * #=> "[2,1]"
1625
1640
  */
1626
1641
  static VALUE doc_dump(int argc, VALUE *argv, VALUE self) {
1627
- Doc doc = self_doc(self);
1642
+ Doc doc;
1628
1643
  Leaf leaf;
1629
1644
  const char *path = 0;
1630
1645
  const char *filename = 0;
1631
1646
 
1632
1647
  if (1 <= argc) {
1633
1648
  if (Qnil != *argv) {
1634
- path = StringValuePtr(*argv);
1649
+ StringValue(*argv);
1635
1650
  }
1636
1651
  if (2 <= argc) {
1637
- filename = StringValuePtr(argv[1]);
1652
+ filename = StringValueCStr(argv[1]);
1653
+ }
1654
+ if (Qnil != *argv) {
1655
+ path = RSTRING_PTR(*argv);
1638
1656
  }
1639
1657
  }
1658
+ doc = self_doc(self);
1640
1659
  if (0 != (leaf = get_doc_leaf(doc, path))) {
1641
1660
  volatile VALUE rjson;
1642
1661
 
@@ -1668,9 +1687,7 @@ static VALUE doc_dump(int argc, VALUE *argv, VALUE self) {
1668
1687
  * Oj::Doc.open('[1,2,3]') { |doc| doc.size() } #=> 4
1669
1688
  */
1670
1689
  static VALUE doc_size(VALUE self) {
1671
- Doc d;
1672
- TypedData_Get_Struct(self, struct _doc, &oj_doc_type, d);
1673
- return ULONG2NUM(d->size);
1690
+ return ULONG2NUM(self_doc(self)->size);
1674
1691
  }
1675
1692
 
1676
1693
  /* @overload close() => nil
data/ext/oj/intern.c CHANGED
@@ -17,9 +17,6 @@
17
17
  #define HASH_SLOT_CNT ((uint64_t)256)
18
18
  #define HASH_MASK (HASH_SLOT_CNT - 1)
19
19
 
20
- // almost the Murmur hash algorithm
21
- #define M 0x5bd1e995
22
-
23
20
  typedef struct _keyVal {
24
21
  struct _keyVal *next;
25
22
  const char *key;
@@ -155,40 +152,6 @@ ID oj_attr_intern(const char *key, size_t len) {
155
152
  return cache_intern(c, key, len);
156
153
  }
157
154
 
158
- static uint64_t hash_calc(const uint8_t *key, size_t len) {
159
- const uint8_t *end = key + len;
160
- const uint8_t *endless = key + (len & 0xFFFFFFFC);
161
- uint64_t h = (uint64_t)len ^ oj_hash_seed;
162
- uint64_t k;
163
-
164
- while (key < endless) {
165
- k = (uint64_t)*key++;
166
- k |= (uint64_t)*key++ << 8;
167
- k |= (uint64_t)*key++ << 16;
168
- k |= (uint64_t)*key++ << 24;
169
-
170
- k *= M;
171
- k ^= k >> 24;
172
- h *= M;
173
- h ^= k * M;
174
- }
175
- if (1 < end - key) {
176
- uint16_t k16 = (uint16_t)*key++;
177
-
178
- k16 |= (uint16_t)*key++ << 8;
179
- h ^= k16 << 8;
180
- }
181
- if (key < end) {
182
- h ^= *key;
183
- }
184
- h *= M;
185
- h ^= h >> 13;
186
- h *= M;
187
- h ^= h >> 15;
188
-
189
- return h;
190
- }
191
-
192
155
  static VALUE resolve_classname(VALUE mod, const char *classname, int auto_define) {
193
156
  VALUE clas;
194
157
  ID ci = rb_intern(classname);
@@ -264,14 +227,22 @@ static VALUE intern_new_class(VALUE a) {
264
227
  KeyVal bucket = args->bucket;
265
228
  VALUE clas = resolve_classpath(args->pi, args->key, args->len, args->auto_define, args->error_class);
266
229
 
230
+ if (Qundef == clas) {
231
+ return clas;
232
+ }
267
233
  if (NULL != bucket->key) { // not the top slot
268
- KeyVal b = OJ_R_ALLOC(struct _keyVal);
269
-
270
- b->next = NULL;
271
- bucket->next = b;
272
- bucket = b;
234
+ KeyVal b = (KeyVal)OJ_R_ALLOC_N(char, sizeof(struct _keyVal) + args->len + 1);
235
+ char *key = (char *)(b + 1);
236
+
237
+ memcpy(key, args->key, args->len);
238
+ key[args->len] = '\0';
239
+ b->next = NULL;
240
+ b->key = key;
241
+ bucket->next = b;
242
+ bucket = b;
243
+ } else {
244
+ bucket->key = oj_strndup(args->key, args->len);
273
245
  }
274
- bucket->key = oj_strndup(args->key, args->len);
275
246
  bucket->len = args->len;
276
247
  bucket->val = clas;
277
248
 
@@ -281,7 +252,7 @@ static VALUE intern_new_class(VALUE a) {
281
252
  static KeyVal find_class(KeyVal bucket, const char *key, size_t len, VALUE *clas) {
282
253
  if (NULL != bucket->key) { // not the top slot
283
254
  for (KeyVal b = bucket; 0 != b; b = b->next) {
284
- if (len == b->len && 0 == strncmp(b->key, key, len)) {
255
+ if (len == b->len && 0 == memcmp(b->key, key, len)) {
285
256
  *clas = b->val;
286
257
  return NULL;
287
258
  }
@@ -292,7 +263,7 @@ static KeyVal find_class(KeyVal bucket, const char *key, size_t len, VALUE *clas
292
263
  }
293
264
 
294
265
  VALUE oj_class_intern(const char *key, size_t len, bool safe, ParseInfo pi, int auto_define, VALUE error_class) {
295
- uint64_t h = hash_calc((const uint8_t *)key, len) & HASH_MASK;
266
+ uint64_t h = oj_hash_calc((const uint8_t *)key, len) & HASH_MASK;
296
267
  struct _internArgs args = {NULL, key, len, pi, auto_define, error_class};
297
268
  VALUE clas = Qundef;
298
269
 
@@ -321,7 +292,7 @@ VALUE oj_class_intern(const char *key, size_t len, bool safe, ParseInfo pi, int
321
292
  } else if (NULL != (args.bucket = find_class(class_hash.slots + h, key, len, &clas))) {
322
293
  clas = intern_new_class((VALUE)&args);
323
294
  }
324
- if (NULL != args.bucket) { // newly added to the cache
295
+ if (NULL != args.bucket && Qundef != clas) { // newly added to the cache
325
296
  rb_gc_register_mark_object(clas);
326
297
  }
327
298
  return clas;