msgpack 1.2.9 → 1.4.4

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 (46) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yaml +56 -0
  3. data/.gitignore +3 -1
  4. data/.rubocop.yml +4 -1
  5. data/ChangeLog +46 -0
  6. data/Gemfile +3 -0
  7. data/README.md +242 -0
  8. data/Rakefile +1 -9
  9. data/doclib/msgpack/factory.rb +1 -0
  10. data/doclib/msgpack/time.rb +22 -0
  11. data/doclib/msgpack/timestamp.rb +44 -0
  12. data/ext/java/org/msgpack/jruby/Buffer.java +17 -16
  13. data/ext/java/org/msgpack/jruby/Decoder.java +29 -10
  14. data/ext/java/org/msgpack/jruby/Encoder.java +22 -12
  15. data/ext/java/org/msgpack/jruby/ExtensionRegistry.java +9 -9
  16. data/ext/java/org/msgpack/jruby/ExtensionValue.java +5 -8
  17. data/ext/java/org/msgpack/jruby/Factory.java +7 -2
  18. data/ext/java/org/msgpack/jruby/Packer.java +11 -9
  19. data/ext/java/org/msgpack/jruby/Unpacker.java +40 -27
  20. data/ext/msgpack/buffer.c +4 -16
  21. data/ext/msgpack/buffer.h +60 -5
  22. data/ext/msgpack/compat.h +1 -12
  23. data/ext/msgpack/extconf.rb +39 -7
  24. data/ext/msgpack/factory_class.c +10 -5
  25. data/ext/msgpack/packer.c +18 -5
  26. data/ext/msgpack/packer.h +0 -16
  27. data/ext/msgpack/packer_class.c +0 -9
  28. data/ext/msgpack/packer_ext_registry.c +0 -22
  29. data/ext/msgpack/unpacker.c +41 -49
  30. data/ext/msgpack/unpacker.h +8 -0
  31. data/ext/msgpack/unpacker_class.c +23 -13
  32. data/lib/msgpack/symbol.rb +14 -4
  33. data/lib/msgpack/time.rb +29 -0
  34. data/lib/msgpack/timestamp.rb +76 -0
  35. data/lib/msgpack/version.rb +4 -7
  36. data/lib/msgpack.rb +5 -8
  37. data/msgpack.gemspec +3 -7
  38. data/spec/factory_spec.rb +17 -0
  39. data/spec/msgpack_spec.rb +1 -1
  40. data/spec/packer_spec.rb +18 -0
  41. data/spec/spec_helper.rb +27 -0
  42. data/spec/timestamp_spec.rb +161 -0
  43. data/spec/unpacker_spec.rb +113 -1
  44. metadata +19 -51
  45. data/.travis.yml +0 -41
  46. data/README.rdoc +0 -209
data/ext/msgpack/buffer.c CHANGED
@@ -23,11 +23,11 @@
23
23
  static ID s_replace;
24
24
  #endif
25
25
 
26
- #ifdef COMPAT_HAVE_ENCODING /* see compat.h*/
27
26
  int msgpack_rb_encindex_utf8;
28
27
  int msgpack_rb_encindex_usascii;
29
28
  int msgpack_rb_encindex_ascii8bit;
30
- #endif
29
+
30
+ ID s_uminus;
31
31
 
32
32
  #ifndef DISABLE_RMEM
33
33
  static msgpack_rmem_t s_rmem;
@@ -35,11 +35,11 @@ static msgpack_rmem_t s_rmem;
35
35
 
36
36
  void msgpack_buffer_static_init()
37
37
  {
38
- #ifdef COMPAT_HAVE_ENCODING
38
+ s_uminus = rb_intern("-@");
39
+
39
40
  msgpack_rb_encindex_utf8 = rb_utf8_encindex();
40
41
  msgpack_rb_encindex_usascii = rb_usascii_encindex();
41
42
  msgpack_rb_encindex_ascii8bit = rb_ascii8bit_encindex();
42
- #endif
43
43
 
44
44
  #ifndef DISABLE_RMEM
45
45
  msgpack_rmem_init(&s_rmem);
@@ -164,12 +164,7 @@ size_t msgpack_buffer_read_to_string_nonblock(msgpack_buffer_t* b, VALUE string,
164
164
  b->head->mapped_string != NO_MAPPED_STRING &&
165
165
  length >= b->read_reference_threshold) {
166
166
  VALUE s = _msgpack_buffer_refer_head_mapped_string(b, length);
167
- #ifndef HAVE_RB_STR_REPLACE
168
- /* TODO MRI 1.8 */
169
- rb_funcall(string, s_replace, 1, s);
170
- #else
171
167
  rb_str_replace(string, s);
172
- #endif
173
168
  /* here doesn't have to call ENCODING_SET because
174
169
  * encoding of s is always ASCII-8BIT */
175
170
  _msgpack_buffer_consumed(b, length);
@@ -308,9 +303,7 @@ static inline void _msgpack_buffer_add_new_chunk(msgpack_buffer_t* b)
308
303
  static inline void _msgpack_buffer_append_reference(msgpack_buffer_t* b, VALUE string)
309
304
  {
310
305
  VALUE mapped_string = rb_str_dup(string);
311
- #ifdef COMPAT_HAVE_ENCODING
312
306
  ENCODING_SET(mapped_string, msgpack_rb_encindex_ascii8bit);
313
- #endif
314
307
 
315
308
  _msgpack_buffer_add_new_chunk(b);
316
309
 
@@ -337,7 +330,6 @@ void _msgpack_buffer_append_long_string(msgpack_buffer_t* b, VALUE string)
337
330
 
338
331
  if(b->io != Qnil) {
339
332
  msgpack_buffer_flush(b);
340
- #ifdef COMPAT_HAVE_ENCODING
341
333
  if (ENCODING_GET(string) == msgpack_rb_encindex_ascii8bit) {
342
334
  rb_funcall(b->io, b->io_write_all_method, 1, string);
343
335
  } else if(!STR_DUP_LIKELY_DOES_COPY(string)) {
@@ -347,10 +339,6 @@ void _msgpack_buffer_append_long_string(msgpack_buffer_t* b, VALUE string)
347
339
  } else {
348
340
  msgpack_buffer_append(b, RSTRING_PTR(string), length);
349
341
  }
350
- #else
351
- rb_funcall(b->io, b->io_write_all_method, 1, string);
352
- #endif
353
-
354
342
  } else if(!STR_DUP_LIKELY_DOES_COPY(string)) {
355
343
  _msgpack_buffer_append_reference(b, string);
356
344
 
data/ext/msgpack/buffer.h CHANGED
@@ -49,11 +49,11 @@
49
49
 
50
50
  #define NO_MAPPED_STRING ((VALUE)0)
51
51
 
52
- #ifdef COMPAT_HAVE_ENCODING /* see compat.h*/
53
52
  extern int msgpack_rb_encindex_utf8;
54
53
  extern int msgpack_rb_encindex_usascii;
55
54
  extern int msgpack_rb_encindex_ascii8bit;
56
- #endif
55
+
56
+ extern ID s_uminus;
57
57
 
58
58
  struct msgpack_buffer_chunk_t;
59
59
  typedef struct msgpack_buffer_chunk_t msgpack_buffer_chunk_t;
@@ -262,6 +262,20 @@ static inline size_t msgpack_buffer_append_string(msgpack_buffer_t* b, VALUE str
262
262
  return length;
263
263
  }
264
264
 
265
+ static inline size_t msgpack_buffer_append_string_reference(msgpack_buffer_t* b, VALUE string)
266
+ {
267
+ size_t length = RSTRING_LEN(string);
268
+
269
+ if(length > MSGPACK_BUFFER_STRING_WRITE_REFERENCE_MINIMUM) {
270
+ _msgpack_buffer_append_long_string(b, string);
271
+
272
+ } else {
273
+ msgpack_buffer_append(b, RSTRING_PTR(string), length);
274
+ }
275
+
276
+ return length;
277
+ }
278
+
265
279
 
266
280
  /*
267
281
  * IO functions
@@ -424,7 +438,7 @@ static inline VALUE _msgpack_buffer_refer_head_mapped_string(msgpack_buffer_t* b
424
438
  return rb_str_substr(b->head->mapped_string, offset, length);
425
439
  }
426
440
 
427
- static inline VALUE msgpack_buffer_read_top_as_string(msgpack_buffer_t* b, size_t length, bool will_be_frozen)
441
+ static inline VALUE msgpack_buffer_read_top_as_string(msgpack_buffer_t* b, size_t length, bool will_be_frozen, bool utf8)
428
442
  {
429
443
  #ifndef DISABLE_BUFFER_READ_REFERENCE_OPTIMIZE
430
444
  /* optimize */
@@ -432,16 +446,57 @@ static inline VALUE msgpack_buffer_read_top_as_string(msgpack_buffer_t* b, size_
432
446
  b->head->mapped_string != NO_MAPPED_STRING &&
433
447
  length >= b->read_reference_threshold) {
434
448
  VALUE result = _msgpack_buffer_refer_head_mapped_string(b, length);
449
+ if (utf8) ENCODING_SET(result, msgpack_rb_encindex_utf8);
435
450
  _msgpack_buffer_consumed(b, length);
436
451
  return result;
437
452
  }
438
453
  #endif
439
454
 
440
- VALUE result = rb_str_new(b->read_buffer, length);
455
+ VALUE result;
456
+
457
+ #ifdef HAVE_RB_ENC_INTERNED_STR
458
+ if (will_be_frozen) {
459
+ result = rb_enc_interned_str(b->read_buffer, length, utf8 ? rb_utf8_encoding() : rb_ascii8bit_encoding());
460
+ } else {
461
+ if (utf8) {
462
+ result = rb_utf8_str_new(b->read_buffer, length);
463
+ } else {
464
+ result = rb_str_new(b->read_buffer, length);
465
+ }
466
+ }
441
467
  _msgpack_buffer_consumed(b, length);
442
468
  return result;
469
+
470
+ #else
471
+
472
+ if (utf8) {
473
+ result = rb_utf8_str_new(b->read_buffer, length);
474
+ } else {
475
+ result = rb_str_new(b->read_buffer, length);
476
+ }
477
+
478
+ #if STR_UMINUS_DEDUPE
479
+ if (will_be_frozen) {
480
+ #if STR_UMINUS_DEDUPE_FROZEN
481
+ // Starting from MRI 2.8 it is preferable to freeze the string
482
+ // before deduplication so that it can be interned directly
483
+ // otherwise it would be duplicated first which is wasteful.
484
+ rb_str_freeze(result);
485
+ #endif //STR_UMINUS_DEDUPE_FROZEN
486
+ // MRI 2.5 and older do not deduplicate strings that are already
487
+ // frozen.
488
+ result = rb_funcall(result, s_uminus, 0);
489
+ }
490
+ #endif // STR_UMINUS_DEDUPE
491
+ _msgpack_buffer_consumed(b, length);
492
+ return result;
493
+
494
+ #endif // HAVE_RB_ENC_INTERNED_STR
443
495
  }
444
496
 
497
+ static inline VALUE msgpack_buffer_read_top_as_symbol(msgpack_buffer_t* b, size_t length)
498
+ {
499
+ return rb_str_intern(msgpack_buffer_read_top_as_string(b, length, true, false));
500
+ }
445
501
 
446
502
  #endif
447
-
data/ext/msgpack/compat.h CHANGED
@@ -20,6 +20,7 @@
20
20
 
21
21
  #include <stdbool.h>
22
22
  #include "ruby.h"
23
+ #include "ruby/encoding.h"
23
24
 
24
25
  #if defined(HAVE_RUBY_ST_H)
25
26
  # include "ruby/st.h" /* ruby hash on Ruby 1.9 */
@@ -38,18 +39,6 @@
38
39
  # define ZALLOC_N(type,n) RB_ZALLOC_N(type,n)
39
40
  #endif
40
41
 
41
- /*
42
- * COMPAT_HAVE_ENCODING
43
- */
44
- #ifdef HAVE_RUBY_ENCODING_H
45
- # include "ruby/encoding.h"
46
- # define COMPAT_HAVE_ENCODING
47
- #endif
48
-
49
- #if defined(__MACRUBY__) /* MacRuby */
50
- # undef COMPAT_HAVE_ENCODING
51
- #endif
52
-
53
42
 
54
43
  /*
55
44
  * define STR_DUP_LIKELY_DOES_COPY
@@ -2,13 +2,7 @@ require 'mkmf'
2
2
 
3
3
  have_header("ruby/st.h")
4
4
  have_header("st.h")
5
- have_func("rb_str_replace", ["ruby.h"])
6
- have_func("rb_intern_str", ["ruby.h"])
7
- have_func("rb_sym2str", ["ruby.h"])
8
- have_func("rb_str_intern", ["ruby.h"])
9
- have_func("rb_block_lambda", ["ruby.h"])
10
- have_func("rb_hash_dup", ["ruby.h"])
11
- have_func("rb_hash_clear", ["ruby.h"])
5
+ have_func("rb_enc_interned_str", "ruby.h")
12
6
 
13
7
  unless RUBY_PLATFORM.include? 'mswin'
14
8
  $CFLAGS << %[ -I.. -Wall -O3 -g -std=gnu99]
@@ -25,6 +19,44 @@ if defined?(RUBY_ENGINE) && RUBY_ENGINE == 'rbx'
25
19
  $CFLAGS << %[ -DDISABLE_RMEM]
26
20
  end
27
21
 
22
+ # checking if Hash#[]= (rb_hash_aset) dedupes string keys
23
+ h = {}
24
+ x = {}
25
+ r = rand.to_s
26
+ h[%W(#{r}).join('')] = :foo
27
+ x[%W(#{r}).join('')] = :foo
28
+ if x.keys[0].equal?(h.keys[0])
29
+ $CFLAGS << ' -DHASH_ASET_DEDUPE=1 '
30
+ else
31
+ $CFLAGS << ' -DHASH_ASET_DEDUPE=0 '
32
+ end
33
+
34
+
35
+ # checking if String#-@ (str_uminus) dedupes... '
36
+ begin
37
+ a = -(%w(t e s t).join)
38
+ b = -(%w(t e s t).join)
39
+ if a.equal?(b)
40
+ $CFLAGS << ' -DSTR_UMINUS_DEDUPE=1 '
41
+ else
42
+ $CFLAGS += ' -DSTR_UMINUS_DEDUPE=0 '
43
+ end
44
+ rescue NoMethodError
45
+ $CFLAGS << ' -DSTR_UMINUS_DEDUPE=0 '
46
+ end
47
+
48
+ # checking if String#-@ (str_uminus) directly interns frozen strings... '
49
+ begin
50
+ s = rand.to_s.freeze
51
+ if (-s).equal?(s) && (-s.dup).equal?(s)
52
+ $CFLAGS << ' -DSTR_UMINUS_DEDUPE_FROZEN=1 '
53
+ else
54
+ $CFLAGS << ' -DSTR_UMINUS_DEDUPE_FROZEN=0 '
55
+ end
56
+ rescue NoMethodError
57
+ $CFLAGS << ' -DSTR_UMINUS_DEDUPE_FROZEN=0 '
58
+ end
59
+
28
60
  if warnflags = CONFIG['warnflags']
29
61
  warnflags.slice!(/ -Wdeclaration-after-statement/)
30
62
  end
@@ -32,6 +32,8 @@ struct msgpack_factory_t {
32
32
  msgpack_packer_ext_registry_t pkrg;
33
33
  msgpack_unpacker_ext_registry_t ukrg;
34
34
  bool has_symbol_ext_type;
35
+ bool optimized_symbol_ext_type;
36
+ int symbol_ext_type;
35
37
  };
36
38
 
37
39
  #define FACTORY(from, name) \
@@ -114,6 +116,8 @@ VALUE MessagePack_Factory_unpacker(int argc, VALUE* argv, VALUE self)
114
116
 
115
117
  msgpack_unpacker_ext_registry_destroy(&uk->ext_registry);
116
118
  msgpack_unpacker_ext_registry_dup(&fc->ukrg, &uk->ext_registry);
119
+ uk->optimized_symbol_ext_type = fc->optimized_symbol_ext_type;
120
+ uk->symbol_ext_type = fc->symbol_ext_type;
117
121
 
118
122
  return unpacker;
119
123
  }
@@ -128,11 +132,7 @@ static VALUE Factory_registered_types_internal(VALUE self)
128
132
  rb_hash_aset(uk_mapping, INT2FIX(i - 128), fc->ukrg.array[i]);
129
133
  }
130
134
  }
131
- #ifdef HAVE_RB_HASH_DUP
132
135
  return rb_ary_new3(2, rb_hash_dup(fc->pkrg.hash), uk_mapping);
133
- #else
134
- return rb_ary_new3(2, rb_funcall(fc->pkrg.hash, rb_intern("dup"), 0), uk_mapping);
135
- #endif
136
136
  }
137
137
 
138
138
  static VALUE Factory_register_type(int argc, VALUE* argv, VALUE self)
@@ -141,7 +141,7 @@ static VALUE Factory_register_type(int argc, VALUE* argv, VALUE self)
141
141
 
142
142
  int ext_type;
143
143
  VALUE ext_module;
144
- VALUE options;
144
+ VALUE options = Qnil;
145
145
  VALUE packer_arg, unpacker_arg;
146
146
  VALUE packer_proc, unpacker_proc;
147
147
 
@@ -188,6 +188,8 @@ static VALUE Factory_register_type(int argc, VALUE* argv, VALUE self)
188
188
  if(unpacker_arg != Qnil) {
189
189
  if(rb_type(unpacker_arg) == T_SYMBOL || rb_type(unpacker_arg) == T_STRING) {
190
190
  unpacker_proc = rb_obj_method(ext_module, unpacker_arg);
191
+ } else if (rb_respond_to(unpacker_arg, rb_intern("call"))) {
192
+ unpacker_proc = unpacker_arg;
191
193
  } else {
192
194
  unpacker_proc = rb_funcall(unpacker_arg, rb_intern("method"), 1, ID2SYM(rb_intern("call")));
193
195
  }
@@ -197,6 +199,9 @@ static VALUE Factory_register_type(int argc, VALUE* argv, VALUE self)
197
199
 
198
200
  if (ext_module == rb_cSymbol) {
199
201
  fc->has_symbol_ext_type = true;
202
+ if(RB_TEST(options) && RB_TEST(rb_hash_aref(options, ID2SYM(rb_intern("optimized_symbols_parsing"))))) {
203
+ fc->optimized_symbol_ext_type = true;
204
+ }
200
205
  }
201
206
 
202
207
  msgpack_unpacker_ext_registry_put(&fc->ukrg, ext_module, ext_type, unpacker_proc, unpacker_arg);
data/ext/msgpack/packer.c CHANGED
@@ -121,7 +121,7 @@ void msgpack_packer_write_hash_value(msgpack_packer_t* pk, VALUE v)
121
121
  #endif
122
122
  }
123
123
 
124
- void msgpack_packer_write_other_value(msgpack_packer_t* pk, VALUE v)
124
+ bool msgpack_packer_try_write_with_ext_type_lookup(msgpack_packer_t* pk, VALUE v)
125
125
  {
126
126
  int ext_type;
127
127
 
@@ -131,7 +131,14 @@ void msgpack_packer_write_other_value(msgpack_packer_t* pk, VALUE v)
131
131
  VALUE payload = rb_funcall(proc, s_call, 1, v);
132
132
  StringValue(payload);
133
133
  msgpack_packer_write_ext(pk, ext_type, payload);
134
- } else {
134
+ return true;
135
+ }
136
+ return false;
137
+ }
138
+
139
+ void msgpack_packer_write_other_value(msgpack_packer_t* pk, VALUE v)
140
+ {
141
+ if(!(msgpack_packer_try_write_with_ext_type_lookup(pk, v))) {
135
142
  rb_funcall(v, pk->to_msgpack_method, 1, pk->to_msgpack_arg);
136
143
  }
137
144
  }
@@ -155,13 +162,19 @@ void msgpack_packer_write_value(msgpack_packer_t* pk, VALUE v)
155
162
  msgpack_packer_write_symbol_value(pk, v);
156
163
  break;
157
164
  case T_STRING:
158
- msgpack_packer_write_string_value(pk, v);
165
+ if(rb_class_of(v) == rb_cString || !msgpack_packer_try_write_with_ext_type_lookup(pk, v)) {
166
+ msgpack_packer_write_string_value(pk, v);
167
+ }
159
168
  break;
160
169
  case T_ARRAY:
161
- msgpack_packer_write_array_value(pk, v);
170
+ if(rb_class_of(v) == rb_cArray || !msgpack_packer_try_write_with_ext_type_lookup(pk, v)) {
171
+ msgpack_packer_write_array_value(pk, v);
172
+ }
162
173
  break;
163
174
  case T_HASH:
164
- msgpack_packer_write_hash_value(pk, v);
175
+ if(rb_class_of(v) == rb_cHash || !msgpack_packer_try_write_with_ext_type_lookup(pk, v)) {
176
+ msgpack_packer_write_hash_value(pk, v);
177
+ }
165
178
  break;
166
179
  case T_BIGNUM:
167
180
  msgpack_packer_write_bignum_value(pk, v);
data/ext/msgpack/packer.h CHANGED
@@ -396,7 +396,6 @@ static inline void msgpack_packer_write_ext(msgpack_packer_t* pk, int ext_type,
396
396
  msgpack_buffer_append_string(PACKER_BUFFER_(pk), payload);
397
397
  }
398
398
 
399
- #ifdef COMPAT_HAVE_ENCODING
400
399
  static inline bool msgpack_packer_is_binary(VALUE v, int encindex)
401
400
  {
402
401
  return encindex == msgpack_rb_encindex_ascii8bit;
@@ -414,7 +413,6 @@ static inline bool msgpack_packer_is_utf8_compat_string(VALUE v, int encindex)
414
413
  #endif
415
414
  ;
416
415
  }
417
- #endif
418
416
 
419
417
  static inline void msgpack_packer_write_string_value(msgpack_packer_t* pk, VALUE v)
420
418
  {
@@ -425,7 +423,6 @@ static inline void msgpack_packer_write_string_value(msgpack_packer_t* pk, VALUE
425
423
  rb_raise(rb_eArgError, "size of string is too long to pack: %lu bytes should be <= %lu", len, 0xffffffffUL);
426
424
  }
427
425
 
428
- #ifdef COMPAT_HAVE_ENCODING
429
426
  int encindex = ENCODING_GET(v);
430
427
  if(msgpack_packer_is_binary(v, encindex) && !pk->compatibility_mode) {
431
428
  /* write ASCII-8BIT string using Binary type */
@@ -443,24 +440,11 @@ static inline void msgpack_packer_write_string_value(msgpack_packer_t* pk, VALUE
443
440
  msgpack_packer_write_raw_header(pk, (unsigned int)len);
444
441
  msgpack_buffer_append_string(PACKER_BUFFER_(pk), v);
445
442
  }
446
- #else
447
- msgpack_packer_write_raw_header(pk, (unsigned int)len);
448
- msgpack_buffer_append_string(PACKER_BUFFER_(pk), v);
449
- #endif
450
443
  }
451
444
 
452
445
  static inline void msgpack_packer_write_symbol_string_value(msgpack_packer_t* pk, VALUE v)
453
446
  {
454
- #ifdef HAVE_RB_SYM2STR
455
- /* rb_sym2str is added since MRI 2.2.0 */
456
447
  msgpack_packer_write_string_value(pk, rb_sym2str(v));
457
- #else
458
- VALUE str = rb_id2str(SYM2ID(v));
459
- if (!str) {
460
- rb_raise(rb_eRuntimeError, "could not convert a symbol to string");
461
- }
462
- msgpack_packer_write_string_value(pk, str);
463
- #endif
464
448
  }
465
449
 
466
450
  void msgpack_packer_write_other_value(msgpack_packer_t* pk, VALUE v);
@@ -339,11 +339,7 @@ static VALUE Packer_write_to(VALUE self, VALUE io)
339
339
  static VALUE Packer_registered_types_internal(VALUE self)
340
340
  {
341
341
  PACKER(self, pk);
342
- #ifdef HAVE_RB_HASH_DUP
343
342
  return rb_hash_dup(pk->ext_registry.hash);
344
- #else
345
- return rb_funcall(pk->ext_registry.hash, rb_intern("dup"), 0);
346
- #endif
347
343
  }
348
344
 
349
345
  static VALUE Packer_register_type(int argc, VALUE* argv, VALUE self)
@@ -359,12 +355,7 @@ static VALUE Packer_register_type(int argc, VALUE* argv, VALUE self)
359
355
  case 2:
360
356
  /* register_type(0x7f, Time) {|obj| block... } */
361
357
  rb_need_block();
362
- #ifdef HAVE_RB_BLOCK_LAMBDA
363
358
  proc = rb_block_lambda();
364
- #else
365
- /* MRI 1.8 */
366
- proc = rb_block_proc();
367
- #endif
368
359
  arg = proc;
369
360
  break;
370
361
  case 3:
@@ -43,37 +43,15 @@ void msgpack_packer_ext_registry_mark(msgpack_packer_ext_registry_t* pkrg)
43
43
  void msgpack_packer_ext_registry_dup(msgpack_packer_ext_registry_t* src,
44
44
  msgpack_packer_ext_registry_t* dst)
45
45
  {
46
- #ifdef HAVE_RB_HASH_DUP
47
46
  dst->hash = rb_hash_dup(src->hash);
48
47
  dst->cache = rb_hash_dup(src->cache);
49
- #else
50
- dst->hash = rb_funcall(src->hash, rb_intern("dup"), 0);
51
- dst->cache = rb_funcall(src->cache, rb_intern("dup"), 0);
52
- #endif
53
48
  }
54
49
 
55
- #ifndef HAVE_RB_HASH_CLEAR
56
-
57
- static int
58
- __rb_hash_clear_clear_i(key, value, dummy)
59
- VALUE key, value, dummy;
60
- {
61
- return ST_DELETE;
62
- }
63
-
64
- #endif
65
-
66
50
  VALUE msgpack_packer_ext_registry_put(msgpack_packer_ext_registry_t* pkrg,
67
51
  VALUE ext_module, int ext_type, VALUE proc, VALUE arg)
68
52
  {
69
53
  VALUE e = rb_ary_new3(3, INT2FIX(ext_type), proc, arg);
70
54
  /* clear lookup cache not to miss added type */
71
- #ifdef HAVE_RB_HASH_CLEAR
72
55
  rb_hash_clear(pkrg->cache);
73
- #else
74
- if(FIX2INT(rb_funcall(pkrg->cache, rb_intern("size"), 0)) > 0) {
75
- rb_hash_foreach(pkrg->cache, __rb_hash_clear_clear_i, 0);
76
- }
77
- #endif
78
56
  return rb_hash_aset(pkrg->hash, ext_module, e);
79
57
  }
@@ -142,32 +142,27 @@ static inline void reset_head_byte(msgpack_unpacker_t* uk)
142
142
 
143
143
  static inline int object_complete(msgpack_unpacker_t* uk, VALUE object)
144
144
  {
145
+ if(uk->freeze) {
146
+ rb_obj_freeze(object);
147
+ }
148
+
145
149
  uk->last_object = object;
146
150
  reset_head_byte(uk);
147
151
  return PRIMITIVE_OBJECT_COMPLETE;
148
152
  }
149
153
 
150
- static inline int object_complete_string(msgpack_unpacker_t* uk, VALUE str)
151
- {
152
- #ifdef COMPAT_HAVE_ENCODING
153
- ENCODING_SET(str, msgpack_rb_encindex_utf8);
154
- #endif
155
- return object_complete(uk, str);
156
- }
157
-
158
- static inline int object_complete_binary(msgpack_unpacker_t* uk, VALUE str)
154
+ static inline int object_complete_symbol(msgpack_unpacker_t* uk, VALUE object)
159
155
  {
160
- #ifdef COMPAT_HAVE_ENCODING
161
- ENCODING_SET(str, msgpack_rb_encindex_ascii8bit);
162
- #endif
163
- return object_complete(uk, str);
156
+ uk->last_object = object;
157
+ reset_head_byte(uk);
158
+ return PRIMITIVE_OBJECT_COMPLETE;
164
159
  }
165
160
 
166
161
  static inline int object_complete_ext(msgpack_unpacker_t* uk, int ext_type, VALUE str)
167
162
  {
168
- #ifdef COMPAT_HAVE_ENCODING
169
- ENCODING_SET(str, msgpack_rb_encindex_ascii8bit);
170
- #endif
163
+ if (uk->optimized_symbol_ext_type && ext_type == uk->symbol_ext_type) {
164
+ return object_complete_symbol(uk, rb_str_intern(str));
165
+ }
171
166
 
172
167
  VALUE proc = msgpack_unpacker_ext_registry_lookup(&uk->ext_registry, ext_type);
173
168
  if(proc != Qnil) {
@@ -271,9 +266,10 @@ static int read_raw_body_cont(msgpack_unpacker_t* uk)
271
266
 
272
267
  int ret;
273
268
  if(uk->reading_raw_type == RAW_TYPE_STRING) {
274
- ret = object_complete_string(uk, uk->reading_raw);
275
- } else if(uk->reading_raw_type == RAW_TYPE_BINARY) {
276
- ret = object_complete_binary(uk, uk->reading_raw);
269
+ ENCODING_SET(uk->reading_raw, msgpack_rb_encindex_utf8);
270
+ ret = object_complete(uk, uk->reading_raw);
271
+ } else if (uk->reading_raw_type == RAW_TYPE_BINARY) {
272
+ ret = object_complete(uk, uk->reading_raw);
277
273
  } else {
278
274
  ret = object_complete_ext(uk, uk->reading_raw_type, uk->reading_raw);
279
275
  }
@@ -288,20 +284,26 @@ static inline int read_raw_body_begin(msgpack_unpacker_t* uk, int raw_type)
288
284
  /* try optimized read */
289
285
  size_t length = uk->reading_raw_remaining;
290
286
  if(length <= msgpack_buffer_top_readable_size(UNPACKER_BUFFER_(uk))) {
291
- /* don't use zerocopy for hash keys but get a frozen string directly
292
- * because rb_hash_aset freezes keys and it causes copying */
293
- bool will_freeze = is_reading_map_key(uk);
294
- VALUE string = msgpack_buffer_read_top_as_string(UNPACKER_BUFFER_(uk), length, will_freeze);
295
287
  int ret;
296
- if(raw_type == RAW_TYPE_STRING) {
297
- ret = object_complete_string(uk, string);
298
- } else if(raw_type == RAW_TYPE_BINARY) {
299
- ret = object_complete_binary(uk, string);
288
+ if ((uk->optimized_symbol_ext_type && uk->symbol_ext_type == raw_type) || (uk->symbolize_keys && is_reading_map_key(uk))) {
289
+ VALUE symbol = msgpack_buffer_read_top_as_symbol(UNPACKER_BUFFER_(uk), length);
290
+ ret = object_complete_symbol(uk, symbol);
300
291
  } else {
301
- ret = object_complete_ext(uk, raw_type, string);
302
- }
303
- if(will_freeze) {
304
- rb_obj_freeze(string);
292
+ /* don't use zerocopy for hash keys but get a frozen string directly
293
+ * because rb_hash_aset freezes keys and it causes copying */
294
+ bool will_freeze = uk->freeze || is_reading_map_key(uk);
295
+ VALUE string = msgpack_buffer_read_top_as_string(UNPACKER_BUFFER_(uk), length, will_freeze, raw_type == RAW_TYPE_STRING);
296
+ if(raw_type == RAW_TYPE_STRING || raw_type == RAW_TYPE_BINARY) {
297
+ ret = object_complete(uk, string);
298
+ } else {
299
+ ret = object_complete_ext(uk, raw_type, string);
300
+ }
301
+
302
+ # if !HASH_ASET_DEDUPE
303
+ if(will_freeze) {
304
+ rb_obj_freeze(string);
305
+ }
306
+ # endif
305
307
  }
306
308
  uk->reading_raw_remaining = 0;
307
309
  return ret;
@@ -332,7 +334,7 @@ static int read_primitive(msgpack_unpacker_t* uk)
332
334
  SWITCH_RANGE(b, 0xa0, 0xbf) // FixRaw / fixstr
333
335
  int count = b & 0x1f;
334
336
  if(count == 0) {
335
- return object_complete_string(uk, rb_str_buf_new(0));
337
+ return object_complete(uk, rb_utf8_str_new_static("", 0));
336
338
  }
337
339
  /* read_raw_body_begin sets uk->reading_raw */
338
340
  uk->reading_raw_remaining = count;
@@ -517,7 +519,7 @@ static int read_primitive(msgpack_unpacker_t* uk)
517
519
  READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 1);
518
520
  uint8_t count = cb->u8;
519
521
  if(count == 0) {
520
- return object_complete_string(uk, rb_str_buf_new(0));
522
+ return object_complete(uk, rb_utf8_str_new_static("", 0));
521
523
  }
522
524
  /* read_raw_body_begin sets uk->reading_raw */
523
525
  uk->reading_raw_remaining = count;
@@ -529,7 +531,7 @@ static int read_primitive(msgpack_unpacker_t* uk)
529
531
  READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 2);
530
532
  uint16_t count = _msgpack_be16(cb->u16);
531
533
  if(count == 0) {
532
- return object_complete_string(uk, rb_str_buf_new(0));
534
+ return object_complete(uk, rb_utf8_str_new_static("", 0));
533
535
  }
534
536
  /* read_raw_body_begin sets uk->reading_raw */
535
537
  uk->reading_raw_remaining = count;
@@ -541,7 +543,7 @@ static int read_primitive(msgpack_unpacker_t* uk)
541
543
  READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 4);
542
544
  uint32_t count = _msgpack_be32(cb->u32);
543
545
  if(count == 0) {
544
- return object_complete_string(uk, rb_str_buf_new(0));
546
+ return object_complete(uk, rb_utf8_str_new_static("", 0));
545
547
  }
546
548
  /* read_raw_body_begin sets uk->reading_raw */
547
549
  uk->reading_raw_remaining = count;
@@ -553,7 +555,7 @@ static int read_primitive(msgpack_unpacker_t* uk)
553
555
  READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 1);
554
556
  uint8_t count = cb->u8;
555
557
  if(count == 0) {
556
- return object_complete_binary(uk, rb_str_buf_new(0));
558
+ return object_complete(uk, rb_str_new_static("", 0));
557
559
  }
558
560
  /* read_raw_body_begin sets uk->reading_raw */
559
561
  uk->reading_raw_remaining = count;
@@ -565,7 +567,7 @@ static int read_primitive(msgpack_unpacker_t* uk)
565
567
  READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 2);
566
568
  uint16_t count = _msgpack_be16(cb->u16);
567
569
  if(count == 0) {
568
- return object_complete_binary(uk, rb_str_buf_new(0));
570
+ return object_complete(uk, rb_str_new_static("", 0));
569
571
  }
570
572
  /* read_raw_body_begin sets uk->reading_raw */
571
573
  uk->reading_raw_remaining = count;
@@ -577,7 +579,7 @@ static int read_primitive(msgpack_unpacker_t* uk)
577
579
  READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 4);
578
580
  uint32_t count = _msgpack_be32(cb->u32);
579
581
  if(count == 0) {
580
- return object_complete_binary(uk, rb_str_buf_new(0));
582
+ return object_complete(uk, rb_str_new_static("", 0));
581
583
  }
582
584
  /* read_raw_body_begin sets uk->reading_raw */
583
585
  uk->reading_raw_remaining = count;
@@ -719,18 +721,8 @@ int msgpack_unpacker_read(msgpack_unpacker_t* uk, size_t target_stack_depth)
719
721
  break;
720
722
  case STACK_TYPE_MAP_VALUE:
721
723
  if(uk->symbolize_keys && rb_type(top->key) == T_STRING) {
722
- /* here uses rb_intern_str instead of rb_intern so that Ruby VM can GC unused symbols */
723
- #ifdef HAVE_RB_STR_INTERN
724
- /* rb_str_intern is added since MRI 2.2.0 */
724
+ /* here uses rb_str_intern instead of rb_intern so that Ruby VM can GC unused symbols */
725
725
  rb_hash_aset(top->object, rb_str_intern(top->key), uk->last_object);
726
- #else
727
- #ifndef HAVE_RB_INTERN_STR
728
- /* MRI 1.8 doesn't have rb_intern_str or rb_intern2 */
729
- rb_hash_aset(top->object, ID2SYM(rb_intern(RSTRING_PTR(top->key))), uk->last_object);
730
- #else
731
- rb_hash_aset(top->object, ID2SYM(rb_intern_str(top->key)), uk->last_object);
732
- #endif
733
- #endif
734
726
  } else {
735
727
  rb_hash_aset(top->object, top->key, uk->last_object);
736
728
  }
@@ -64,7 +64,10 @@ struct msgpack_unpacker_t {
64
64
 
65
65
  /* options */
66
66
  bool symbolize_keys;
67
+ bool freeze;
67
68
  bool allow_unknown_ext;
69
+ bool optimized_symbol_ext_type;
70
+ int symbol_ext_type;
68
71
  };
69
72
 
70
73
  #define UNPACKER_BUFFER_(uk) (&(uk)->buffer)
@@ -96,6 +99,11 @@ static inline void msgpack_unpacker_set_symbolized_keys(msgpack_unpacker_t* uk,
96
99
  uk->symbolize_keys = enable;
97
100
  }
98
101
 
102
+ static inline void msgpack_unpacker_set_freeze(msgpack_unpacker_t* uk, bool enable)
103
+ {
104
+ uk->freeze = enable;
105
+ }
106
+
99
107
  static inline void msgpack_unpacker_set_allow_unknown_ext(msgpack_unpacker_t* uk, bool enable)
100
108
  {
101
109
  uk->allow_unknown_ext = enable;