msgpack 1.3.3 → 1.6.0

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 (67) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yaml +57 -0
  3. data/.rubocop.yml +2 -2
  4. data/ChangeLog +74 -0
  5. data/Gemfile +1 -1
  6. data/README.md +266 -0
  7. data/Rakefile +1 -9
  8. data/bench/bench.rb +78 -0
  9. data/bin/console +8 -0
  10. data/doclib/msgpack/factory.rb +47 -3
  11. data/doclib/msgpack/packer.rb +5 -4
  12. data/doclib/msgpack/unpacker.rb +2 -2
  13. data/ext/java/org/msgpack/jruby/Buffer.java +23 -16
  14. data/ext/java/org/msgpack/jruby/Decoder.java +46 -23
  15. data/ext/java/org/msgpack/jruby/Encoder.java +68 -30
  16. data/ext/java/org/msgpack/jruby/ExtensionRegistry.java +37 -49
  17. data/ext/java/org/msgpack/jruby/ExtensionValue.java +5 -8
  18. data/ext/java/org/msgpack/jruby/Factory.java +47 -7
  19. data/ext/java/org/msgpack/jruby/Packer.java +29 -17
  20. data/ext/java/org/msgpack/jruby/Unpacker.java +72 -37
  21. data/ext/msgpack/buffer.c +42 -68
  22. data/ext/msgpack/buffer.h +59 -14
  23. data/ext/msgpack/buffer_class.c +90 -52
  24. data/ext/msgpack/compat.h +1 -111
  25. data/ext/msgpack/extconf.rb +45 -19
  26. data/ext/msgpack/factory_class.c +133 -43
  27. data/ext/msgpack/packer.c +60 -36
  28. data/ext/msgpack/packer.h +27 -25
  29. data/ext/msgpack/packer_class.c +84 -77
  30. data/ext/msgpack/packer_class.h +11 -0
  31. data/ext/msgpack/packer_ext_registry.c +24 -32
  32. data/ext/msgpack/packer_ext_registry.h +40 -33
  33. data/ext/msgpack/sysdep.h +5 -2
  34. data/ext/msgpack/unpacker.c +132 -115
  35. data/ext/msgpack/unpacker.h +23 -10
  36. data/ext/msgpack/unpacker_class.c +83 -78
  37. data/ext/msgpack/unpacker_class.h +11 -0
  38. data/ext/msgpack/unpacker_ext_registry.c +42 -18
  39. data/ext/msgpack/unpacker_ext_registry.h +23 -16
  40. data/lib/msgpack/bigint.rb +69 -0
  41. data/lib/msgpack/factory.rb +103 -0
  42. data/lib/msgpack/symbol.rb +21 -4
  43. data/lib/msgpack/time.rb +1 -1
  44. data/lib/msgpack/version.rb +4 -8
  45. data/lib/msgpack.rb +6 -12
  46. data/msgpack.gemspec +4 -6
  47. data/spec/bigint_spec.rb +26 -0
  48. data/spec/cruby/buffer_spec.rb +17 -0
  49. data/spec/factory_spec.rb +351 -12
  50. data/spec/msgpack_spec.rb +1 -1
  51. data/spec/packer_spec.rb +18 -0
  52. data/spec/spec_helper.rb +37 -3
  53. data/spec/timestamp_spec.rb +38 -0
  54. data/spec/unpacker_spec.rb +157 -4
  55. metadata +31 -61
  56. data/.travis.yml +0 -43
  57. data/README.rdoc +0 -225
  58. data/bench/pack.rb +0 -23
  59. data/bench/pack_log.rb +0 -33
  60. data/bench/pack_log_long.rb +0 -65
  61. data/bench/pack_symbols.rb +0 -28
  62. data/bench/run.sh +0 -14
  63. data/bench/run_long.sh +0 -35
  64. data/bench/run_symbols.sh +0 -26
  65. data/bench/unpack.rb +0 -21
  66. data/bench/unpack_log.rb +0 -34
  67. data/bench/unpack_log_long.rb +0 -67
@@ -20,7 +20,7 @@
20
20
  #include "rmem.h"
21
21
  #include "extension_value_class.h"
22
22
 
23
- #if !defined(DISABLE_RMEM) && !defined(DISABLE_UNPACKER_STACK_RMEM) && \
23
+ #if !defined(DISABLE_UNPACKER_STACK_RMEM) && \
24
24
  MSGPACK_UNPACKER_STACK_CAPACITY * MSGPACK_UNPACKER_STACK_SIZE <= MSGPACK_RMEM_PAGE_SIZE
25
25
  #define UNPACKER_STACK_RMEM
26
26
  #endif
@@ -34,7 +34,14 @@ static ID s_call;
34
34
  static msgpack_rmem_t s_stack_rmem;
35
35
  #endif
36
36
 
37
- void msgpack_unpacker_static_init()
37
+ #if !defined(HAVE_RB_HASH_NEW_CAPA)
38
+ static inline VALUE rb_hash_new_capa(long capa)
39
+ {
40
+ return rb_hash_new();
41
+ }
42
+ #endif
43
+
44
+ void msgpack_unpacker_static_init(void)
38
45
  {
39
46
  #ifdef UNPACKER_STACK_RMEM
40
47
  msgpack_rmem_init(&s_stack_rmem);
@@ -43,7 +50,7 @@ void msgpack_unpacker_static_init()
43
50
  s_call = rb_intern("call");
44
51
  }
45
52
 
46
- void msgpack_unpacker_static_destroy()
53
+ void msgpack_unpacker_static_destroy(void)
47
54
  {
48
55
  #ifdef UNPACKER_STACK_RMEM
49
56
  msgpack_rmem_destroy(&s_stack_rmem);
@@ -52,10 +59,21 @@ void msgpack_unpacker_static_destroy()
52
59
 
53
60
  #define HEAD_BYTE_REQUIRED 0xc1
54
61
 
62
+ static inline msgpack_unpacker_stack_t* _msgpack_unpacker_new_stack(void) {
63
+ msgpack_unpacker_stack_t *stack = ZALLOC(msgpack_unpacker_stack_t);
64
+ stack->capacity = MSGPACK_UNPACKER_STACK_CAPACITY;
65
+ #ifdef UNPACKER_STACK_RMEM
66
+ stack->data = msgpack_rmem_alloc(&s_stack_rmem);
67
+ /*memset(uk->stack, 0, MSGPACK_UNPACKER_STACK_CAPACITY);*/
68
+ #else
69
+ /*uk->stack = calloc(MSGPACK_UNPACKER_STACK_CAPACITY, sizeof(msgpack_unpacker_stack_entry_t));*/
70
+ stack->data = xmalloc(MSGPACK_UNPACKER_STACK_CAPACITY * sizeof(msgpack_unpacker_stack_entry_t));
71
+ #endif
72
+ return stack;
73
+ }
74
+
55
75
  void _msgpack_unpacker_init(msgpack_unpacker_t* uk)
56
76
  {
57
- memset(uk, 0, sizeof(msgpack_unpacker_t));
58
-
59
77
  msgpack_buffer_init(UNPACKER_BUFFER_(uk));
60
78
 
61
79
  uk->head_byte = HEAD_BYTE_REQUIRED;
@@ -63,39 +81,42 @@ void _msgpack_unpacker_init(msgpack_unpacker_t* uk)
63
81
  uk->last_object = Qnil;
64
82
  uk->reading_raw = Qnil;
65
83
 
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;
84
+ uk->stack = _msgpack_unpacker_new_stack();
85
+ }
86
+
87
+ static inline void _msgpack_unpacker_free_stack(msgpack_unpacker_stack_t* stack) {
88
+ #ifdef UNPACKER_STACK_RMEM
89
+ msgpack_rmem_free(&s_stack_rmem, stack->data);
90
+ #else
91
+ xfree(stack->data);
92
+ #endif
93
+ xfree(stack);
74
94
  }
75
95
 
76
96
  void _msgpack_unpacker_destroy(msgpack_unpacker_t* uk)
77
97
  {
78
- #ifdef UNPACKER_STACK_RMEM
79
- msgpack_rmem_free(&s_stack_rmem, uk->stack);
80
- #else
81
- xfree(uk->stack);
82
- #endif
83
-
98
+ _msgpack_unpacker_free_stack(uk->stack);
84
99
  msgpack_buffer_destroy(UNPACKER_BUFFER_(uk));
85
100
  }
86
101
 
102
+ void msgpack_unpacker_mark_stack(msgpack_unpacker_stack_t* stack)
103
+ {
104
+ while (stack) {
105
+ msgpack_unpacker_stack_entry_t* s = stack->data;
106
+ msgpack_unpacker_stack_entry_t* send = stack->data + stack->depth;
107
+ for(; s < send; s++) {
108
+ rb_gc_mark(s->object);
109
+ rb_gc_mark(s->key);
110
+ }
111
+ stack = stack->parent;
112
+ }
113
+ }
114
+
87
115
  void msgpack_unpacker_mark(msgpack_unpacker_t* uk)
88
116
  {
89
117
  rb_gc_mark(uk->last_object);
90
118
  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
-
119
+ msgpack_unpacker_mark_stack(uk->stack);
99
120
  /* See MessagePack_Buffer_wrap */
100
121
  /* msgpack_buffer_mark(UNPACKER_BUFFER_(uk)); */
101
122
  rb_gc_mark(uk->buffer_ref);
@@ -107,9 +128,8 @@ void _msgpack_unpacker_reset(msgpack_unpacker_t* uk)
107
128
 
108
129
  uk->head_byte = HEAD_BYTE_REQUIRED;
109
130
 
110
- /*memset(uk->stack, 0, sizeof(msgpack_unpacker_t) * uk->stack_depth);*/
111
- uk->stack_depth = 0;
112
-
131
+ /*memset(uk->stack, 0, sizeof(msgpack_unpacker_t) * uk->stack->depth);*/
132
+ uk->stack->depth = 0;
113
133
  uk->last_object = Qnil;
114
134
  uk->reading_raw = Qnil;
115
135
  uk->reading_raw_remaining = 0;
@@ -142,41 +162,42 @@ static inline void reset_head_byte(msgpack_unpacker_t* uk)
142
162
 
143
163
  static inline int object_complete(msgpack_unpacker_t* uk, VALUE object)
144
164
  {
165
+ if(uk->freeze) {
166
+ rb_obj_freeze(object);
167
+ }
168
+
145
169
  uk->last_object = object;
146
170
  reset_head_byte(uk);
147
171
  return PRIMITIVE_OBJECT_COMPLETE;
148
172
  }
149
173
 
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)
174
+ static inline int object_complete_symbol(msgpack_unpacker_t* uk, VALUE object)
159
175
  {
160
- #ifdef COMPAT_HAVE_ENCODING
161
- ENCODING_SET(str, msgpack_rb_encindex_ascii8bit);
162
- #endif
163
- return object_complete(uk, str);
176
+ uk->last_object = object;
177
+ reset_head_byte(uk);
178
+ return PRIMITIVE_OBJECT_COMPLETE;
164
179
  }
165
180
 
166
181
  static inline int object_complete_ext(msgpack_unpacker_t* uk, int ext_type, VALUE str)
167
182
  {
168
- #ifdef COMPAT_HAVE_ENCODING
169
- ENCODING_SET(str, msgpack_rb_encindex_ascii8bit);
170
- #endif
183
+ if (uk->optimized_symbol_ext_type && ext_type == uk->symbol_ext_type) {
184
+ if (RB_UNLIKELY(NIL_P(str))) { // empty extension is returned as Qnil
185
+ return object_complete_symbol(uk, ID2SYM(rb_intern3("", 0, rb_utf8_encoding())));
186
+ }
187
+ return object_complete_symbol(uk, rb_str_intern(str));
188
+ }
189
+
190
+ int ext_flags;
191
+ VALUE proc = msgpack_unpacker_ext_registry_lookup(uk->ext_registry, ext_type, &ext_flags);
171
192
 
172
- VALUE proc = msgpack_unpacker_ext_registry_lookup(&uk->ext_registry, ext_type);
173
193
  if(proc != Qnil) {
174
- VALUE obj = rb_funcall(proc, s_call, 1, str);
194
+ VALUE obj;
195
+ obj = rb_funcall(proc, s_call, 1, str == Qnil ? rb_str_buf_new(0) : str);
175
196
  return object_complete(uk, obj);
176
197
  }
177
198
 
178
199
  if(uk->allow_unknown_ext) {
179
- VALUE obj = MessagePack_ExtensionValue_new(ext_type, str);
200
+ VALUE obj = MessagePack_ExtensionValue_new(ext_type, str == Qnil ? rb_str_buf_new(0) : str);
180
201
  return object_complete(uk, obj);
181
202
  }
182
203
 
@@ -184,37 +205,37 @@ static inline int object_complete_ext(msgpack_unpacker_t* uk, int ext_type, VALU
184
205
  }
185
206
 
186
207
  /* stack funcs */
187
- static inline msgpack_unpacker_stack_t* _msgpack_unpacker_stack_top(msgpack_unpacker_t* uk)
208
+ static inline msgpack_unpacker_stack_entry_t* _msgpack_unpacker_stack_entry_top(msgpack_unpacker_t* uk)
188
209
  {
189
- return &uk->stack[uk->stack_depth-1];
210
+ return &uk->stack->data[uk->stack->depth-1];
190
211
  }
191
212
 
192
213
  static inline int _msgpack_unpacker_stack_push(msgpack_unpacker_t* uk, enum stack_type_t type, size_t count, VALUE object)
193
214
  {
194
215
  reset_head_byte(uk);
195
216
 
196
- if(uk->stack_capacity - uk->stack_depth <= 0) {
217
+ if(uk->stack->capacity - uk->stack->depth <= 0) {
197
218
  return PRIMITIVE_STACK_TOO_DEEP;
198
219
  }
199
220
 
200
- msgpack_unpacker_stack_t* next = &uk->stack[uk->stack_depth];
221
+ msgpack_unpacker_stack_entry_t* next = &uk->stack->data[uk->stack->depth];
201
222
  next->count = count;
202
223
  next->type = type;
203
224
  next->object = object;
204
225
  next->key = Qnil;
205
226
 
206
- uk->stack_depth++;
227
+ uk->stack->depth++;
207
228
  return PRIMITIVE_CONTAINER_START;
208
229
  }
209
230
 
210
231
  static inline VALUE msgpack_unpacker_stack_pop(msgpack_unpacker_t* uk)
211
232
  {
212
- return --uk->stack_depth;
233
+ return --uk->stack->depth;
213
234
  }
214
235
 
215
236
  static inline bool msgpack_unpacker_stack_is_empty(msgpack_unpacker_t* uk)
216
237
  {
217
- return uk->stack_depth == 0;
238
+ return uk->stack->depth == 0;
218
239
  }
219
240
 
220
241
  #ifdef USE_CASE_RANGE
@@ -242,8 +263,8 @@ static inline bool msgpack_unpacker_stack_is_empty(msgpack_unpacker_t* uk)
242
263
 
243
264
  static inline bool is_reading_map_key(msgpack_unpacker_t* uk)
244
265
  {
245
- if(uk->stack_depth > 0) {
246
- msgpack_unpacker_stack_t* top = _msgpack_unpacker_stack_top(uk);
266
+ if(uk->stack->depth > 0) {
267
+ msgpack_unpacker_stack_entry_t* top = _msgpack_unpacker_stack_entry_top(uk);
247
268
  if(top->type == STACK_TYPE_MAP_KEY) {
248
269
  return true;
249
270
  }
@@ -271,9 +292,10 @@ static int read_raw_body_cont(msgpack_unpacker_t* uk)
271
292
 
272
293
  int ret;
273
294
  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);
295
+ ENCODING_SET(uk->reading_raw, msgpack_rb_encindex_utf8);
296
+ ret = object_complete(uk, uk->reading_raw);
297
+ } else if (uk->reading_raw_type == RAW_TYPE_BINARY) {
298
+ ret = object_complete(uk, uk->reading_raw);
277
299
  } else {
278
300
  ret = object_complete_ext(uk, uk->reading_raw_type, uk->reading_raw);
279
301
  }
@@ -285,23 +307,49 @@ static inline int read_raw_body_begin(msgpack_unpacker_t* uk, int raw_type)
285
307
  {
286
308
  /* assuming uk->reading_raw == Qnil */
287
309
 
310
+ int ext_flags;
311
+ VALUE proc;
312
+
313
+ if(!(raw_type == RAW_TYPE_STRING || raw_type == RAW_TYPE_BINARY)) {
314
+ proc = msgpack_unpacker_ext_registry_lookup(uk->ext_registry, raw_type, &ext_flags);
315
+ if(proc != Qnil && ext_flags & MSGPACK_EXT_RECURSIVE) {
316
+ VALUE obj;
317
+ uk->last_object = Qnil;
318
+ reset_head_byte(uk);
319
+ uk->reading_raw_remaining = 0;
320
+
321
+ msgpack_unpacker_stack_t* child_stack = _msgpack_unpacker_new_stack();
322
+ child_stack->parent = uk->stack;
323
+ uk->stack = child_stack;
324
+
325
+ obj = rb_funcall(proc, s_call, 1, uk->self);
326
+
327
+ uk->stack = child_stack->parent;
328
+ _msgpack_unpacker_free_stack(child_stack);
329
+
330
+ return object_complete(uk, obj);
331
+ }
332
+ }
333
+
288
334
  /* try optimized read */
289
335
  size_t length = uk->reading_raw_remaining;
290
336
  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
337
  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);
338
+ if ((uk->optimized_symbol_ext_type && uk->symbol_ext_type == raw_type) || (uk->symbolize_keys && is_reading_map_key(uk))) {
339
+ VALUE symbol = msgpack_buffer_read_top_as_symbol(UNPACKER_BUFFER_(uk), length, raw_type != RAW_TYPE_BINARY);
340
+ ret = object_complete_symbol(uk, symbol);
300
341
  } else {
301
- ret = object_complete_ext(uk, raw_type, string);
302
- }
303
- if(will_freeze) {
304
- rb_obj_freeze(string);
342
+ bool will_freeze = uk->freeze;
343
+ if(raw_type == RAW_TYPE_STRING || raw_type == RAW_TYPE_BINARY) {
344
+ /* don't use zerocopy for hash keys but get a frozen string directly
345
+ * because rb_hash_aset freezes keys and it causes copying */
346
+ will_freeze = will_freeze || is_reading_map_key(uk);
347
+ VALUE string = msgpack_buffer_read_top_as_string(UNPACKER_BUFFER_(uk), length, will_freeze, raw_type == RAW_TYPE_STRING);
348
+ ret = object_complete(uk, string);
349
+ } else {
350
+ VALUE string = msgpack_buffer_read_top_as_string(UNPACKER_BUFFER_(uk), length, false, false);
351
+ ret = object_complete_ext(uk, raw_type, string);
352
+ }
305
353
  }
306
354
  uk->reading_raw_remaining = 0;
307
355
  return ret;
@@ -331,9 +379,6 @@ static int read_primitive(msgpack_unpacker_t* uk)
331
379
 
332
380
  SWITCH_RANGE(b, 0xa0, 0xbf) // FixRaw / fixstr
333
381
  int count = b & 0x1f;
334
- if(count == 0) {
335
- return object_complete_string(uk, rb_str_buf_new(0));
336
- }
337
382
  /* read_raw_body_begin sets uk->reading_raw */
338
383
  uk->reading_raw_remaining = count;
339
384
  return read_raw_body_begin(uk, RAW_TYPE_STRING);
@@ -350,7 +395,7 @@ static int read_primitive(msgpack_unpacker_t* uk)
350
395
  if(count == 0) {
351
396
  return object_complete(uk, rb_hash_new());
352
397
  }
353
- return _msgpack_unpacker_stack_push(uk, STACK_TYPE_MAP_KEY, count*2, rb_hash_new());
398
+ return _msgpack_unpacker_stack_push(uk, STACK_TYPE_MAP_KEY, count*2, rb_hash_new_capa(count));
354
399
 
355
400
  SWITCH_RANGE(b, 0xc0, 0xdf) // Variable
356
401
  switch(b) {
@@ -371,7 +416,7 @@ static int read_primitive(msgpack_unpacker_t* uk)
371
416
  uint8_t length = cb->u8;
372
417
  int ext_type = (signed char) cb->buffer[1];
373
418
  if(length == 0) {
374
- return object_complete_ext(uk, ext_type, rb_str_buf_new(0));
419
+ return object_complete_ext(uk, ext_type, Qnil);
375
420
  }
376
421
  uk->reading_raw_remaining = length;
377
422
  return read_raw_body_begin(uk, ext_type);
@@ -383,7 +428,7 @@ static int read_primitive(msgpack_unpacker_t* uk)
383
428
  uint16_t length = _msgpack_be16(cb->u16);
384
429
  int ext_type = (signed char) cb->buffer[2];
385
430
  if(length == 0) {
386
- return object_complete_ext(uk, ext_type, rb_str_buf_new(0));
431
+ return object_complete_ext(uk, ext_type, Qnil);
387
432
  }
388
433
  uk->reading_raw_remaining = length;
389
434
  return read_raw_body_begin(uk, ext_type);
@@ -395,7 +440,7 @@ static int read_primitive(msgpack_unpacker_t* uk)
395
440
  uint32_t length = _msgpack_be32(cb->u32);
396
441
  int ext_type = (signed char) cb->buffer[4];
397
442
  if(length == 0) {
398
- return object_complete_ext(uk, ext_type, rb_str_buf_new(0));
443
+ return object_complete_ext(uk, ext_type, Qnil);
399
444
  }
400
445
  uk->reading_raw_remaining = length;
401
446
  return read_raw_body_begin(uk, ext_type);
@@ -433,7 +478,7 @@ static int read_primitive(msgpack_unpacker_t* uk)
433
478
  {
434
479
  READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 4);
435
480
  uint32_t u32 = _msgpack_be32(cb->u32);
436
- return object_complete(uk, ULONG2NUM((unsigned long)u32));
481
+ return object_complete(uk, ULONG2NUM(u32)); // long at least 32 bits
437
482
  }
438
483
 
439
484
  case 0xcf: // unsigned int 64
@@ -461,7 +506,7 @@ static int read_primitive(msgpack_unpacker_t* uk)
461
506
  {
462
507
  READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 4);
463
508
  int32_t i32 = _msgpack_be32(cb->i32);
464
- return object_complete(uk, LONG2NUM((long)i32));
509
+ return object_complete(uk, LONG2NUM(i32)); // long at least 32 bits
465
510
  }
466
511
 
467
512
  case 0xd3: // signed int 64
@@ -516,9 +561,6 @@ static int read_primitive(msgpack_unpacker_t* uk)
516
561
  {
517
562
  READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 1);
518
563
  uint8_t count = cb->u8;
519
- if(count == 0) {
520
- return object_complete_string(uk, rb_str_buf_new(0));
521
- }
522
564
  /* read_raw_body_begin sets uk->reading_raw */
523
565
  uk->reading_raw_remaining = count;
524
566
  return read_raw_body_begin(uk, RAW_TYPE_STRING);
@@ -528,9 +570,6 @@ static int read_primitive(msgpack_unpacker_t* uk)
528
570
  {
529
571
  READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 2);
530
572
  uint16_t count = _msgpack_be16(cb->u16);
531
- if(count == 0) {
532
- return object_complete_string(uk, rb_str_buf_new(0));
533
- }
534
573
  /* read_raw_body_begin sets uk->reading_raw */
535
574
  uk->reading_raw_remaining = count;
536
575
  return read_raw_body_begin(uk, RAW_TYPE_STRING);
@@ -540,9 +579,6 @@ static int read_primitive(msgpack_unpacker_t* uk)
540
579
  {
541
580
  READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 4);
542
581
  uint32_t count = _msgpack_be32(cb->u32);
543
- if(count == 0) {
544
- return object_complete_string(uk, rb_str_buf_new(0));
545
- }
546
582
  /* read_raw_body_begin sets uk->reading_raw */
547
583
  uk->reading_raw_remaining = count;
548
584
  return read_raw_body_begin(uk, RAW_TYPE_STRING);
@@ -552,9 +588,6 @@ static int read_primitive(msgpack_unpacker_t* uk)
552
588
  {
553
589
  READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 1);
554
590
  uint8_t count = cb->u8;
555
- if(count == 0) {
556
- return object_complete_binary(uk, rb_str_buf_new(0));
557
- }
558
591
  /* read_raw_body_begin sets uk->reading_raw */
559
592
  uk->reading_raw_remaining = count;
560
593
  return read_raw_body_begin(uk, RAW_TYPE_BINARY);
@@ -564,9 +597,6 @@ static int read_primitive(msgpack_unpacker_t* uk)
564
597
  {
565
598
  READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 2);
566
599
  uint16_t count = _msgpack_be16(cb->u16);
567
- if(count == 0) {
568
- return object_complete_binary(uk, rb_str_buf_new(0));
569
- }
570
600
  /* read_raw_body_begin sets uk->reading_raw */
571
601
  uk->reading_raw_remaining = count;
572
602
  return read_raw_body_begin(uk, RAW_TYPE_BINARY);
@@ -576,9 +606,6 @@ static int read_primitive(msgpack_unpacker_t* uk)
576
606
  {
577
607
  READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 4);
578
608
  uint32_t count = _msgpack_be32(cb->u32);
579
- if(count == 0) {
580
- return object_complete_binary(uk, rb_str_buf_new(0));
581
- }
582
609
  /* read_raw_body_begin sets uk->reading_raw */
583
610
  uk->reading_raw_remaining = count;
584
611
  return read_raw_body_begin(uk, RAW_TYPE_BINARY);
@@ -611,7 +638,7 @@ static int read_primitive(msgpack_unpacker_t* uk)
611
638
  if(count == 0) {
612
639
  return object_complete(uk, rb_hash_new());
613
640
  }
614
- return _msgpack_unpacker_stack_push(uk, STACK_TYPE_MAP_KEY, count*2, rb_hash_new());
641
+ return _msgpack_unpacker_stack_push(uk, STACK_TYPE_MAP_KEY, count*2, rb_hash_new_capa(count));
615
642
  }
616
643
 
617
644
  case 0xdf: // map 32
@@ -621,7 +648,7 @@ static int read_primitive(msgpack_unpacker_t* uk)
621
648
  if(count == 0) {
622
649
  return object_complete(uk, rb_hash_new());
623
650
  }
624
- return _msgpack_unpacker_stack_push(uk, STACK_TYPE_MAP_KEY, count*2, rb_hash_new());
651
+ return _msgpack_unpacker_stack_push(uk, STACK_TYPE_MAP_KEY, count*2, rb_hash_new_capa(count));
625
652
  }
626
653
 
627
654
  default:
@@ -708,7 +735,7 @@ int msgpack_unpacker_read(msgpack_unpacker_t* uk, size_t target_stack_depth)
708
735
 
709
736
  container_completed:
710
737
  {
711
- msgpack_unpacker_stack_t* top = _msgpack_unpacker_stack_top(uk);
738
+ msgpack_unpacker_stack_entry_t* top = _msgpack_unpacker_stack_entry_top(uk);
712
739
  switch(top->type) {
713
740
  case STACK_TYPE_ARRAY:
714
741
  rb_ary_push(top->object, uk->last_object);
@@ -719,18 +746,8 @@ int msgpack_unpacker_read(msgpack_unpacker_t* uk, size_t target_stack_depth)
719
746
  break;
720
747
  case STACK_TYPE_MAP_VALUE:
721
748
  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 */
749
+ /* here uses rb_str_intern instead of rb_intern so that Ruby VM can GC unused symbols */
725
750
  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
751
  } else {
735
752
  rb_hash_aset(top->object, top->key, uk->last_object);
736
753
  }
@@ -768,7 +785,7 @@ int msgpack_unpacker_skip(msgpack_unpacker_t* uk, size_t target_stack_depth)
768
785
 
769
786
  container_completed:
770
787
  {
771
- msgpack_unpacker_stack_t* top = _msgpack_unpacker_stack_top(uk);
788
+ msgpack_unpacker_stack_entry_t* top = _msgpack_unpacker_stack_entry_top(uk);
772
789
 
773
790
  /* this section optimized out */
774
791
  // TODO object_complete still creates objects which should be optimized out
@@ -27,6 +27,7 @@
27
27
 
28
28
  struct msgpack_unpacker_t;
29
29
  typedef struct msgpack_unpacker_t msgpack_unpacker_t;
30
+ typedef struct msgpack_unpacker_stack_t msgpack_unpacker_stack_t;
30
31
 
31
32
  enum stack_type_t {
32
33
  STACK_TYPE_ARRAY,
@@ -39,19 +40,23 @@ typedef struct {
39
40
  enum stack_type_t type;
40
41
  VALUE object;
41
42
  VALUE key;
42
- } msgpack_unpacker_stack_t;
43
+ } msgpack_unpacker_stack_entry_t;
44
+
45
+ struct msgpack_unpacker_stack_t {
46
+ size_t depth;
47
+ size_t capacity;
48
+ msgpack_unpacker_stack_entry_t *data;
49
+ msgpack_unpacker_stack_t *parent;
50
+ };
43
51
 
44
52
  #define MSGPACK_UNPACKER_STACK_SIZE (8+4+8+8) /* assumes size_t <= 64bit, enum <= 32bit, VALUE <= 64bit */
45
53
 
46
54
  struct msgpack_unpacker_t {
47
55
  msgpack_buffer_t buffer;
48
-
56
+ msgpack_unpacker_stack_t *stack;
49
57
  unsigned int head_byte;
50
58
 
51
- msgpack_unpacker_stack_t* stack;
52
- size_t stack_depth;
53
- size_t stack_capacity;
54
-
59
+ VALUE self;
55
60
  VALUE last_object;
56
61
 
57
62
  VALUE reading_raw;
@@ -60,11 +65,14 @@ struct msgpack_unpacker_t {
60
65
 
61
66
  VALUE buffer_ref;
62
67
 
63
- msgpack_unpacker_ext_registry_t ext_registry;
68
+ msgpack_unpacker_ext_registry_t *ext_registry;
64
69
 
65
70
  /* options */
66
71
  bool symbolize_keys;
72
+ bool freeze;
67
73
  bool allow_unknown_ext;
74
+ bool optimized_symbol_ext_type;
75
+ int symbol_ext_type;
68
76
  };
69
77
 
70
78
  #define UNPACKER_BUFFER_(uk) (&(uk)->buffer)
@@ -79,11 +87,11 @@ enum msgpack_unpacker_object_type {
79
87
  TYPE_MAP,
80
88
  };
81
89
 
82
- void msgpack_unpacker_static_init();
90
+ void msgpack_unpacker_static_init(void);
83
91
 
84
- void msgpack_unpacker_static_destroy();
92
+ void msgpack_unpacker_static_destroy(void);
85
93
 
86
- void _msgpack_unpacker_init(msgpack_unpacker_t* uk);
94
+ void _msgpack_unpacker_init(msgpack_unpacker_t*);
87
95
 
88
96
  void _msgpack_unpacker_destroy(msgpack_unpacker_t* uk);
89
97
 
@@ -96,6 +104,11 @@ static inline void msgpack_unpacker_set_symbolized_keys(msgpack_unpacker_t* uk,
96
104
  uk->symbolize_keys = enable;
97
105
  }
98
106
 
107
+ static inline void msgpack_unpacker_set_freeze(msgpack_unpacker_t* uk, bool enable)
108
+ {
109
+ uk->freeze = enable;
110
+ }
111
+
99
112
  static inline void msgpack_unpacker_set_allow_unknown_ext(msgpack_unpacker_t* uk, bool enable)
100
113
  {
101
114
  uk->allow_unknown_ext = enable;