msgpack 1.4.5 → 1.5.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yaml +5 -5
  3. data/ChangeLog +32 -0
  4. data/README.md +25 -1
  5. data/bench/bench.rb +78 -0
  6. data/doclib/msgpack/factory.rb +45 -2
  7. data/ext/java/org/msgpack/jruby/Buffer.java +6 -0
  8. data/ext/java/org/msgpack/jruby/Decoder.java +23 -19
  9. data/ext/java/org/msgpack/jruby/Encoder.java +46 -18
  10. data/ext/java/org/msgpack/jruby/ExtensionRegistry.java +24 -31
  11. data/ext/java/org/msgpack/jruby/Factory.java +40 -5
  12. data/ext/java/org/msgpack/jruby/Packer.java +21 -11
  13. data/ext/java/org/msgpack/jruby/Unpacker.java +44 -22
  14. data/ext/msgpack/buffer.c +9 -36
  15. data/ext/msgpack/buffer.h +9 -1
  16. data/ext/msgpack/buffer_class.c +18 -9
  17. data/ext/msgpack/compat.h +0 -99
  18. data/ext/msgpack/extconf.rb +9 -11
  19. data/ext/msgpack/factory_class.c +62 -5
  20. data/ext/msgpack/packer.c +42 -29
  21. data/ext/msgpack/packer.h +25 -7
  22. data/ext/msgpack/packer_class.c +23 -20
  23. data/ext/msgpack/packer_ext_registry.c +13 -4
  24. data/ext/msgpack/packer_ext_registry.h +10 -5
  25. data/ext/msgpack/unpacker.c +99 -68
  26. data/ext/msgpack/unpacker.h +10 -6
  27. data/ext/msgpack/unpacker_class.c +16 -8
  28. data/ext/msgpack/unpacker_ext_registry.c +3 -2
  29. data/ext/msgpack/unpacker_ext_registry.h +5 -2
  30. data/lib/msgpack/bigint.rb +69 -0
  31. data/lib/msgpack/factory.rb +103 -0
  32. data/lib/msgpack/version.rb +1 -1
  33. data/lib/msgpack.rb +4 -5
  34. data/msgpack.gemspec +1 -0
  35. data/spec/bigint_spec.rb +26 -0
  36. data/spec/factory_spec.rb +248 -0
  37. data/spec/spec_helper.rb +9 -1
  38. data/spec/timestamp_spec.rb +2 -2
  39. data/spec/unpacker_spec.rb +12 -0
  40. metadata +20 -13
  41. data/bench/pack.rb +0 -23
  42. data/bench/pack_log.rb +0 -33
  43. data/bench/pack_log_long.rb +0 -65
  44. data/bench/pack_symbols.rb +0 -28
  45. data/bench/run.sh +0 -14
  46. data/bench/run_long.sh +0 -35
  47. data/bench/run_symbols.sh +0 -26
  48. data/bench/unpack.rb +0 -21
  49. data/bench/unpack_log.rb +0 -34
  50. data/bench/unpack_log_long.rb +0 -67
@@ -34,6 +34,13 @@ static ID s_call;
34
34
  static msgpack_rmem_t s_stack_rmem;
35
35
  #endif
36
36
 
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
+
37
44
  void msgpack_unpacker_static_init()
38
45
  {
39
46
  #ifdef UNPACKER_STACK_RMEM
@@ -52,6 +59,19 @@ 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
  msgpack_unpacker_t* _msgpack_unpacker_new(void)
56
76
  {
57
77
  msgpack_unpacker_t* uk = ZALLOC_N(msgpack_unpacker_t, 1);
@@ -63,41 +83,44 @@ msgpack_unpacker_t* _msgpack_unpacker_new(void)
63
83
  uk->last_object = Qnil;
64
84
  uk->reading_raw = Qnil;
65
85
 
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;
86
+ uk->stack = _msgpack_unpacker_new_stack();
74
87
 
75
88
  return uk;
76
89
  }
77
90
 
91
+ static inline void _msgpack_unpacker_free_stack(msgpack_unpacker_stack_t* stack) {
92
+ #ifdef UNPACKER_STACK_RMEM
93
+ msgpack_rmem_free(&s_stack_rmem, stack->data);
94
+ #else
95
+ xfree(stack->data);
96
+ #endif
97
+ xfree(stack);
98
+ }
99
+
78
100
  void _msgpack_unpacker_destroy(msgpack_unpacker_t* uk)
79
101
  {
80
- #ifdef UNPACKER_STACK_RMEM
81
- msgpack_rmem_free(&s_stack_rmem, uk->stack);
82
- #else
83
- xfree(uk->stack);
84
- #endif
85
-
102
+ _msgpack_unpacker_free_stack(uk->stack);
86
103
  msgpack_buffer_destroy(UNPACKER_BUFFER_(uk));
87
104
  }
88
105
 
106
+ void msgpack_unpacker_mark_stack(msgpack_unpacker_stack_t* stack)
107
+ {
108
+ while (stack) {
109
+ msgpack_unpacker_stack_entry_t* s = stack->data;
110
+ msgpack_unpacker_stack_entry_t* send = stack->data + stack->depth;
111
+ for(; s < send; s++) {
112
+ rb_gc_mark(s->object);
113
+ rb_gc_mark(s->key);
114
+ }
115
+ stack = stack->parent;
116
+ }
117
+ }
118
+
89
119
  void msgpack_unpacker_mark(msgpack_unpacker_t* uk)
90
120
  {
91
121
  rb_gc_mark(uk->last_object);
92
122
  rb_gc_mark(uk->reading_raw);
93
-
94
- msgpack_unpacker_stack_t* s = uk->stack;
95
- msgpack_unpacker_stack_t* send = uk->stack + uk->stack_depth;
96
- for(; s < send; s++) {
97
- rb_gc_mark(s->object);
98
- rb_gc_mark(s->key);
99
- }
100
-
123
+ msgpack_unpacker_mark_stack(uk->stack);
101
124
  /* See MessagePack_Buffer_wrap */
102
125
  /* msgpack_buffer_mark(UNPACKER_BUFFER_(uk)); */
103
126
  rb_gc_mark(uk->buffer_ref);
@@ -109,9 +132,8 @@ void _msgpack_unpacker_reset(msgpack_unpacker_t* uk)
109
132
 
110
133
  uk->head_byte = HEAD_BYTE_REQUIRED;
111
134
 
112
- /*memset(uk->stack, 0, sizeof(msgpack_unpacker_t) * uk->stack_depth);*/
113
- uk->stack_depth = 0;
114
-
135
+ /*memset(uk->stack, 0, sizeof(msgpack_unpacker_t) * uk->stack->depth);*/
136
+ uk->stack->depth = 0;
115
137
  uk->last_object = Qnil;
116
138
  uk->reading_raw = Qnil;
117
139
  uk->reading_raw_remaining = 0;
@@ -163,17 +185,23 @@ static inline int object_complete_symbol(msgpack_unpacker_t* uk, VALUE object)
163
185
  static inline int object_complete_ext(msgpack_unpacker_t* uk, int ext_type, VALUE str)
164
186
  {
165
187
  if (uk->optimized_symbol_ext_type && ext_type == uk->symbol_ext_type) {
188
+ if (RB_UNLIKELY(NIL_P(str))) { // empty extension is returned as Qnil
189
+ return object_complete_symbol(uk, ID2SYM(rb_intern3("", 0, rb_utf8_encoding())));
190
+ }
166
191
  return object_complete_symbol(uk, rb_str_intern(str));
167
192
  }
168
193
 
169
- VALUE proc = msgpack_unpacker_ext_registry_lookup(uk->ext_registry, ext_type);
194
+ int ext_flags;
195
+ VALUE proc = msgpack_unpacker_ext_registry_lookup(uk->ext_registry, ext_type, &ext_flags);
196
+
170
197
  if(proc != Qnil) {
171
- VALUE obj = rb_funcall(proc, s_call, 1, str);
198
+ VALUE obj;
199
+ obj = rb_funcall(proc, s_call, 1, str == Qnil ? rb_str_buf_new(0) : str);
172
200
  return object_complete(uk, obj);
173
201
  }
174
202
 
175
203
  if(uk->allow_unknown_ext) {
176
- VALUE obj = MessagePack_ExtensionValue_new(ext_type, str);
204
+ VALUE obj = MessagePack_ExtensionValue_new(ext_type, str == Qnil ? rb_str_buf_new(0) : str);
177
205
  return object_complete(uk, obj);
178
206
  }
179
207
 
@@ -181,37 +209,37 @@ static inline int object_complete_ext(msgpack_unpacker_t* uk, int ext_type, VALU
181
209
  }
182
210
 
183
211
  /* stack funcs */
184
- static inline msgpack_unpacker_stack_t* _msgpack_unpacker_stack_top(msgpack_unpacker_t* uk)
212
+ static inline msgpack_unpacker_stack_entry_t* _msgpack_unpacker_stack_entry_top(msgpack_unpacker_t* uk)
185
213
  {
186
- return &uk->stack[uk->stack_depth-1];
214
+ return &uk->stack->data[uk->stack->depth-1];
187
215
  }
188
216
 
189
217
  static inline int _msgpack_unpacker_stack_push(msgpack_unpacker_t* uk, enum stack_type_t type, size_t count, VALUE object)
190
218
  {
191
219
  reset_head_byte(uk);
192
220
 
193
- if(uk->stack_capacity - uk->stack_depth <= 0) {
221
+ if(uk->stack->capacity - uk->stack->depth <= 0) {
194
222
  return PRIMITIVE_STACK_TOO_DEEP;
195
223
  }
196
224
 
197
- msgpack_unpacker_stack_t* next = &uk->stack[uk->stack_depth];
225
+ msgpack_unpacker_stack_entry_t* next = &uk->stack->data[uk->stack->depth];
198
226
  next->count = count;
199
227
  next->type = type;
200
228
  next->object = object;
201
229
  next->key = Qnil;
202
230
 
203
- uk->stack_depth++;
231
+ uk->stack->depth++;
204
232
  return PRIMITIVE_CONTAINER_START;
205
233
  }
206
234
 
207
235
  static inline VALUE msgpack_unpacker_stack_pop(msgpack_unpacker_t* uk)
208
236
  {
209
- return --uk->stack_depth;
237
+ return --uk->stack->depth;
210
238
  }
211
239
 
212
240
  static inline bool msgpack_unpacker_stack_is_empty(msgpack_unpacker_t* uk)
213
241
  {
214
- return uk->stack_depth == 0;
242
+ return uk->stack->depth == 0;
215
243
  }
216
244
 
217
245
  #ifdef USE_CASE_RANGE
@@ -239,8 +267,8 @@ static inline bool msgpack_unpacker_stack_is_empty(msgpack_unpacker_t* uk)
239
267
 
240
268
  static inline bool is_reading_map_key(msgpack_unpacker_t* uk)
241
269
  {
242
- if(uk->stack_depth > 0) {
243
- msgpack_unpacker_stack_t* top = _msgpack_unpacker_stack_top(uk);
270
+ if(uk->stack->depth > 0) {
271
+ msgpack_unpacker_stack_entry_t* top = _msgpack_unpacker_stack_entry_top(uk);
244
272
  if(top->type == STACK_TYPE_MAP_KEY) {
245
273
  return true;
246
274
  }
@@ -283,6 +311,30 @@ static inline int read_raw_body_begin(msgpack_unpacker_t* uk, int raw_type)
283
311
  {
284
312
  /* assuming uk->reading_raw == Qnil */
285
313
 
314
+ int ext_flags;
315
+ VALUE proc;
316
+
317
+ if(!(raw_type == RAW_TYPE_STRING || raw_type == RAW_TYPE_BINARY)) {
318
+ proc = msgpack_unpacker_ext_registry_lookup(uk->ext_registry, raw_type, &ext_flags);
319
+ if(proc != Qnil && ext_flags & MSGPACK_EXT_RECURSIVE) {
320
+ VALUE obj;
321
+ uk->last_object = Qnil;
322
+ reset_head_byte(uk);
323
+ uk->reading_raw_remaining = 0;
324
+
325
+ msgpack_unpacker_stack_t* child_stack = _msgpack_unpacker_new_stack();
326
+ child_stack->parent = uk->stack;
327
+ uk->stack = child_stack;
328
+
329
+ obj = rb_funcall(proc, s_call, 1, uk->buffer.owner);
330
+
331
+ uk->stack = child_stack->parent;
332
+ _msgpack_unpacker_free_stack(child_stack);
333
+
334
+ return object_complete(uk, obj);
335
+ }
336
+ }
337
+
286
338
  /* try optimized read */
287
339
  size_t length = uk->reading_raw_remaining;
288
340
  if(length <= msgpack_buffer_top_readable_size(UNPACKER_BUFFER_(uk))) {
@@ -331,9 +383,6 @@ static int read_primitive(msgpack_unpacker_t* uk)
331
383
 
332
384
  SWITCH_RANGE(b, 0xa0, 0xbf) // FixRaw / fixstr
333
385
  int count = b & 0x1f;
334
- if(count == 0) {
335
- return object_complete(uk, rb_utf8_str_new_static("", 0));
336
- }
337
386
  /* read_raw_body_begin sets uk->reading_raw */
338
387
  uk->reading_raw_remaining = count;
339
388
  return read_raw_body_begin(uk, RAW_TYPE_STRING);
@@ -350,7 +399,7 @@ static int read_primitive(msgpack_unpacker_t* uk)
350
399
  if(count == 0) {
351
400
  return object_complete(uk, rb_hash_new());
352
401
  }
353
- return _msgpack_unpacker_stack_push(uk, STACK_TYPE_MAP_KEY, count*2, rb_hash_new());
402
+ return _msgpack_unpacker_stack_push(uk, STACK_TYPE_MAP_KEY, count*2, rb_hash_new_capa(count));
354
403
 
355
404
  SWITCH_RANGE(b, 0xc0, 0xdf) // Variable
356
405
  switch(b) {
@@ -371,7 +420,7 @@ static int read_primitive(msgpack_unpacker_t* uk)
371
420
  uint8_t length = cb->u8;
372
421
  int ext_type = (signed char) cb->buffer[1];
373
422
  if(length == 0) {
374
- return object_complete_ext(uk, ext_type, rb_str_buf_new(0));
423
+ return object_complete_ext(uk, ext_type, Qnil);
375
424
  }
376
425
  uk->reading_raw_remaining = length;
377
426
  return read_raw_body_begin(uk, ext_type);
@@ -383,7 +432,7 @@ static int read_primitive(msgpack_unpacker_t* uk)
383
432
  uint16_t length = _msgpack_be16(cb->u16);
384
433
  int ext_type = (signed char) cb->buffer[2];
385
434
  if(length == 0) {
386
- return object_complete_ext(uk, ext_type, rb_str_buf_new(0));
435
+ return object_complete_ext(uk, ext_type, Qnil);
387
436
  }
388
437
  uk->reading_raw_remaining = length;
389
438
  return read_raw_body_begin(uk, ext_type);
@@ -395,7 +444,7 @@ static int read_primitive(msgpack_unpacker_t* uk)
395
444
  uint32_t length = _msgpack_be32(cb->u32);
396
445
  int ext_type = (signed char) cb->buffer[4];
397
446
  if(length == 0) {
398
- return object_complete_ext(uk, ext_type, rb_str_buf_new(0));
447
+ return object_complete_ext(uk, ext_type, Qnil);
399
448
  }
400
449
  uk->reading_raw_remaining = length;
401
450
  return read_raw_body_begin(uk, ext_type);
@@ -433,7 +482,7 @@ static int read_primitive(msgpack_unpacker_t* uk)
433
482
  {
434
483
  READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 4);
435
484
  uint32_t u32 = _msgpack_be32(cb->u32);
436
- return object_complete(uk, ULONG2NUM((unsigned long)u32));
485
+ return object_complete(uk, ULONG2NUM(u32)); // long at least 32 bits
437
486
  }
438
487
 
439
488
  case 0xcf: // unsigned int 64
@@ -461,7 +510,7 @@ static int read_primitive(msgpack_unpacker_t* uk)
461
510
  {
462
511
  READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 4);
463
512
  int32_t i32 = _msgpack_be32(cb->i32);
464
- return object_complete(uk, LONG2NUM((long)i32));
513
+ return object_complete(uk, LONG2NUM(i32)); // long at least 32 bits
465
514
  }
466
515
 
467
516
  case 0xd3: // signed int 64
@@ -516,9 +565,6 @@ static int read_primitive(msgpack_unpacker_t* uk)
516
565
  {
517
566
  READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 1);
518
567
  uint8_t count = cb->u8;
519
- if(count == 0) {
520
- return object_complete(uk, rb_utf8_str_new_static("", 0));
521
- }
522
568
  /* read_raw_body_begin sets uk->reading_raw */
523
569
  uk->reading_raw_remaining = count;
524
570
  return read_raw_body_begin(uk, RAW_TYPE_STRING);
@@ -528,9 +574,6 @@ static int read_primitive(msgpack_unpacker_t* uk)
528
574
  {
529
575
  READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 2);
530
576
  uint16_t count = _msgpack_be16(cb->u16);
531
- if(count == 0) {
532
- return object_complete(uk, rb_utf8_str_new_static("", 0));
533
- }
534
577
  /* read_raw_body_begin sets uk->reading_raw */
535
578
  uk->reading_raw_remaining = count;
536
579
  return read_raw_body_begin(uk, RAW_TYPE_STRING);
@@ -540,9 +583,6 @@ static int read_primitive(msgpack_unpacker_t* uk)
540
583
  {
541
584
  READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 4);
542
585
  uint32_t count = _msgpack_be32(cb->u32);
543
- if(count == 0) {
544
- return object_complete(uk, rb_utf8_str_new_static("", 0));
545
- }
546
586
  /* read_raw_body_begin sets uk->reading_raw */
547
587
  uk->reading_raw_remaining = count;
548
588
  return read_raw_body_begin(uk, RAW_TYPE_STRING);
@@ -552,9 +592,6 @@ static int read_primitive(msgpack_unpacker_t* uk)
552
592
  {
553
593
  READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 1);
554
594
  uint8_t count = cb->u8;
555
- if(count == 0) {
556
- return object_complete(uk, rb_str_new_static("", 0));
557
- }
558
595
  /* read_raw_body_begin sets uk->reading_raw */
559
596
  uk->reading_raw_remaining = count;
560
597
  return read_raw_body_begin(uk, RAW_TYPE_BINARY);
@@ -564,9 +601,6 @@ static int read_primitive(msgpack_unpacker_t* uk)
564
601
  {
565
602
  READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 2);
566
603
  uint16_t count = _msgpack_be16(cb->u16);
567
- if(count == 0) {
568
- return object_complete(uk, rb_str_new_static("", 0));
569
- }
570
604
  /* read_raw_body_begin sets uk->reading_raw */
571
605
  uk->reading_raw_remaining = count;
572
606
  return read_raw_body_begin(uk, RAW_TYPE_BINARY);
@@ -576,9 +610,6 @@ static int read_primitive(msgpack_unpacker_t* uk)
576
610
  {
577
611
  READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 4);
578
612
  uint32_t count = _msgpack_be32(cb->u32);
579
- if(count == 0) {
580
- return object_complete(uk, rb_str_new_static("", 0));
581
- }
582
613
  /* read_raw_body_begin sets uk->reading_raw */
583
614
  uk->reading_raw_remaining = count;
584
615
  return read_raw_body_begin(uk, RAW_TYPE_BINARY);
@@ -611,7 +642,7 @@ static int read_primitive(msgpack_unpacker_t* uk)
611
642
  if(count == 0) {
612
643
  return object_complete(uk, rb_hash_new());
613
644
  }
614
- return _msgpack_unpacker_stack_push(uk, STACK_TYPE_MAP_KEY, count*2, rb_hash_new());
645
+ return _msgpack_unpacker_stack_push(uk, STACK_TYPE_MAP_KEY, count*2, rb_hash_new_capa(count));
615
646
  }
616
647
 
617
648
  case 0xdf: // map 32
@@ -621,7 +652,7 @@ static int read_primitive(msgpack_unpacker_t* uk)
621
652
  if(count == 0) {
622
653
  return object_complete(uk, rb_hash_new());
623
654
  }
624
- return _msgpack_unpacker_stack_push(uk, STACK_TYPE_MAP_KEY, count*2, rb_hash_new());
655
+ return _msgpack_unpacker_stack_push(uk, STACK_TYPE_MAP_KEY, count*2, rb_hash_new_capa(count));
625
656
  }
626
657
 
627
658
  default:
@@ -708,7 +739,7 @@ int msgpack_unpacker_read(msgpack_unpacker_t* uk, size_t target_stack_depth)
708
739
 
709
740
  container_completed:
710
741
  {
711
- msgpack_unpacker_stack_t* top = _msgpack_unpacker_stack_top(uk);
742
+ msgpack_unpacker_stack_entry_t* top = _msgpack_unpacker_stack_entry_top(uk);
712
743
  switch(top->type) {
713
744
  case STACK_TYPE_ARRAY:
714
745
  rb_ary_push(top->object, uk->last_object);
@@ -758,7 +789,7 @@ int msgpack_unpacker_skip(msgpack_unpacker_t* uk, size_t target_stack_depth)
758
789
 
759
790
  container_completed:
760
791
  {
761
- msgpack_unpacker_stack_t* top = _msgpack_unpacker_stack_top(uk);
792
+ msgpack_unpacker_stack_entry_t* top = _msgpack_unpacker_stack_entry_top(uk);
762
793
 
763
794
  /* this section optimized out */
764
795
  // 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,22 @@ 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
-
55
59
  VALUE last_object;
56
60
 
57
61
  VALUE reading_raw;
@@ -33,6 +33,10 @@ static VALUE eUnexpectedTypeError;
33
33
  static VALUE eUnknownExtTypeError;
34
34
  static VALUE mTypeError; // obsoleted. only for backward compatibility. See #86.
35
35
 
36
+ static VALUE sym_symbolize_keys;
37
+ static VALUE sym_freeze;
38
+ static VALUE sym_allow_unknown_ext;
39
+
36
40
  #define UNPACKER(from, name) \
37
41
  msgpack_unpacker_t *name = NULL; \
38
42
  Data_Get_Struct(from, msgpack_unpacker_t, name); \
@@ -83,7 +87,7 @@ VALUE MessagePack_Unpacker_initialize(int argc, VALUE* argv, VALUE self)
83
87
  } else if(argc == 2) {
84
88
  io = argv[0];
85
89
  options = argv[1];
86
- if(rb_type(options) != T_HASH) {
90
+ if(options != Qnil && rb_type(options) != T_HASH) {
87
91
  rb_raise(rb_eArgError, "expected Hash but found %s.", rb_obj_classname(options));
88
92
  }
89
93
 
@@ -100,13 +104,13 @@ VALUE MessagePack_Unpacker_initialize(int argc, VALUE* argv, VALUE self)
100
104
  if(options != Qnil) {
101
105
  VALUE v;
102
106
 
103
- v = rb_hash_aref(options, ID2SYM(rb_intern("symbolize_keys")));
107
+ v = rb_hash_aref(options, sym_symbolize_keys);
104
108
  msgpack_unpacker_set_symbolized_keys(uk, RTEST(v));
105
109
 
106
- v = rb_hash_aref(options, ID2SYM(rb_intern("freeze")));
110
+ v = rb_hash_aref(options, sym_freeze);
107
111
  msgpack_unpacker_set_freeze(uk, RTEST(v));
108
112
 
109
- v = rb_hash_aref(options, ID2SYM(rb_intern("allow_unknown_ext")));
113
+ v = rb_hash_aref(options, sym_allow_unknown_ext);
110
114
  msgpack_unpacker_set_allow_unknown_ext(uk, RTEST(v));
111
115
  }
112
116
 
@@ -143,6 +147,7 @@ NORETURN(static void raise_unpacker_error(int r))
143
147
  case PRIMITIVE_UNEXPECTED_TYPE:
144
148
  rb_raise(eUnexpectedTypeError, "unexpected type");
145
149
  case PRIMITIVE_UNEXPECTED_EXT_TYPE:
150
+ // rb_bug("unexpected extension type");
146
151
  rb_raise(eUnknownExtTypeError, "unexpected extension type");
147
152
  default:
148
153
  rb_raise(eUnpackError, "logically unknown error %d", r);
@@ -204,7 +209,7 @@ static VALUE Unpacker_read_array_header(VALUE self)
204
209
  raise_unpacker_error(r);
205
210
  }
206
211
 
207
- return ULONG2NUM(size);
212
+ return ULONG2NUM(size); // long at least 32 bits
208
213
  }
209
214
 
210
215
  static VALUE Unpacker_read_map_header(VALUE self)
@@ -217,7 +222,7 @@ static VALUE Unpacker_read_map_header(VALUE self)
217
222
  raise_unpacker_error((int)r);
218
223
  }
219
224
 
220
- return ULONG2NUM(size);
225
+ return ULONG2NUM(size); // long at least 32 bits
221
226
  }
222
227
 
223
228
 
@@ -361,7 +366,7 @@ static VALUE Unpacker_register_type(int argc, VALUE* argv, VALUE self)
361
366
  rb_raise(rb_eRangeError, "integer %d too big to convert to `signed char'", ext_type);
362
367
  }
363
368
 
364
- msgpack_unpacker_ext_registry_put(&uk->ext_registry, ext_module, ext_type, proc, arg);
369
+ msgpack_unpacker_ext_registry_put(&uk->ext_registry, ext_module, ext_type, 0, proc, arg);
365
370
 
366
371
  return Qnil;
367
372
  }
@@ -411,6 +416,10 @@ void MessagePack_Unpacker_module_init(VALUE mMessagePack)
411
416
 
412
417
  eUnknownExtTypeError = rb_define_class_under(mMessagePack, "UnknownExtTypeError", eUnpackError);
413
418
 
419
+ sym_symbolize_keys = ID2SYM(rb_intern("symbolize_keys"));
420
+ sym_freeze = ID2SYM(rb_intern("freeze"));
421
+ sym_allow_unknown_ext = ID2SYM(rb_intern("allow_unknown_ext"));
422
+
414
423
  rb_define_alloc_func(cMessagePack_Unpacker, MessagePack_Unpacker_alloc);
415
424
 
416
425
  rb_define_method(cMessagePack_Unpacker, "initialize", MessagePack_Unpacker_initialize, -1);
@@ -441,4 +450,3 @@ void MessagePack_Unpacker_module_init(VALUE mMessagePack)
441
450
 
442
451
  rb_define_method(cMessagePack_Unpacker, "full_unpack", Unpacker_full_unpack, 0);
443
452
  }
444
-
@@ -77,9 +77,10 @@ void msgpack_unpacker_ext_registry_release(msgpack_unpacker_ext_registry_t* ukrg
77
77
  }
78
78
 
79
79
  void msgpack_unpacker_ext_registry_put(msgpack_unpacker_ext_registry_t** ukrg,
80
- VALUE ext_module, int ext_type, VALUE proc, VALUE arg)
80
+ VALUE ext_module, int ext_type, int flags, VALUE proc, VALUE arg)
81
81
  {
82
82
  msgpack_unpacker_ext_registry_t* ext_registry = msgpack_unpacker_ext_registry_cow(*ukrg);
83
- ext_registry->array[ext_type + 128] = rb_ary_new3(3, ext_module, proc, arg);
83
+
84
+ ext_registry->array[ext_type + 128] = rb_ary_new3(4, ext_module, proc, arg, INT2FIX(flags));
84
85
  *ukrg = ext_registry;
85
86
  }
@@ -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_unpacker_ext_registry_t;
25
27
  typedef struct msgpack_unpacker_ext_registry_t msgpack_unpacker_ext_registry_t;
26
28
 
@@ -46,14 +48,15 @@ static inline void msgpack_unpacker_ext_registry_borrow(msgpack_unpacker_ext_reg
46
48
  void msgpack_unpacker_ext_registry_mark(msgpack_unpacker_ext_registry_t* ukrg);
47
49
 
48
50
  void msgpack_unpacker_ext_registry_put(msgpack_unpacker_ext_registry_t** ukrg,
49
- VALUE ext_module, int ext_type, VALUE proc, VALUE arg);
51
+ VALUE ext_module, int ext_type, int flags, VALUE proc, VALUE arg);
50
52
 
51
53
  static inline VALUE msgpack_unpacker_ext_registry_lookup(msgpack_unpacker_ext_registry_t* ukrg,
52
- int ext_type)
54
+ int ext_type, int* ext_flags_result)
53
55
  {
54
56
  if (ukrg) {
55
57
  VALUE entry = ukrg->array[ext_type + 128];
56
58
  if (entry != Qnil) {
59
+ *ext_flags_result = FIX2INT(rb_ary_entry(entry, 3));
57
60
  return rb_ary_entry(entry, 1);
58
61
  }
59
62
  }
@@ -0,0 +1,69 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MessagePack
4
+ module Bigint
5
+ # We split the bigint in 32bits chunks so that individual part fits into
6
+ # a MRI immediate Integer.
7
+ CHUNK_BITLENGTH = 32
8
+ FORMAT = 'CL>*'
9
+
10
+ if Integer.instance_method(:[]).arity != 1 # Ruby 2.7 and newer
11
+ # Starting from Ruby 2.7 we can address arbitrary bitranges inside an Integer with Integer#[]
12
+ # This allows to not allocate any Integer.
13
+ def self.to_msgpack_ext(bigint)
14
+ members = []
15
+
16
+ if bigint < 0
17
+ bigint = -bigint
18
+ members << 1
19
+ else
20
+ members << 0
21
+ end
22
+
23
+ offset = 0
24
+ length = bigint.bit_length
25
+ while offset < length
26
+ members << bigint[offset, CHUNK_BITLENGTH]
27
+ offset += CHUNK_BITLENGTH
28
+ end
29
+
30
+ members.pack(FORMAT)
31
+ end
32
+ else
33
+ # On 2.6 and older since we can't address arbitrary bitranges, so we fallback to shifting the bigint.
34
+ # This means that after each shift, we may allocate another Integer instance.
35
+ BASE = (2**CHUNK_BITLENGTH) - 1
36
+ def self.to_msgpack_ext(bigint)
37
+ members = []
38
+
39
+ if bigint < 0
40
+ bigint = -bigint
41
+ members << 1
42
+ else
43
+ members << 0
44
+ end
45
+
46
+ while bigint > 0
47
+ members << (bigint & BASE)
48
+ bigint = bigint >> CHUNK_BITLENGTH
49
+ end
50
+
51
+ members.pack(FORMAT)
52
+ end
53
+ end
54
+
55
+ def self.from_msgpack_ext(data)
56
+ parts = data.unpack(FORMAT)
57
+
58
+ sign = parts.shift
59
+ sum = parts.pop.to_i
60
+
61
+ parts.reverse_each do |part|
62
+ sum = sum << CHUNK_BITLENGTH
63
+ sum += part
64
+ end
65
+
66
+ sign == 0 ? sum : -sum
67
+ end
68
+ end
69
+ end