msgpack 1.7.5 → 1.8.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.
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: []