msgpack 1.4.2 → 1.7.2

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