msgpack 1.4.2 → 1.7.2

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 (95) hide show
  1. checksums.yaml +4 -4
  2. data/ChangeLog +85 -0
  3. data/README.md +52 -1
  4. data/ext/java/org/msgpack/jruby/Buffer.java +26 -19
  5. data/ext/java/org/msgpack/jruby/Decoder.java +29 -21
  6. data/ext/java/org/msgpack/jruby/Encoder.java +68 -30
  7. data/ext/java/org/msgpack/jruby/ExtensionRegistry.java +43 -64
  8. data/ext/java/org/msgpack/jruby/ExtensionValue.java +6 -9
  9. data/ext/java/org/msgpack/jruby/Factory.java +43 -42
  10. data/ext/java/org/msgpack/jruby/Packer.java +37 -40
  11. data/ext/java/org/msgpack/jruby/Unpacker.java +80 -73
  12. data/ext/msgpack/buffer.c +54 -74
  13. data/ext/msgpack/buffer.h +21 -18
  14. data/ext/msgpack/buffer_class.c +161 -52
  15. data/ext/msgpack/buffer_class.h +1 -0
  16. data/ext/msgpack/compat.h +0 -99
  17. data/ext/msgpack/extconf.rb +25 -46
  18. data/ext/msgpack/factory_class.c +143 -87
  19. data/ext/msgpack/packer.c +66 -43
  20. data/ext/msgpack/packer.h +25 -20
  21. data/ext/msgpack/packer_class.c +102 -130
  22. data/ext/msgpack/packer_class.h +11 -0
  23. data/ext/msgpack/packer_ext_registry.c +35 -40
  24. data/ext/msgpack/packer_ext_registry.h +41 -38
  25. data/ext/msgpack/rbinit.c +1 -1
  26. data/ext/msgpack/rmem.c +3 -4
  27. data/ext/msgpack/sysdep.h +5 -2
  28. data/ext/msgpack/unpacker.c +126 -108
  29. data/ext/msgpack/unpacker.h +16 -13
  30. data/ext/msgpack/unpacker_class.c +86 -126
  31. data/ext/msgpack/unpacker_class.h +11 -0
  32. data/ext/msgpack/unpacker_ext_registry.c +40 -28
  33. data/ext/msgpack/unpacker_ext_registry.h +21 -18
  34. data/lib/msgpack/bigint.rb +69 -0
  35. data/lib/msgpack/buffer.rb +9 -0
  36. data/lib/msgpack/factory.rb +140 -10
  37. data/lib/msgpack/packer.rb +10 -1
  38. data/lib/msgpack/symbol.rb +21 -4
  39. data/lib/msgpack/time.rb +1 -1
  40. data/lib/msgpack/unpacker.rb +14 -1
  41. data/lib/msgpack/version.rb +1 -1
  42. data/lib/msgpack.rb +6 -7
  43. data/msgpack.gemspec +8 -5
  44. metadata +37 -82
  45. data/.gitignore +0 -23
  46. data/.rubocop.yml +0 -36
  47. data/.travis.yml +0 -39
  48. data/Gemfile +0 -9
  49. data/Rakefile +0 -71
  50. data/appveyor.yml +0 -18
  51. data/bench/pack.rb +0 -23
  52. data/bench/pack_log.rb +0 -33
  53. data/bench/pack_log_long.rb +0 -65
  54. data/bench/pack_symbols.rb +0 -28
  55. data/bench/run.sh +0 -14
  56. data/bench/run_long.sh +0 -35
  57. data/bench/run_symbols.sh +0 -26
  58. data/bench/unpack.rb +0 -21
  59. data/bench/unpack_log.rb +0 -34
  60. data/bench/unpack_log_long.rb +0 -67
  61. data/doclib/msgpack/buffer.rb +0 -193
  62. data/doclib/msgpack/core_ext.rb +0 -101
  63. data/doclib/msgpack/error.rb +0 -19
  64. data/doclib/msgpack/extension_value.rb +0 -9
  65. data/doclib/msgpack/factory.rb +0 -101
  66. data/doclib/msgpack/packer.rb +0 -208
  67. data/doclib/msgpack/time.rb +0 -22
  68. data/doclib/msgpack/timestamp.rb +0 -44
  69. data/doclib/msgpack/unpacker.rb +0 -183
  70. data/doclib/msgpack.rb +0 -87
  71. data/msgpack.org.md +0 -46
  72. data/spec/cases.json +0 -1
  73. data/spec/cases.msg +0 -0
  74. data/spec/cases_compact.msg +0 -0
  75. data/spec/cases_spec.rb +0 -39
  76. data/spec/cruby/buffer_io_spec.rb +0 -255
  77. data/spec/cruby/buffer_packer.rb +0 -29
  78. data/spec/cruby/buffer_spec.rb +0 -575
  79. data/spec/cruby/buffer_unpacker.rb +0 -19
  80. data/spec/cruby/unpacker_spec.rb +0 -70
  81. data/spec/ext_value_spec.rb +0 -99
  82. data/spec/exttypes.rb +0 -51
  83. data/spec/factory_spec.rb +0 -367
  84. data/spec/format_spec.rb +0 -301
  85. data/spec/jruby/benchmarks/shootout_bm.rb +0 -73
  86. data/spec/jruby/benchmarks/symbolize_keys_bm.rb +0 -25
  87. data/spec/jruby/unpacker_spec.rb +0 -186
  88. data/spec/msgpack_spec.rb +0 -214
  89. data/spec/pack_spec.rb +0 -61
  90. data/spec/packer_spec.rb +0 -557
  91. data/spec/random_compat.rb +0 -24
  92. data/spec/spec_helper.rb +0 -55
  93. data/spec/timestamp_spec.rb +0 -121
  94. data/spec/unpack_spec.rb +0 -57
  95. data/spec/unpacker_spec.rb +0 -819
@@ -21,6 +21,8 @@
21
21
  #include "compat.h"
22
22
  #include "ruby.h"
23
23
 
24
+ #define MSGPACK_EXT_RECURSIVE 0b0001
25
+
24
26
  struct msgpack_packer_ext_registry_t;
25
27
  typedef struct msgpack_packer_ext_registry_t msgpack_packer_ext_registry_t;
26
28
 
@@ -29,22 +31,21 @@ struct msgpack_packer_ext_registry_t {
29
31
  VALUE cache; // lookup cache for ext types inherited from a super class
30
32
  };
31
33
 
32
- void msgpack_packer_ext_registry_static_init();
33
-
34
- void msgpack_packer_ext_registry_static_destroy();
35
-
36
- void msgpack_packer_ext_registry_init(msgpack_packer_ext_registry_t* pkrg);
34
+ void msgpack_packer_ext_registry_init(VALUE owner, msgpack_packer_ext_registry_t* pkrg);
37
35
 
38
36
  static inline void msgpack_packer_ext_registry_destroy(msgpack_packer_ext_registry_t* pkrg)
39
37
  { }
40
38
 
41
39
  void msgpack_packer_ext_registry_mark(msgpack_packer_ext_registry_t* pkrg);
42
40
 
43
- void msgpack_packer_ext_registry_dup(msgpack_packer_ext_registry_t* src,
41
+ void msgpack_packer_ext_registry_borrow(VALUE owner, msgpack_packer_ext_registry_t* src,
44
42
  msgpack_packer_ext_registry_t* dst);
45
43
 
46
- VALUE msgpack_packer_ext_registry_put(msgpack_packer_ext_registry_t* pkrg,
47
- VALUE ext_module, int ext_type, VALUE proc, VALUE arg);
44
+ void msgpack_packer_ext_registry_dup(VALUE owner, msgpack_packer_ext_registry_t* src,
45
+ msgpack_packer_ext_registry_t* dst);
46
+
47
+ void msgpack_packer_ext_registry_put(VALUE owner, msgpack_packer_ext_registry_t* pkrg,
48
+ VALUE ext_module, int ext_type, int flags, VALUE proc);
48
49
 
49
50
  static int msgpack_packer_ext_find_superclass(VALUE key, VALUE value, VALUE arg)
50
51
  {
@@ -60,59 +61,60 @@ static int msgpack_packer_ext_find_superclass(VALUE key, VALUE value, VALUE arg)
60
61
  }
61
62
 
62
63
  static inline VALUE msgpack_packer_ext_registry_fetch(msgpack_packer_ext_registry_t* pkrg,
63
- VALUE lookup_class, int* ext_type_result)
64
+ VALUE lookup_class, int* ext_type_result, int* ext_flags_result)
64
65
  {
65
66
  // fetch lookup_class from hash, which is a hash to register classes
66
67
  VALUE type = rb_hash_lookup(pkrg->hash, lookup_class);
67
68
  if(type != Qnil) {
68
69
  *ext_type_result = FIX2INT(rb_ary_entry(type, 0));
70
+ *ext_flags_result = FIX2INT(rb_ary_entry(type, 2));
69
71
  return rb_ary_entry(type, 1);
70
72
  }
71
73
 
72
74
  // fetch lookup_class from cache, which stores results of searching ancestors from pkrg->hash
73
- VALUE type_inht = rb_hash_lookup(pkrg->cache, lookup_class);
74
- if(type_inht != Qnil) {
75
- *ext_type_result = FIX2INT(rb_ary_entry(type_inht, 0));
76
- return rb_ary_entry(type_inht, 1);
75
+ if (RTEST(pkrg->cache)) {
76
+ VALUE type_inht = rb_hash_lookup(pkrg->cache, lookup_class);
77
+ if(type_inht != Qnil) {
78
+ *ext_type_result = FIX2INT(rb_ary_entry(type_inht, 0));
79
+ *ext_flags_result = FIX2INT(rb_ary_entry(type_inht, 2));
80
+ return rb_ary_entry(type_inht, 1);
81
+ }
77
82
  }
78
83
 
79
84
  return Qnil;
80
85
  }
81
86
 
82
87
  static inline VALUE msgpack_packer_ext_registry_lookup(msgpack_packer_ext_registry_t* pkrg,
83
- VALUE instance, int* ext_type_result)
88
+ VALUE instance, int* ext_type_result, int* ext_flags_result)
84
89
  {
85
- VALUE lookup_class;
86
90
  VALUE type;
87
91
 
88
- /*
89
- * 1. check whether singleton_class of this instance is registered (or resolved in past) or not.
90
- *
91
- * Objects of type Integer (Fixnum, Bignum), Float, Symbol and frozen
92
- * String have no singleton class and raise a TypeError when trying to get
93
- * it. See implementation of #singleton_class in ruby's source code:
94
- * VALUE rb_singleton_class(VALUE obj);
95
- *
96
- * Since all but symbols are already filtered out when reaching this code
97
- * only symbols are checked here.
98
- */
99
- if (!SYMBOL_P(instance)) {
100
- lookup_class = rb_singleton_class(instance);
101
-
102
- type = msgpack_packer_ext_registry_fetch(pkrg, lookup_class, ext_type_result);
92
+ if (pkrg->hash == Qnil) { // No extensions registered
93
+ return Qnil;
94
+ }
103
95
 
104
- if(type != Qnil) {
105
- return type;
106
- }
96
+ /*
97
+ * 1. check whether singleton_class or class of this instance is registered (or resolved in past) or not.
98
+ *
99
+ * Objects of type Integer (Fixnum, Bignum), Float, Symbol and frozen
100
+ * `rb_class_of` returns the singleton_class if the object has one, or the "real class" otherwise.
101
+ */
102
+ VALUE lookup_class = rb_class_of(instance);
103
+ type = msgpack_packer_ext_registry_fetch(pkrg, lookup_class, ext_type_result, ext_flags_result);
104
+ if(type != Qnil) {
105
+ return type;
107
106
  }
108
107
 
109
108
  /*
110
- * 2. check the class of instance is registered (or resolved in past) or not.
109
+ * 2. If the object had a singleton_class check if the real class of instance is registered
110
+ * (or resolved in past) or not.
111
111
  */
112
- type = msgpack_packer_ext_registry_fetch(pkrg, rb_obj_class(instance), ext_type_result);
113
-
114
- if(type != Qnil) {
115
- return type;
112
+ VALUE real_class = rb_obj_class(instance);
113
+ if(lookup_class != real_class) {
114
+ type = msgpack_packer_ext_registry_fetch(pkrg, real_class, ext_type_result, ext_flags_result);
115
+ if(type != Qnil) {
116
+ return type;
117
+ }
116
118
  }
117
119
 
118
120
  /*
@@ -128,6 +130,7 @@ static inline VALUE msgpack_packer_ext_registry_lookup(msgpack_packer_ext_regist
128
130
  VALUE superclass_type = rb_hash_lookup(pkrg->hash, superclass);
129
131
  rb_hash_aset(pkrg->cache, lookup_class, superclass_type);
130
132
  *ext_type_result = FIX2INT(rb_ary_entry(superclass_type, 0));
133
+ *ext_flags_result = FIX2INT(rb_ary_entry(superclass_type, 2));
131
134
  return rb_ary_entry(superclass_type, 1);
132
135
  }
133
136
 
data/ext/msgpack/rbinit.c CHANGED
@@ -22,7 +22,7 @@
22
22
  #include "factory_class.h"
23
23
  #include "extension_value_class.h"
24
24
 
25
- void Init_msgpack(void)
25
+ RUBY_FUNC_EXPORTED void Init_msgpack(void)
26
26
  {
27
27
  VALUE mMessagePack = rb_define_module("MessagePack");
28
28
 
data/ext/msgpack/rmem.c CHANGED
@@ -65,11 +65,10 @@ void* _msgpack_rmem_alloc2(msgpack_rmem_t* pm)
65
65
  /* allocate new chunk */
66
66
  c = pm->array_last++;
67
67
 
68
- /* move to head */
69
- msgpack_rmem_chunk_t tmp = pm->head;
70
- pm->head = *c;
71
- *c = tmp;
68
+ /* move head to array */
69
+ *c = pm->head;
72
70
 
71
+ pm->head.pages = NULL; /* make sure we don't point to another chunk's pages in case xmalloc triggers GC */
73
72
  pm->head.mask = 0xffffffff & (~1); /* "& (~1)" means first chunk is already allocated */
74
73
  pm->head.pages = xmalloc(MSGPACK_RMEM_PAGE_SIZE * 32);
75
74
 
data/ext/msgpack/sysdep.h CHANGED
@@ -35,8 +35,11 @@
35
35
  # define _msgpack_be16(x) ((uint16_t)_byteswap_ushort((unsigned short)x))
36
36
  # else
37
37
  # define _msgpack_be16(x) ( \
38
- ((((uint16_t)x) << 8) ) | \
39
- ((((uint16_t)x) >> 8) ) )
38
+ ( \
39
+ ((((uint16_t)x) << 8) ) | \
40
+ ((((uint16_t)x) >> 8) ) \
41
+ ) \
42
+ & 0x0000FFFF )
40
43
  # endif
41
44
  #else
42
45
  # define _msgpack_be16(x) ntohs(x)
@@ -19,43 +19,48 @@
19
19
  #include "unpacker.h"
20
20
  #include "rmem.h"
21
21
  #include "extension_value_class.h"
22
+ #include <assert.h>
22
23
 
23
- #if !defined(DISABLE_RMEM) && !defined(DISABLE_UNPACKER_STACK_RMEM) && \
24
- MSGPACK_UNPACKER_STACK_CAPACITY * MSGPACK_UNPACKER_STACK_SIZE <= MSGPACK_RMEM_PAGE_SIZE
25
- #define UNPACKER_STACK_RMEM
24
+ #if !defined(HAVE_RB_PROC_CALL_WITH_BLOCK)
25
+ #define rb_proc_call_with_block(recv, argc, argv, block) rb_funcallv(recv, rb_intern("call"), argc, argv)
26
26
  #endif
27
27
 
28
28
  static int RAW_TYPE_STRING = 256;
29
29
  static int RAW_TYPE_BINARY = 257;
30
30
 
31
- static ID s_call;
32
-
33
- #ifdef UNPACKER_STACK_RMEM
34
31
  static msgpack_rmem_t s_stack_rmem;
35
- #endif
36
32
 
37
- void msgpack_unpacker_static_init()
33
+ #if !defined(HAVE_RB_HASH_NEW_CAPA)
34
+ static inline VALUE rb_hash_new_capa(long capa)
38
35
  {
39
- #ifdef UNPACKER_STACK_RMEM
40
- msgpack_rmem_init(&s_stack_rmem);
36
+ return rb_hash_new();
37
+ }
41
38
  #endif
42
39
 
43
- s_call = rb_intern("call");
40
+ void msgpack_unpacker_static_init(void)
41
+ {
42
+ assert(sizeof(msgpack_unpacker_stack_entry_t) * MSGPACK_UNPACKER_STACK_CAPACITY <= MSGPACK_RMEM_PAGE_SIZE);
43
+
44
+ msgpack_rmem_init(&s_stack_rmem);
44
45
  }
45
46
 
46
- void msgpack_unpacker_static_destroy()
47
+ void msgpack_unpacker_static_destroy(void)
47
48
  {
48
- #ifdef UNPACKER_STACK_RMEM
49
49
  msgpack_rmem_destroy(&s_stack_rmem);
50
- #endif
51
50
  }
52
51
 
53
52
  #define HEAD_BYTE_REQUIRED 0xc1
54
53
 
54
+ static inline msgpack_unpacker_stack_t* _msgpack_unpacker_new_stack(void) {
55
+ msgpack_unpacker_stack_t *stack = ZALLOC(msgpack_unpacker_stack_t);
56
+ stack->capacity = MSGPACK_UNPACKER_STACK_CAPACITY;
57
+ stack->data = msgpack_rmem_alloc(&s_stack_rmem);
58
+ /*memset(uk->stack, 0, MSGPACK_UNPACKER_STACK_CAPACITY);*/
59
+ return stack;
60
+ }
61
+
55
62
  void _msgpack_unpacker_init(msgpack_unpacker_t* uk)
56
63
  {
57
- memset(uk, 0, sizeof(msgpack_unpacker_t));
58
-
59
64
  msgpack_buffer_init(UNPACKER_BUFFER_(uk));
60
65
 
61
66
  uk->head_byte = HEAD_BYTE_REQUIRED;
@@ -63,42 +68,44 @@ void _msgpack_unpacker_init(msgpack_unpacker_t* uk)
63
68
  uk->last_object = Qnil;
64
69
  uk->reading_raw = Qnil;
65
70
 
66
- #ifdef UNPACKER_STACK_RMEM
67
- uk->stack = msgpack_rmem_alloc(&s_stack_rmem);
68
- /*memset(uk->stack, 0, MSGPACK_UNPACKER_STACK_CAPACITY);*/
69
- #else
70
- /*uk->stack = calloc(MSGPACK_UNPACKER_STACK_CAPACITY, sizeof(msgpack_unpacker_stack_t));*/
71
- uk->stack = xmalloc(MSGPACK_UNPACKER_STACK_CAPACITY * sizeof(msgpack_unpacker_stack_t));
72
- #endif
73
- uk->stack_capacity = MSGPACK_UNPACKER_STACK_CAPACITY;
71
+ uk->stack = _msgpack_unpacker_new_stack();
72
+ }
73
+
74
+ static inline void _msgpack_unpacker_free_stack(msgpack_unpacker_stack_t* stack) {
75
+ if (!msgpack_rmem_free(&s_stack_rmem, stack->data)) {
76
+ rb_bug("Failed to free an rmem pointer, memory leak?");
77
+ }
78
+ xfree(stack);
74
79
  }
75
80
 
76
81
  void _msgpack_unpacker_destroy(msgpack_unpacker_t* uk)
77
82
  {
78
- #ifdef UNPACKER_STACK_RMEM
79
- msgpack_rmem_free(&s_stack_rmem, uk->stack);
80
- #else
81
- xfree(uk->stack);
82
- #endif
83
-
83
+ _msgpack_unpacker_free_stack(uk->stack);
84
84
  msgpack_buffer_destroy(UNPACKER_BUFFER_(uk));
85
85
  }
86
86
 
87
+ void msgpack_unpacker_mark_stack(msgpack_unpacker_stack_t* stack)
88
+ {
89
+ while (stack) {
90
+ msgpack_unpacker_stack_entry_t* s = stack->data;
91
+ msgpack_unpacker_stack_entry_t* send = stack->data + stack->depth;
92
+ for(; s < send; s++) {
93
+ rb_gc_mark(s->object);
94
+ rb_gc_mark(s->key);
95
+ }
96
+ stack = stack->parent;
97
+ }
98
+ }
99
+
87
100
  void msgpack_unpacker_mark(msgpack_unpacker_t* uk)
88
101
  {
89
102
  rb_gc_mark(uk->last_object);
90
103
  rb_gc_mark(uk->reading_raw);
91
-
92
- msgpack_unpacker_stack_t* s = uk->stack;
93
- msgpack_unpacker_stack_t* send = uk->stack + uk->stack_depth;
94
- for(; s < send; s++) {
95
- rb_gc_mark(s->object);
96
- rb_gc_mark(s->key);
97
- }
98
-
104
+ msgpack_unpacker_mark_stack(uk->stack);
99
105
  /* See MessagePack_Buffer_wrap */
100
106
  /* msgpack_buffer_mark(UNPACKER_BUFFER_(uk)); */
101
107
  rb_gc_mark(uk->buffer_ref);
108
+ rb_gc_mark(uk->self);
102
109
  }
103
110
 
104
111
  void _msgpack_unpacker_reset(msgpack_unpacker_t* uk)
@@ -107,9 +114,8 @@ void _msgpack_unpacker_reset(msgpack_unpacker_t* uk)
107
114
 
108
115
  uk->head_byte = HEAD_BYTE_REQUIRED;
109
116
 
110
- /*memset(uk->stack, 0, sizeof(msgpack_unpacker_t) * uk->stack_depth);*/
111
- uk->stack_depth = 0;
112
-
117
+ /*memset(uk->stack, 0, sizeof(msgpack_unpacker_t) * uk->stack->depth);*/
118
+ uk->stack->depth = 0;
113
119
  uk->last_object = Qnil;
114
120
  uk->reading_raw = Qnil;
115
121
  uk->reading_raw_remaining = 0;
@@ -151,16 +157,34 @@ static inline int object_complete(msgpack_unpacker_t* uk, VALUE object)
151
157
  return PRIMITIVE_OBJECT_COMPLETE;
152
158
  }
153
159
 
160
+ static inline int object_complete_symbol(msgpack_unpacker_t* uk, VALUE object)
161
+ {
162
+ uk->last_object = object;
163
+ reset_head_byte(uk);
164
+ return PRIMITIVE_OBJECT_COMPLETE;
165
+ }
166
+
154
167
  static inline int object_complete_ext(msgpack_unpacker_t* uk, int ext_type, VALUE str)
155
168
  {
156
- VALUE proc = msgpack_unpacker_ext_registry_lookup(&uk->ext_registry, ext_type);
169
+ if (uk->optimized_symbol_ext_type && ext_type == uk->symbol_ext_type) {
170
+ if (RB_UNLIKELY(NIL_P(str))) { // empty extension is returned as Qnil
171
+ return object_complete_symbol(uk, ID2SYM(rb_intern3("", 0, rb_utf8_encoding())));
172
+ }
173
+ return object_complete_symbol(uk, rb_str_intern(str));
174
+ }
175
+
176
+ int ext_flags;
177
+ VALUE proc = msgpack_unpacker_ext_registry_lookup(uk->ext_registry, ext_type, &ext_flags);
178
+
157
179
  if(proc != Qnil) {
158
- VALUE obj = rb_funcall(proc, s_call, 1, str);
180
+ VALUE obj;
181
+ VALUE arg = (str == Qnil ? rb_str_buf_new(0) : str);
182
+ obj = rb_proc_call_with_block(proc, 1, &arg, Qnil);
159
183
  return object_complete(uk, obj);
160
184
  }
161
185
 
162
186
  if(uk->allow_unknown_ext) {
163
- VALUE obj = MessagePack_ExtensionValue_new(ext_type, str);
187
+ VALUE obj = MessagePack_ExtensionValue_new(ext_type, str == Qnil ? rb_str_buf_new(0) : str);
164
188
  return object_complete(uk, obj);
165
189
  }
166
190
 
@@ -168,37 +192,37 @@ static inline int object_complete_ext(msgpack_unpacker_t* uk, int ext_type, VALU
168
192
  }
169
193
 
170
194
  /* stack funcs */
171
- static inline msgpack_unpacker_stack_t* _msgpack_unpacker_stack_top(msgpack_unpacker_t* uk)
195
+ static inline msgpack_unpacker_stack_entry_t* _msgpack_unpacker_stack_entry_top(msgpack_unpacker_t* uk)
172
196
  {
173
- return &uk->stack[uk->stack_depth-1];
197
+ return &uk->stack->data[uk->stack->depth-1];
174
198
  }
175
199
 
176
200
  static inline int _msgpack_unpacker_stack_push(msgpack_unpacker_t* uk, enum stack_type_t type, size_t count, VALUE object)
177
201
  {
178
202
  reset_head_byte(uk);
179
203
 
180
- if(uk->stack_capacity - uk->stack_depth <= 0) {
204
+ if(uk->stack->capacity - uk->stack->depth <= 0) {
181
205
  return PRIMITIVE_STACK_TOO_DEEP;
182
206
  }
183
207
 
184
- msgpack_unpacker_stack_t* next = &uk->stack[uk->stack_depth];
208
+ msgpack_unpacker_stack_entry_t* next = &uk->stack->data[uk->stack->depth];
185
209
  next->count = count;
186
210
  next->type = type;
187
211
  next->object = object;
188
212
  next->key = Qnil;
189
213
 
190
- uk->stack_depth++;
214
+ uk->stack->depth++;
191
215
  return PRIMITIVE_CONTAINER_START;
192
216
  }
193
217
 
194
218
  static inline VALUE msgpack_unpacker_stack_pop(msgpack_unpacker_t* uk)
195
219
  {
196
- return --uk->stack_depth;
220
+ return --uk->stack->depth;
197
221
  }
198
222
 
199
223
  static inline bool msgpack_unpacker_stack_is_empty(msgpack_unpacker_t* uk)
200
224
  {
201
- return uk->stack_depth == 0;
225
+ return uk->stack->depth == 0;
202
226
  }
203
227
 
204
228
  #ifdef USE_CASE_RANGE
@@ -226,8 +250,8 @@ static inline bool msgpack_unpacker_stack_is_empty(msgpack_unpacker_t* uk)
226
250
 
227
251
  static inline bool is_reading_map_key(msgpack_unpacker_t* uk)
228
252
  {
229
- if(uk->stack_depth > 0) {
230
- msgpack_unpacker_stack_t* top = _msgpack_unpacker_stack_top(uk);
253
+ if(uk->stack->depth > 0) {
254
+ msgpack_unpacker_stack_entry_t* top = _msgpack_unpacker_stack_entry_top(uk);
231
255
  if(top->type == STACK_TYPE_MAP_KEY) {
232
256
  return true;
233
257
  }
@@ -270,25 +294,50 @@ static inline int read_raw_body_begin(msgpack_unpacker_t* uk, int raw_type)
270
294
  {
271
295
  /* assuming uk->reading_raw == Qnil */
272
296
 
297
+ int ext_flags;
298
+ VALUE proc;
299
+
300
+ if(!(raw_type == RAW_TYPE_STRING || raw_type == RAW_TYPE_BINARY)) {
301
+ proc = msgpack_unpacker_ext_registry_lookup(uk->ext_registry, raw_type, &ext_flags);
302
+ if(proc != Qnil && ext_flags & MSGPACK_EXT_RECURSIVE) {
303
+ VALUE obj;
304
+ uk->last_object = Qnil;
305
+ reset_head_byte(uk);
306
+ uk->reading_raw_remaining = 0;
307
+
308
+ msgpack_unpacker_stack_t* child_stack = _msgpack_unpacker_new_stack();
309
+ child_stack->parent = uk->stack;
310
+ uk->stack = child_stack;
311
+
312
+ obj = rb_proc_call_with_block(proc, 1, &uk->self, Qnil);
313
+
314
+ uk->stack = child_stack->parent;
315
+ _msgpack_unpacker_free_stack(child_stack);
316
+
317
+ return object_complete(uk, obj);
318
+ }
319
+ }
320
+
273
321
  /* try optimized read */
274
322
  size_t length = uk->reading_raw_remaining;
275
323
  if(length <= msgpack_buffer_top_readable_size(UNPACKER_BUFFER_(uk))) {
276
- /* don't use zerocopy for hash keys but get a frozen string directly
277
- * because rb_hash_aset freezes keys and it causes copying */
278
- bool will_freeze = uk->freeze || is_reading_map_key(uk);
279
- VALUE string = msgpack_buffer_read_top_as_string(UNPACKER_BUFFER_(uk), length, will_freeze, raw_type == RAW_TYPE_STRING);
280
324
  int ret;
281
- if(raw_type == RAW_TYPE_STRING || raw_type == RAW_TYPE_BINARY) {
282
- ret = object_complete(uk, string);
325
+ if ((uk->optimized_symbol_ext_type && uk->symbol_ext_type == raw_type) || (uk->symbolize_keys && is_reading_map_key(uk))) {
326
+ VALUE symbol = msgpack_buffer_read_top_as_symbol(UNPACKER_BUFFER_(uk), length, raw_type != RAW_TYPE_BINARY);
327
+ ret = object_complete_symbol(uk, symbol);
283
328
  } else {
284
- ret = object_complete_ext(uk, raw_type, string);
285
- }
286
-
287
- # if !HASH_ASET_DEDUPE
288
- if(will_freeze) {
289
- rb_obj_freeze(string);
329
+ bool will_freeze = uk->freeze;
330
+ if(raw_type == RAW_TYPE_STRING || raw_type == RAW_TYPE_BINARY) {
331
+ /* don't use zerocopy for hash keys but get a frozen string directly
332
+ * because rb_hash_aset freezes keys and it causes copying */
333
+ will_freeze = will_freeze || is_reading_map_key(uk);
334
+ VALUE string = msgpack_buffer_read_top_as_string(UNPACKER_BUFFER_(uk), length, will_freeze, raw_type == RAW_TYPE_STRING);
335
+ ret = object_complete(uk, string);
336
+ } else {
337
+ VALUE string = msgpack_buffer_read_top_as_string(UNPACKER_BUFFER_(uk), length, false, false);
338
+ ret = object_complete_ext(uk, raw_type, string);
339
+ }
290
340
  }
291
- # endif
292
341
  uk->reading_raw_remaining = 0;
293
342
  return ret;
294
343
  }
@@ -317,9 +366,6 @@ static int read_primitive(msgpack_unpacker_t* uk)
317
366
 
318
367
  SWITCH_RANGE(b, 0xa0, 0xbf) // FixRaw / fixstr
319
368
  int count = b & 0x1f;
320
- if(count == 0) {
321
- return object_complete(uk, rb_utf8_str_new_static("", 0));
322
- }
323
369
  /* read_raw_body_begin sets uk->reading_raw */
324
370
  uk->reading_raw_remaining = count;
325
371
  return read_raw_body_begin(uk, RAW_TYPE_STRING);
@@ -336,7 +382,7 @@ static int read_primitive(msgpack_unpacker_t* uk)
336
382
  if(count == 0) {
337
383
  return object_complete(uk, rb_hash_new());
338
384
  }
339
- return _msgpack_unpacker_stack_push(uk, STACK_TYPE_MAP_KEY, count*2, rb_hash_new());
385
+ return _msgpack_unpacker_stack_push(uk, STACK_TYPE_MAP_KEY, count*2, rb_hash_new_capa(count));
340
386
 
341
387
  SWITCH_RANGE(b, 0xc0, 0xdf) // Variable
342
388
  switch(b) {
@@ -357,7 +403,7 @@ static int read_primitive(msgpack_unpacker_t* uk)
357
403
  uint8_t length = cb->u8;
358
404
  int ext_type = (signed char) cb->buffer[1];
359
405
  if(length == 0) {
360
- return object_complete_ext(uk, ext_type, rb_str_buf_new(0));
406
+ return object_complete_ext(uk, ext_type, Qnil);
361
407
  }
362
408
  uk->reading_raw_remaining = length;
363
409
  return read_raw_body_begin(uk, ext_type);
@@ -369,7 +415,7 @@ static int read_primitive(msgpack_unpacker_t* uk)
369
415
  uint16_t length = _msgpack_be16(cb->u16);
370
416
  int ext_type = (signed char) cb->buffer[2];
371
417
  if(length == 0) {
372
- return object_complete_ext(uk, ext_type, rb_str_buf_new(0));
418
+ return object_complete_ext(uk, ext_type, Qnil);
373
419
  }
374
420
  uk->reading_raw_remaining = length;
375
421
  return read_raw_body_begin(uk, ext_type);
@@ -381,7 +427,7 @@ static int read_primitive(msgpack_unpacker_t* uk)
381
427
  uint32_t length = _msgpack_be32(cb->u32);
382
428
  int ext_type = (signed char) cb->buffer[4];
383
429
  if(length == 0) {
384
- return object_complete_ext(uk, ext_type, rb_str_buf_new(0));
430
+ return object_complete_ext(uk, ext_type, Qnil);
385
431
  }
386
432
  uk->reading_raw_remaining = length;
387
433
  return read_raw_body_begin(uk, ext_type);
@@ -419,7 +465,7 @@ static int read_primitive(msgpack_unpacker_t* uk)
419
465
  {
420
466
  READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 4);
421
467
  uint32_t u32 = _msgpack_be32(cb->u32);
422
- return object_complete(uk, ULONG2NUM((unsigned long)u32));
468
+ return object_complete(uk, ULONG2NUM(u32)); // long at least 32 bits
423
469
  }
424
470
 
425
471
  case 0xcf: // unsigned int 64
@@ -447,7 +493,7 @@ static int read_primitive(msgpack_unpacker_t* uk)
447
493
  {
448
494
  READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 4);
449
495
  int32_t i32 = _msgpack_be32(cb->i32);
450
- return object_complete(uk, LONG2NUM((long)i32));
496
+ return object_complete(uk, LONG2NUM(i32)); // long at least 32 bits
451
497
  }
452
498
 
453
499
  case 0xd3: // signed int 64
@@ -502,9 +548,6 @@ static int read_primitive(msgpack_unpacker_t* uk)
502
548
  {
503
549
  READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 1);
504
550
  uint8_t count = cb->u8;
505
- if(count == 0) {
506
- return object_complete(uk, rb_utf8_str_new_static("", 0));
507
- }
508
551
  /* read_raw_body_begin sets uk->reading_raw */
509
552
  uk->reading_raw_remaining = count;
510
553
  return read_raw_body_begin(uk, RAW_TYPE_STRING);
@@ -514,9 +557,6 @@ static int read_primitive(msgpack_unpacker_t* uk)
514
557
  {
515
558
  READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 2);
516
559
  uint16_t count = _msgpack_be16(cb->u16);
517
- if(count == 0) {
518
- return object_complete(uk, rb_utf8_str_new_static("", 0));
519
- }
520
560
  /* read_raw_body_begin sets uk->reading_raw */
521
561
  uk->reading_raw_remaining = count;
522
562
  return read_raw_body_begin(uk, RAW_TYPE_STRING);
@@ -526,9 +566,6 @@ static int read_primitive(msgpack_unpacker_t* uk)
526
566
  {
527
567
  READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 4);
528
568
  uint32_t count = _msgpack_be32(cb->u32);
529
- if(count == 0) {
530
- return object_complete(uk, rb_utf8_str_new_static("", 0));
531
- }
532
569
  /* read_raw_body_begin sets uk->reading_raw */
533
570
  uk->reading_raw_remaining = count;
534
571
  return read_raw_body_begin(uk, RAW_TYPE_STRING);
@@ -538,9 +575,6 @@ static int read_primitive(msgpack_unpacker_t* uk)
538
575
  {
539
576
  READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 1);
540
577
  uint8_t count = cb->u8;
541
- if(count == 0) {
542
- return object_complete(uk, rb_str_new_static("", 0));
543
- }
544
578
  /* read_raw_body_begin sets uk->reading_raw */
545
579
  uk->reading_raw_remaining = count;
546
580
  return read_raw_body_begin(uk, RAW_TYPE_BINARY);
@@ -550,9 +584,6 @@ static int read_primitive(msgpack_unpacker_t* uk)
550
584
  {
551
585
  READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 2);
552
586
  uint16_t count = _msgpack_be16(cb->u16);
553
- if(count == 0) {
554
- return object_complete(uk, rb_str_new_static("", 0));
555
- }
556
587
  /* read_raw_body_begin sets uk->reading_raw */
557
588
  uk->reading_raw_remaining = count;
558
589
  return read_raw_body_begin(uk, RAW_TYPE_BINARY);
@@ -562,9 +593,6 @@ static int read_primitive(msgpack_unpacker_t* uk)
562
593
  {
563
594
  READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 4);
564
595
  uint32_t count = _msgpack_be32(cb->u32);
565
- if(count == 0) {
566
- return object_complete(uk, rb_str_new_static("", 0));
567
- }
568
596
  /* read_raw_body_begin sets uk->reading_raw */
569
597
  uk->reading_raw_remaining = count;
570
598
  return read_raw_body_begin(uk, RAW_TYPE_BINARY);
@@ -597,7 +625,7 @@ static int read_primitive(msgpack_unpacker_t* uk)
597
625
  if(count == 0) {
598
626
  return object_complete(uk, rb_hash_new());
599
627
  }
600
- return _msgpack_unpacker_stack_push(uk, STACK_TYPE_MAP_KEY, count*2, rb_hash_new());
628
+ return _msgpack_unpacker_stack_push(uk, STACK_TYPE_MAP_KEY, count*2, rb_hash_new_capa(count));
601
629
  }
602
630
 
603
631
  case 0xdf: // map 32
@@ -607,7 +635,7 @@ static int read_primitive(msgpack_unpacker_t* uk)
607
635
  if(count == 0) {
608
636
  return object_complete(uk, rb_hash_new());
609
637
  }
610
- return _msgpack_unpacker_stack_push(uk, STACK_TYPE_MAP_KEY, count*2, rb_hash_new());
638
+ return _msgpack_unpacker_stack_push(uk, STACK_TYPE_MAP_KEY, count*2, rb_hash_new_capa(count));
611
639
  }
612
640
 
613
641
  default:
@@ -694,7 +722,7 @@ int msgpack_unpacker_read(msgpack_unpacker_t* uk, size_t target_stack_depth)
694
722
 
695
723
  container_completed:
696
724
  {
697
- msgpack_unpacker_stack_t* top = _msgpack_unpacker_stack_top(uk);
725
+ msgpack_unpacker_stack_entry_t* top = _msgpack_unpacker_stack_entry_top(uk);
698
726
  switch(top->type) {
699
727
  case STACK_TYPE_ARRAY:
700
728
  rb_ary_push(top->object, uk->last_object);
@@ -705,18 +733,8 @@ int msgpack_unpacker_read(msgpack_unpacker_t* uk, size_t target_stack_depth)
705
733
  break;
706
734
  case STACK_TYPE_MAP_VALUE:
707
735
  if(uk->symbolize_keys && rb_type(top->key) == T_STRING) {
708
- /* here uses rb_intern_str instead of rb_intern so that Ruby VM can GC unused symbols */
709
- #ifdef HAVE_RB_STR_INTERN
710
- /* rb_str_intern is added since MRI 2.2.0 */
736
+ /* here uses rb_str_intern instead of rb_intern so that Ruby VM can GC unused symbols */
711
737
  rb_hash_aset(top->object, rb_str_intern(top->key), uk->last_object);
712
- #else
713
- #ifndef HAVE_RB_INTERN_STR
714
- /* MRI 1.8 doesn't have rb_intern_str or rb_intern2 */
715
- rb_hash_aset(top->object, ID2SYM(rb_intern(RSTRING_PTR(top->key))), uk->last_object);
716
- #else
717
- rb_hash_aset(top->object, ID2SYM(rb_intern_str(top->key)), uk->last_object);
718
- #endif
719
- #endif
720
738
  } else {
721
739
  rb_hash_aset(top->object, top->key, uk->last_object);
722
740
  }
@@ -754,7 +772,7 @@ int msgpack_unpacker_skip(msgpack_unpacker_t* uk, size_t target_stack_depth)
754
772
 
755
773
  container_completed:
756
774
  {
757
- msgpack_unpacker_stack_t* top = _msgpack_unpacker_stack_top(uk);
775
+ msgpack_unpacker_stack_entry_t* top = _msgpack_unpacker_stack_entry_top(uk);
758
776
 
759
777
  /* this section optimized out */
760
778
  // TODO object_complete still creates objects which should be optimized out