msgpack 1.7.5 → 1.8.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 78c1262c368e324ee566f27d3ba8ede06ef9f5ab7097ab9b2d92477f74801fd1
4
- data.tar.gz: f5cc9e68b8538eeb17a1ba8a8c6c4c68b14629fb1a5cb3d27ae9fc878a8fa09b
3
+ metadata.gz: efdb772bf54b74587a6c99e9513f9c16c78bbef3e5e3c17064a4be79fd5adb7a
4
+ data.tar.gz: d2f74cb1115947f5337cd730b6283fac61ceeed3a9457597cc90155b3dc93d7e
5
5
  SHA512:
6
- metadata.gz: d233e10a34114072598456ed08c42a0f16371bf3c8e5881ff05b73347d05e2da7356d2a7bfbc00b3dca130cdb72639b5f84f265ad2bc866905218a1503c8654c
7
- data.tar.gz: 97d5f302bd090099a99ca453032d32d4cefdf84835da1552f7fc6845063b1b45c047f67ada4cb637b884f6868d358d2f81b4c683eac5d04b701242e4f982a3e0
6
+ metadata.gz: 92da2466eac162f0d6d319496d7af3dbbef0d76b77c3aefb4787213e3b957464603859101ae28ac9620be82feb29278b2ed601adf2fd9d9811b364c258061d4b
7
+ data.tar.gz: a469586178eb44bbd50abf4cb34684f6a3fd4038063a80d9b3bf7f5cb9e6a2b34c1fed853be669f0bfb356d618efff3a2eaa51b86dd34d5427787a05453b8e11
data/ChangeLog CHANGED
@@ -1,3 +1,8 @@
1
+ 2025-02-06 1.8.0
2
+
3
+ * Numerous small optimizations.
4
+ * Added `key_cache` option to `Unpacker`.
5
+
1
6
  2024-11-11 1.7.5
2
7
 
3
8
  * Rerelease 1.7.4 with fixed java package.
data/ext/msgpack/buffer.c CHANGED
@@ -300,7 +300,7 @@ static inline void _msgpack_buffer_add_new_chunk(msgpack_buffer_t* b)
300
300
  static inline void _msgpack_buffer_append_reference(msgpack_buffer_t* b, VALUE string)
301
301
  {
302
302
  VALUE mapped_string;
303
- if(ENCODING_GET(string) == msgpack_rb_encindex_ascii8bit && RTEST(rb_obj_frozen_p(string))) {
303
+ if(ENCODING_GET_INLINED(string) == msgpack_rb_encindex_ascii8bit && RB_OBJ_FROZEN_RAW(string)) {
304
304
  mapped_string = string;
305
305
  } else {
306
306
  mapped_string = rb_str_dup(string);
@@ -309,8 +309,9 @@ static inline void _msgpack_buffer_append_reference(msgpack_buffer_t* b, VALUE s
309
309
 
310
310
  _msgpack_buffer_add_new_chunk(b);
311
311
 
312
- char* data = RSTRING_PTR(mapped_string);
313
- size_t length = RSTRING_LEN(mapped_string);
312
+ char* data;
313
+ size_t length;
314
+ RSTRING_GETMEM(mapped_string, data, length);
314
315
 
315
316
  b->tail.first = (char*) data;
316
317
  b->tail.last = (char*) data + length;
@@ -330,7 +331,7 @@ void _msgpack_buffer_append_long_string(msgpack_buffer_t* b, VALUE string)
330
331
  {
331
332
  if(b->io != Qnil) {
332
333
  msgpack_buffer_flush(b);
333
- if (ENCODING_GET(string) == msgpack_rb_encindex_ascii8bit) {
334
+ if (ENCODING_GET_INLINED(string) == msgpack_rb_encindex_ascii8bit) {
334
335
  rb_funcall(b->io, b->io_write_all_method, 1, string);
335
336
  } else {
336
337
  msgpack_buffer_append(b, RSTRING_PTR(string), RSTRING_LEN(string));
data/ext/msgpack/buffer.h CHANGED
@@ -237,13 +237,14 @@ void _msgpack_buffer_append_long_string(msgpack_buffer_t* b, VALUE string);
237
237
 
238
238
  static inline size_t msgpack_buffer_append_string(msgpack_buffer_t* b, VALUE string)
239
239
  {
240
- size_t length = RSTRING_LEN(string);
240
+ size_t length;
241
+ char *ptr;
242
+ RSTRING_GETMEM(string, ptr, length);
241
243
 
242
244
  if(length > b->write_reference_threshold) {
243
245
  _msgpack_buffer_append_long_string(b, string);
244
-
245
246
  } else {
246
- msgpack_buffer_append(b, RSTRING_PTR(string), length);
247
+ msgpack_buffer_append(b, ptr, length);
247
248
  }
248
249
 
249
250
  return length;
@@ -473,4 +474,131 @@ static inline VALUE msgpack_buffer_read_top_as_symbol(msgpack_buffer_t* b, size_
473
474
  return rb_str_intern(msgpack_buffer_read_top_as_string(b, length, true, utf8));
474
475
  }
475
476
 
477
+ // Hash keys are likely to be repeated, and are frozen.
478
+ // As such we can re-use them if we keep a cache of the ones we've seen so far,
479
+ // and save much more expensive lookups into the global fstring table.
480
+ // This cache implementation is deliberately simple, as we're optimizing for compactness,
481
+ // to be able to fit easily embeded inside msgpack_unpacker_t.
482
+ // As such, binary search into a sorted array gives a good tradeoff between compactness and
483
+ // performance.
484
+ #define MSGPACK_KEY_CACHE_CAPACITY 63
485
+
486
+ typedef struct msgpack_key_cache_t msgpack_key_cache_t;
487
+ struct msgpack_key_cache_t {
488
+ int length;
489
+ VALUE entries[MSGPACK_KEY_CACHE_CAPACITY];
490
+ };
491
+
492
+ static inline VALUE build_interned_string(const char *str, const long length)
493
+ {
494
+ # ifdef HAVE_RB_ENC_INTERNED_STR
495
+ return rb_enc_interned_str(str, length, rb_utf8_encoding());
496
+ # else
497
+ VALUE rstring = rb_utf8_str_new(str, length);
498
+ return rb_funcall(rb_str_freeze(rstring), s_uminus, 0);
499
+ # endif
500
+ }
501
+
502
+ static inline VALUE build_symbol(const char *str, const long length)
503
+ {
504
+ return rb_str_intern(build_interned_string(str, length));
505
+ }
506
+
507
+ static void rvalue_cache_insert_at(msgpack_key_cache_t *cache, int index, VALUE rstring)
508
+ {
509
+ MEMMOVE(&cache->entries[index + 1], &cache->entries[index], VALUE, cache->length - index);
510
+ cache->length++;
511
+ cache->entries[index] = rstring;
512
+ }
513
+
514
+ static inline int rstring_cache_cmp(const char *str, const long length, VALUE rstring)
515
+ {
516
+ long rstring_length = RSTRING_LEN(rstring);
517
+ if (length == rstring_length) {
518
+ return memcmp(str, RSTRING_PTR(rstring), length);
519
+ } else {
520
+ return (int)(length - rstring_length);
521
+ }
522
+ }
523
+
524
+ static VALUE rstring_cache_fetch(msgpack_key_cache_t *cache, const char *str, const long length)
525
+ {
526
+ int low = 0;
527
+ int high = cache->length - 1;
528
+ int mid = 0;
529
+ int last_cmp = 0;
530
+
531
+ while (low <= high) {
532
+ mid = (high + low) >> 1;
533
+ VALUE entry = cache->entries[mid];
534
+ last_cmp = rstring_cache_cmp(str, length, entry);
535
+
536
+ if (last_cmp == 0) {
537
+ return entry;
538
+ } else if (last_cmp > 0) {
539
+ low = mid + 1;
540
+ } else {
541
+ high = mid - 1;
542
+ }
543
+ }
544
+
545
+ VALUE rstring = build_interned_string(str, length);
546
+
547
+ if (cache->length < MSGPACK_KEY_CACHE_CAPACITY) {
548
+ if (last_cmp > 0) {
549
+ mid += 1;
550
+ }
551
+
552
+ rvalue_cache_insert_at(cache, mid, rstring);
553
+ }
554
+ return rstring;
555
+ }
556
+
557
+ static VALUE rsymbol_cache_fetch(msgpack_key_cache_t *cache, const char *str, const long length)
558
+ {
559
+ int low = 0;
560
+ int high = cache->length - 1;
561
+ int mid = 0;
562
+ int last_cmp = 0;
563
+
564
+ while (low <= high) {
565
+ mid = (high + low) >> 1;
566
+ VALUE entry = cache->entries[mid];
567
+ last_cmp = rstring_cache_cmp(str, length, rb_sym2str(entry));
568
+
569
+ if (last_cmp == 0) {
570
+ return entry;
571
+ } else if (last_cmp > 0) {
572
+ low = mid + 1;
573
+ } else {
574
+ high = mid - 1;
575
+ }
576
+ }
577
+
578
+ VALUE rsymbol = build_symbol(str, length);
579
+
580
+ if (cache->length < MSGPACK_KEY_CACHE_CAPACITY) {
581
+ if (last_cmp > 0) {
582
+ mid += 1;
583
+ }
584
+
585
+ rvalue_cache_insert_at(cache, mid, rsymbol);
586
+ }
587
+ return rsymbol;
588
+ }
589
+
590
+ static inline VALUE msgpack_buffer_read_top_as_interned_symbol(msgpack_buffer_t* b, msgpack_key_cache_t *cache, size_t length)
591
+ {
592
+ VALUE result = rsymbol_cache_fetch(cache, b->read_buffer, length);
593
+ _msgpack_buffer_consumed(b, length);
594
+ return result;
595
+ }
596
+
597
+ static inline VALUE msgpack_buffer_read_top_as_interned_string(msgpack_buffer_t* b, msgpack_key_cache_t *cache, size_t length)
598
+ {
599
+ VALUE result = rstring_cache_fetch(cache, b->read_buffer, length);
600
+ _msgpack_buffer_consumed(b, length);
601
+ return result;
602
+ }
603
+
476
604
  #endif
@@ -3,17 +3,19 @@ require 'mkmf'
3
3
  have_func("rb_enc_interned_str", "ruby.h") # Ruby 3.0+
4
4
  have_func("rb_hash_new_capa", "ruby.h") # Ruby 3.2+
5
5
  have_func("rb_proc_call_with_block", "ruby.h") # CRuby (TruffleRuby doesn't have it)
6
+ have_func("rb_gc_mark_locations", "ruby.h") # Missing on TruffleRuby
6
7
 
7
8
  append_cflags([
8
9
  "-fvisibility=hidden",
9
10
  "-I..",
10
11
  "-Wall",
11
- "-O3",
12
12
  "-std=gnu99"
13
13
  ])
14
- append_cflags(RbConfig::CONFIG["debugflags"]) if RbConfig::CONFIG["debugflags"]
15
14
 
16
- append_cflags("-DRUBY_DEBUG=1") if ENV["MSGPACK_DEBUG"]
15
+ if ENV["MSGPACK_DEBUG"]
16
+ append_cflags(RbConfig::CONFIG["debugflags"]) if RbConfig::CONFIG["debugflags"]
17
+ append_cflags("-DRUBY_DEBUG=1")
18
+ end
17
19
 
18
20
  if RUBY_VERSION.start_with?('3.0.') && RUBY_VERSION <= '3.0.5'
19
21
  # https://bugs.ruby-lang.org/issues/18772
data/ext/msgpack/packer.h CHANGED
@@ -25,6 +25,11 @@
25
25
  #define MSGPACK_PACKER_IO_FLUSH_THRESHOLD_TO_WRITE_STRING_BODY (1024)
26
26
  #endif
27
27
 
28
+ #ifndef UNREACHABLE_RETURN
29
+ // Ruby 2.5
30
+ #define UNREACHABLE_RETURN() return
31
+ #endif
32
+
28
33
  struct msgpack_packer_t;
29
34
  typedef struct msgpack_packer_t msgpack_packer_t;
30
35
 
@@ -404,27 +409,33 @@ static inline bool msgpack_packer_is_utf8_compat_string(VALUE v, int encindex)
404
409
  {
405
410
  return encindex == msgpack_rb_encindex_utf8
406
411
  || encindex == msgpack_rb_encindex_usascii
407
- || (rb_enc_asciicompat(rb_enc_from_index(encindex)) && ENC_CODERANGE_ASCIIONLY(v));
412
+ || ENC_CODERANGE_ASCIIONLY(v);
408
413
  }
409
414
 
410
415
  static inline void msgpack_packer_write_string_value(msgpack_packer_t* pk, VALUE v)
411
416
  {
412
- /* actual return type of RSTRING_LEN is long */
413
- unsigned long len = RSTRING_LEN(v);
414
- if(len > 0xffffffffUL) {
415
- // TODO rb_eArgError?
416
- rb_raise(rb_eArgError, "size of string is too long to pack: %lu bytes should be <= %lu", len, 0xffffffffUL);
417
+ long len = RSTRING_LEN(v);
418
+
419
+ if(RB_UNLIKELY(len > 0xffffffffL)) {
420
+ rb_raise(rb_eArgError, "size of string is too long to pack: %lu bytes should be <= %ld", len, 0xffffffffL);
421
+ UNREACHABLE_RETURN();
417
422
  }
418
423
 
419
- int encindex = ENCODING_GET(v);
420
- if(msgpack_packer_is_binary(v, encindex) && !pk->compatibility_mode) {
424
+ if (RB_UNLIKELY(pk->compatibility_mode)) {
425
+ msgpack_packer_write_raw_header(pk, (unsigned int)len);
426
+ msgpack_buffer_append_string(PACKER_BUFFER_(pk), v);
427
+ return;
428
+ }
429
+
430
+ int encindex = ENCODING_GET_INLINED(v);
431
+ if(msgpack_packer_is_binary(v, encindex)) {
421
432
  /* write ASCII-8BIT string using Binary type */
422
433
  msgpack_packer_write_bin_header(pk, (unsigned int)len);
423
434
  msgpack_buffer_append_string(PACKER_BUFFER_(pk), v);
424
435
  } else {
425
436
  /* write UTF-8, US-ASCII, or 7bit-safe ascii-compatible string using String type directly */
426
437
  /* in compatibility mode, packer packs String values as is */
427
- if(!pk->compatibility_mode && !msgpack_packer_is_utf8_compat_string(v, encindex)) {
438
+ if(RB_UNLIKELY(!msgpack_packer_is_utf8_compat_string(v, encindex))) {
428
439
  /* transcode other strings to UTF-8 and write using String type */
429
440
  VALUE enc = rb_enc_from_encoding(rb_utf8_encoding()); /* rb_enc_from_encoding_index is not extern */
430
441
  v = rb_str_encode(v, enc, 0, Qnil);
@@ -453,11 +464,7 @@ static inline void msgpack_packer_write_symbol_value(msgpack_packer_t* pk, VALUE
453
464
 
454
465
  static inline void msgpack_packer_write_fixnum_value(msgpack_packer_t* pk, VALUE v)
455
466
  {
456
- #ifdef JRUBY
457
- msgpack_packer_write_long(pk, FIXNUM_P(v) ? FIX2LONG(v) : rb_num2ll(v));
458
- #else
459
467
  msgpack_packer_write_long(pk, FIX2LONG(v));
460
- #endif
461
468
  }
462
469
 
463
470
  static inline void msgpack_packer_write_bignum_value(msgpack_packer_t* pk, VALUE v)
@@ -26,6 +26,19 @@
26
26
  #define rb_proc_call_with_block(recv, argc, argv, block) rb_funcallv(recv, rb_intern("call"), argc, argv)
27
27
  #endif
28
28
 
29
+ #ifndef HAVE_RB_GC_MARK_LOCATIONS
30
+ // For TruffleRuby
31
+ void rb_gc_mark_locations(const VALUE *start, const VALUE *end)
32
+ {
33
+ VALUE *value = start;
34
+
35
+ while (value < end) {
36
+ rb_gc_mark(*value);
37
+ value++;
38
+ }
39
+ }
40
+ #endif
41
+
29
42
  struct protected_proc_call_args {
30
43
  VALUE proc;
31
44
  int argc;
@@ -79,11 +92,29 @@ void msgpack_unpacker_static_destroy(void)
79
92
 
80
93
  #define HEAD_BYTE_REQUIRED 0xc1
81
94
 
82
- static inline void _msgpack_unpacker_stack_init(msgpack_unpacker_stack_t *stack) {
83
- stack->capacity = MSGPACK_UNPACKER_STACK_CAPACITY;
84
- stack->data = msgpack_rmem_alloc(&s_stack_rmem);
95
+ static inline bool _msgpack_unpacker_stack_init(msgpack_unpacker_stack_t *stack) {
96
+ if (!stack->data) {
97
+ stack->capacity = MSGPACK_UNPACKER_STACK_CAPACITY;
98
+ stack->data = msgpack_rmem_alloc(&s_stack_rmem);
99
+ stack->depth = 0;
100
+ return true;
101
+ }
102
+ return false;
85
103
  }
86
104
 
105
+ static inline void _msgpack_unpacker_free_stack(msgpack_unpacker_stack_t* stack) {
106
+ if (stack->data) {
107
+ if (!msgpack_rmem_free(&s_stack_rmem, stack->data)) {
108
+ rb_bug("Failed to free an rmem pointer, memory leak?");
109
+ }
110
+ stack->data = NULL;
111
+ stack->depth = 0;
112
+ }
113
+ }
114
+
115
+ #define STACK_INIT(uk) bool stack_allocated = _msgpack_unpacker_stack_init(&uk->stack);
116
+ #define STACK_FREE(uk) if (stack_allocated) { _msgpack_unpacker_free_stack(&uk->stack); }
117
+
87
118
  void _msgpack_unpacker_init(msgpack_unpacker_t* uk)
88
119
  {
89
120
  msgpack_buffer_init(UNPACKER_BUFFER_(uk));
@@ -92,16 +123,6 @@ void _msgpack_unpacker_init(msgpack_unpacker_t* uk)
92
123
 
93
124
  uk->last_object = Qnil;
94
125
  uk->reading_raw = Qnil;
95
-
96
- _msgpack_unpacker_stack_init(&uk->stack);
97
- }
98
-
99
- static inline void _msgpack_unpacker_free_stack(msgpack_unpacker_stack_t* stack) {
100
- if (!msgpack_rmem_free(&s_stack_rmem, stack->data)) {
101
- rb_bug("Failed to free an rmem pointer, memory leak?");
102
- }
103
- stack->data = NULL;
104
- stack->depth = 0;
105
126
  }
106
127
 
107
128
  void _msgpack_unpacker_destroy(msgpack_unpacker_t* uk)
@@ -122,11 +143,18 @@ void msgpack_unpacker_mark_stack(msgpack_unpacker_stack_t* stack)
122
143
  }
123
144
  }
124
145
 
146
+ void msgpack_unpacker_mark_key_cache(msgpack_key_cache_t *cache)
147
+ {
148
+ const VALUE *entries = &cache->entries[0];
149
+ rb_gc_mark_locations(entries, entries + cache->length);
150
+ }
151
+
125
152
  void msgpack_unpacker_mark(msgpack_unpacker_t* uk)
126
153
  {
127
154
  rb_gc_mark(uk->last_object);
128
155
  rb_gc_mark(uk->reading_raw);
129
156
  msgpack_unpacker_mark_stack(&uk->stack);
157
+ msgpack_unpacker_mark_key_cache(&uk->key_cache);
130
158
  /* See MessagePack_Buffer_wrap */
131
159
  /* msgpack_buffer_mark(UNPACKER_BUFFER_(uk)); */
132
160
  rb_gc_mark(uk->buffer_ref);
@@ -366,15 +394,32 @@ static inline int read_raw_body_begin(msgpack_unpacker_t* uk, int raw_type)
366
394
  size_t length = uk->reading_raw_remaining;
367
395
  if(length <= msgpack_buffer_top_readable_size(UNPACKER_BUFFER_(uk))) {
368
396
  int ret;
369
- if ((uk->optimized_symbol_ext_type && uk->symbol_ext_type == raw_type) || (uk->symbolize_keys && is_reading_map_key(uk))) {
397
+ if ((uk->optimized_symbol_ext_type && uk->symbol_ext_type == raw_type)) {
370
398
  VALUE symbol = msgpack_buffer_read_top_as_symbol(UNPACKER_BUFFER_(uk), length, raw_type != RAW_TYPE_BINARY);
371
399
  ret = object_complete_symbol(uk, symbol);
400
+ } else if (is_reading_map_key(uk) && raw_type == RAW_TYPE_STRING) {
401
+ /* don't use zerocopy for hash keys but get a frozen string directly
402
+ * because rb_hash_aset freezes keys and it causes copying */
403
+ VALUE key;
404
+ if (uk->symbolize_keys) {
405
+ if (uk->use_key_cache) {
406
+ key = msgpack_buffer_read_top_as_interned_symbol(UNPACKER_BUFFER_(uk), &uk->key_cache, length);
407
+ } else {
408
+ key = msgpack_buffer_read_top_as_symbol(UNPACKER_BUFFER_(uk), length, true);
409
+ }
410
+ ret = object_complete_symbol(uk, key);
411
+ } else {
412
+ if (uk->use_key_cache) {
413
+ key = msgpack_buffer_read_top_as_interned_string(UNPACKER_BUFFER_(uk), &uk->key_cache, length);
414
+ } else {
415
+ key = msgpack_buffer_read_top_as_string(UNPACKER_BUFFER_(uk), length, true, true);
416
+ }
417
+
418
+ ret = object_complete(uk, key);
419
+ }
372
420
  } else {
373
421
  bool will_freeze = uk->freeze;
374
422
  if(raw_type == RAW_TYPE_STRING || raw_type == RAW_TYPE_BINARY) {
375
- /* don't use zerocopy for hash keys but get a frozen string directly
376
- * because rb_hash_aset freezes keys and it causes copying */
377
- will_freeze = will_freeze || is_reading_map_key(uk);
378
423
  VALUE string = msgpack_buffer_read_top_as_string(UNPACKER_BUFFER_(uk), length, will_freeze, raw_type == RAW_TYPE_STRING);
379
424
  ret = object_complete(uk, string);
380
425
  } else {
@@ -750,9 +795,15 @@ int msgpack_unpacker_read_map_header(msgpack_unpacker_t* uk, uint32_t* result_si
750
795
 
751
796
  int msgpack_unpacker_read(msgpack_unpacker_t* uk, size_t target_stack_depth)
752
797
  {
798
+ STACK_INIT(uk);
799
+
753
800
  while(true) {
754
801
  int r = read_primitive(uk);
755
802
  if(r < 0) {
803
+ if (r != PRIMITIVE_EOF) {
804
+ // We keep the stack on EOF as the parsing may be resumed.
805
+ STACK_FREE(uk);
806
+ }
756
807
  return r;
757
808
  }
758
809
  if(r == PRIMITIVE_CONTAINER_START) {
@@ -761,6 +812,7 @@ int msgpack_unpacker_read(msgpack_unpacker_t* uk, size_t target_stack_depth)
761
812
  /* PRIMITIVE_OBJECT_COMPLETE */
762
813
 
763
814
  if(msgpack_unpacker_stack_is_empty(uk)) {
815
+ STACK_FREE(uk);
764
816
  return PRIMITIVE_OBJECT_COMPLETE;
765
817
  }
766
818
 
@@ -785,6 +837,7 @@ int msgpack_unpacker_read(msgpack_unpacker_t* uk, size_t target_stack_depth)
785
837
  top->type = STACK_TYPE_MAP_KEY;
786
838
  break;
787
839
  case STACK_TYPE_RECURSIVE:
840
+ STACK_FREE(uk);
788
841
  return PRIMITIVE_OBJECT_COMPLETE;
789
842
  }
790
843
  size_t count = --top->count;
@@ -792,6 +845,7 @@ int msgpack_unpacker_read(msgpack_unpacker_t* uk, size_t target_stack_depth)
792
845
  if(count == 0) {
793
846
  object_complete(uk, top->object);
794
847
  if(msgpack_unpacker_stack_pop(uk) <= target_stack_depth) {
848
+ STACK_FREE(uk);
795
849
  return PRIMITIVE_OBJECT_COMPLETE;
796
850
  }
797
851
  goto container_completed;
@@ -802,9 +856,12 @@ int msgpack_unpacker_read(msgpack_unpacker_t* uk, size_t target_stack_depth)
802
856
 
803
857
  int msgpack_unpacker_skip(msgpack_unpacker_t* uk, size_t target_stack_depth)
804
858
  {
859
+ STACK_INIT(uk);
860
+
805
861
  while(true) {
806
862
  int r = read_primitive(uk);
807
863
  if(r < 0) {
864
+ STACK_FREE(uk);
808
865
  return r;
809
866
  }
810
867
  if(r == PRIMITIVE_CONTAINER_START) {
@@ -813,6 +870,7 @@ int msgpack_unpacker_skip(msgpack_unpacker_t* uk, size_t target_stack_depth)
813
870
  /* PRIMITIVE_OBJECT_COMPLETE */
814
871
 
815
872
  if(msgpack_unpacker_stack_is_empty(uk)) {
873
+ STACK_FREE(uk);
816
874
  return PRIMITIVE_OBJECT_COMPLETE;
817
875
  }
818
876
 
@@ -828,6 +886,7 @@ int msgpack_unpacker_skip(msgpack_unpacker_t* uk, size_t target_stack_depth)
828
886
  if(count == 0) {
829
887
  object_complete(uk, Qnil);
830
888
  if(msgpack_unpacker_stack_pop(uk) <= target_stack_depth) {
889
+ STACK_FREE(uk);
831
890
  return PRIMITIVE_OBJECT_COMPLETE;
832
891
  }
833
892
  goto container_completed;
@@ -50,6 +50,7 @@ struct msgpack_unpacker_stack_t {
50
50
  struct msgpack_unpacker_t {
51
51
  msgpack_buffer_t buffer;
52
52
  msgpack_unpacker_stack_t stack;
53
+ msgpack_key_cache_t key_cache;
53
54
 
54
55
  VALUE self;
55
56
  VALUE last_object;
@@ -66,10 +67,12 @@ struct msgpack_unpacker_t {
66
67
 
67
68
  /* options */
68
69
  int symbol_ext_type;
69
- bool symbolize_keys;
70
- bool freeze;
71
- bool allow_unknown_ext;
72
- bool optimized_symbol_ext_type;
70
+
71
+ bool use_key_cache: 1;
72
+ bool symbolize_keys: 1;
73
+ bool freeze: 1;
74
+ bool allow_unknown_ext: 1;
75
+ bool optimized_symbol_ext_type: 1;
73
76
  };
74
77
 
75
78
  #define UNPACKER_BUFFER_(uk) (&(uk)->buffer)
@@ -101,6 +104,11 @@ static inline void msgpack_unpacker_set_symbolized_keys(msgpack_unpacker_t* uk,
101
104
  uk->symbolize_keys = enable;
102
105
  }
103
106
 
107
+ static inline void msgpack_unpacker_set_key_cache(msgpack_unpacker_t* uk, bool enable)
108
+ {
109
+ uk->use_key_cache = enable;
110
+ }
111
+
104
112
  static inline void msgpack_unpacker_set_freeze(msgpack_unpacker_t* uk, bool enable)
105
113
  {
106
114
  uk->freeze = enable;
@@ -34,6 +34,7 @@ static VALUE eUnknownExtTypeError;
34
34
  static VALUE mTypeError; // obsoleted. only for backward compatibility. See #86.
35
35
 
36
36
  static VALUE sym_symbolize_keys;
37
+ static VALUE sym_key_cache;
37
38
  static VALUE sym_freeze;
38
39
  static VALUE sym_allow_unknown_ext;
39
40
 
@@ -128,6 +129,9 @@ VALUE MessagePack_Unpacker_initialize(int argc, VALUE* argv, VALUE self)
128
129
  if(options != Qnil) {
129
130
  VALUE v;
130
131
 
132
+ v = rb_hash_aref(options, sym_key_cache);
133
+ msgpack_unpacker_set_key_cache(uk, RTEST(v));
134
+
131
135
  v = rb_hash_aref(options, sym_symbolize_keys);
132
136
  msgpack_unpacker_set_symbolized_keys(uk, RTEST(v));
133
137
 
@@ -284,12 +288,6 @@ static VALUE Unpacker_each_impl(VALUE self)
284
288
  raise_unpacker_error(uk, r);
285
289
  }
286
290
  VALUE v = msgpack_unpacker_get_last_object(uk);
287
- #ifdef JRUBY
288
- /* TODO JRuby's rb_yield behaves differently from Ruby 1.9.3 or Rubinius. */
289
- if(rb_type(v) == T_ARRAY) {
290
- v = rb_ary_new3(1, v);
291
- }
292
- #endif
293
291
  rb_yield(v);
294
292
  }
295
293
  }
@@ -419,6 +417,7 @@ void MessagePack_Unpacker_module_init(VALUE mMessagePack)
419
417
  eUnknownExtTypeError = rb_define_class_under(mMessagePack, "UnknownExtTypeError", eUnpackError);
420
418
 
421
419
  sym_symbolize_keys = ID2SYM(rb_intern("symbolize_keys"));
420
+ sym_key_cache = ID2SYM(rb_intern("key_cache"));
422
421
  sym_freeze = ID2SYM(rb_intern("freeze"));
423
422
  sym_allow_unknown_ext = ID2SYM(rb_intern("allow_unknown_ext"));
424
423
 
@@ -1,5 +1,5 @@
1
1
  module MessagePack
2
- VERSION = "1.7.5"
2
+ VERSION = "1.8.0"
3
3
  # Note for maintainers:
4
4
  # Don't miss building/releasing the JRuby version (rake buld:java)
5
5
  # See "How to build -java rubygems" in README for more details.
data/msgpack.gemspec CHANGED
@@ -31,4 +31,6 @@ Gem::Specification.new do |s|
31
31
  s.add_development_dependency 'yard'
32
32
  s.add_development_dependency 'json'
33
33
  s.add_development_dependency 'benchmark-ips', ['~> 2.10.0']
34
+
35
+ s.metadata["changelog_uri"] = "https://github.com/msgpack/msgpack-ruby/blob/master/ChangeLog"
34
36
  end
metadata CHANGED
@@ -1,16 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: msgpack
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.7.5
4
+ version: 1.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sadayuki Furuhashi
8
8
  - Theo Hultberg
9
9
  - Satoshi Tagomori
10
- autorequire:
11
10
  bindir: bin
12
11
  cert_chain: []
13
- date: 2024-11-11 00:00:00.000000000 Z
12
+ date: 2025-02-06 00:00:00.000000000 Z
14
13
  dependencies:
15
14
  - !ruby/object:Gem::Dependency
16
15
  name: bundler
@@ -192,8 +191,8 @@ files:
192
191
  homepage: http://msgpack.org/
193
192
  licenses:
194
193
  - Apache 2.0
195
- metadata: {}
196
- post_install_message:
194
+ metadata:
195
+ changelog_uri: https://github.com/msgpack/msgpack-ruby/blob/master/ChangeLog
197
196
  rdoc_options: []
198
197
  require_paths:
199
198
  - lib
@@ -208,8 +207,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
208
207
  - !ruby/object:Gem::Version
209
208
  version: '0'
210
209
  requirements: []
211
- rubygems_version: 3.5.11
212
- signing_key:
210
+ rubygems_version: 3.6.2
213
211
  specification_version: 4
214
212
  summary: MessagePack, a binary-based efficient data interchange format.
215
213
  test_files: []