msgpack 1.5.6 → 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.
Files changed (81) hide show
  1. checksums.yaml +4 -4
  2. data/ChangeLog +50 -0
  3. data/README.md +48 -12
  4. data/ext/java/org/msgpack/jruby/Buffer.java +3 -3
  5. data/ext/java/org/msgpack/jruby/ExtensionRegistry.java +11 -20
  6. data/ext/java/org/msgpack/jruby/ExtensionValue.java +1 -1
  7. data/ext/java/org/msgpack/jruby/Factory.java +11 -50
  8. data/ext/java/org/msgpack/jruby/Packer.java +9 -24
  9. data/ext/java/org/msgpack/jruby/Unpacker.java +15 -32
  10. data/ext/msgpack/buffer.c +69 -56
  11. data/ext/msgpack/buffer.h +138 -44
  12. data/ext/msgpack/buffer_class.c +132 -31
  13. data/ext/msgpack/buffer_class.h +1 -0
  14. data/ext/msgpack/extconf.rb +20 -30
  15. data/ext/msgpack/factory_class.c +75 -86
  16. data/ext/msgpack/packer.c +13 -16
  17. data/ext/msgpack/packer.h +24 -21
  18. data/ext/msgpack/packer_class.c +72 -98
  19. data/ext/msgpack/packer_class.h +11 -0
  20. data/ext/msgpack/packer_ext_registry.c +31 -28
  21. data/ext/msgpack/packer_ext_registry.h +10 -14
  22. data/ext/msgpack/rbinit.c +1 -1
  23. data/ext/msgpack/rmem.c +3 -4
  24. data/ext/msgpack/sysdep.h +5 -2
  25. data/ext/msgpack/unpacker.c +201 -113
  26. data/ext/msgpack/unpacker.h +22 -15
  27. data/ext/msgpack/unpacker_class.c +87 -92
  28. data/ext/msgpack/unpacker_class.h +11 -0
  29. data/ext/msgpack/unpacker_ext_registry.c +4 -16
  30. data/ext/msgpack/unpacker_ext_registry.h +3 -7
  31. data/lib/msgpack/buffer.rb +9 -0
  32. data/lib/msgpack/factory.rb +90 -63
  33. data/lib/msgpack/packer.rb +10 -1
  34. data/lib/msgpack/unpacker.rb +14 -1
  35. data/lib/msgpack/version.rb +1 -1
  36. data/lib/msgpack.rb +1 -0
  37. data/msgpack.gemspec +8 -3
  38. metadata +21 -51
  39. data/.github/workflows/ci.yaml +0 -57
  40. data/.gitignore +0 -23
  41. data/.rubocop.yml +0 -36
  42. data/Gemfile +0 -9
  43. data/Rakefile +0 -70
  44. data/appveyor.yml +0 -18
  45. data/bench/bench.rb +0 -78
  46. data/doclib/msgpack/buffer.rb +0 -193
  47. data/doclib/msgpack/core_ext.rb +0 -101
  48. data/doclib/msgpack/error.rb +0 -19
  49. data/doclib/msgpack/extension_value.rb +0 -9
  50. data/doclib/msgpack/factory.rb +0 -145
  51. data/doclib/msgpack/packer.rb +0 -209
  52. data/doclib/msgpack/time.rb +0 -22
  53. data/doclib/msgpack/timestamp.rb +0 -44
  54. data/doclib/msgpack/unpacker.rb +0 -183
  55. data/doclib/msgpack.rb +0 -87
  56. data/msgpack.org.md +0 -46
  57. data/spec/bigint_spec.rb +0 -26
  58. data/spec/cases.json +0 -1
  59. data/spec/cases.msg +0 -0
  60. data/spec/cases_compact.msg +0 -0
  61. data/spec/cases_spec.rb +0 -39
  62. data/spec/cruby/buffer_io_spec.rb +0 -255
  63. data/spec/cruby/buffer_packer.rb +0 -29
  64. data/spec/cruby/buffer_spec.rb +0 -575
  65. data/spec/cruby/buffer_unpacker.rb +0 -19
  66. data/spec/cruby/unpacker_spec.rb +0 -70
  67. data/spec/ext_value_spec.rb +0 -99
  68. data/spec/exttypes.rb +0 -51
  69. data/spec/factory_spec.rb +0 -688
  70. data/spec/format_spec.rb +0 -301
  71. data/spec/jruby/benchmarks/shootout_bm.rb +0 -73
  72. data/spec/jruby/benchmarks/symbolize_keys_bm.rb +0 -25
  73. data/spec/jruby/unpacker_spec.rb +0 -186
  74. data/spec/msgpack_spec.rb +0 -214
  75. data/spec/pack_spec.rb +0 -61
  76. data/spec/packer_spec.rb +0 -575
  77. data/spec/random_compat.rb +0 -24
  78. data/spec/spec_helper.rb +0 -71
  79. data/spec/timestamp_spec.rb +0 -159
  80. data/spec/unpack_spec.rb +0 -57
  81. data/spec/unpacker_spec.rb +0 -859
data/ext/msgpack/buffer.c CHANGED
@@ -19,21 +19,15 @@
19
19
  #include "buffer.h"
20
20
  #include "rmem.h"
21
21
 
22
- #ifndef HAVE_RB_STR_REPLACE
23
- static ID s_replace;
24
- #endif
25
-
26
22
  int msgpack_rb_encindex_utf8;
27
23
  int msgpack_rb_encindex_usascii;
28
24
  int msgpack_rb_encindex_ascii8bit;
29
25
 
30
26
  ID s_uminus;
31
27
 
32
- #ifndef DISABLE_RMEM
33
28
  static msgpack_rmem_t s_rmem;
34
- #endif
35
29
 
36
- void msgpack_buffer_static_init()
30
+ void msgpack_buffer_static_init(void)
37
31
  {
38
32
  s_uminus = rb_intern("-@");
39
33
 
@@ -41,20 +35,12 @@ void msgpack_buffer_static_init()
41
35
  msgpack_rb_encindex_usascii = rb_usascii_encindex();
42
36
  msgpack_rb_encindex_ascii8bit = rb_ascii8bit_encindex();
43
37
 
44
- #ifndef DISABLE_RMEM
45
38
  msgpack_rmem_init(&s_rmem);
46
- #endif
47
-
48
- #ifndef HAVE_RB_STR_REPLACE
49
- s_replace = rb_intern("replace");
50
- #endif
51
39
  }
52
40
 
53
- void msgpack_buffer_static_destroy()
41
+ void msgpack_buffer_static_destroy(void)
54
42
  {
55
- #ifndef DISABLE_RMEM
56
43
  msgpack_rmem_destroy(&s_rmem);
57
- #endif
58
44
  }
59
45
 
60
46
  void msgpack_buffer_init(msgpack_buffer_t* b)
@@ -72,16 +58,16 @@ void msgpack_buffer_init(msgpack_buffer_t* b)
72
58
  static void _msgpack_buffer_chunk_destroy(msgpack_buffer_chunk_t* c)
73
59
  {
74
60
  if(c->mem != NULL) {
75
- #ifndef DISABLE_RMEM
76
- if(!msgpack_rmem_free(&s_rmem, c->mem)) {
61
+ if(c->rmem) {
62
+ if(!msgpack_rmem_free(&s_rmem, c->mem)) {
63
+ rb_bug("Failed to free an rmem pointer, memory leak?");
64
+ }
65
+ } else {
77
66
  xfree(c->mem);
78
67
  }
79
68
  /* no needs to update rmem_owner because chunks will not be
80
69
  * free()ed (left in free_list) and thus *rmem_owner is
81
70
  * always valid. */
82
- #else
83
- xfree(c->mem);
84
- #endif
85
71
  }
86
72
  c->first = NULL;
87
73
  c->last = NULL;
@@ -108,8 +94,25 @@ void msgpack_buffer_destroy(msgpack_buffer_t* b)
108
94
  }
109
95
  }
110
96
 
111
- void msgpack_buffer_mark(msgpack_buffer_t* b)
97
+ size_t msgpack_buffer_memsize(const msgpack_buffer_t* b)
98
+ {
99
+ size_t memsize = 0;
100
+ msgpack_buffer_chunk_t* c = b->head;
101
+
102
+ while(c) {
103
+ memsize += sizeof(msgpack_buffer_chunk_t);
104
+ if(c->mapped_string != NO_MAPPED_STRING) {
105
+ memsize += (c->last - c->first);
106
+ }
107
+ c = c->next;
108
+ }
109
+
110
+ return memsize;
111
+ }
112
+
113
+ void msgpack_buffer_mark(void *ptr)
112
114
  {
115
+ msgpack_buffer_t* b = ptr;
113
116
  /* head is always available */
114
117
  msgpack_buffer_chunk_t* c = b->head;
115
118
  while(c != &b->tail) {
@@ -120,8 +123,6 @@ void msgpack_buffer_mark(msgpack_buffer_t* b)
120
123
 
121
124
  rb_gc_mark(b->io);
122
125
  rb_gc_mark(b->io_buffer);
123
-
124
- rb_gc_mark(b->owner);
125
126
  }
126
127
 
127
128
  bool _msgpack_buffer_shift_chunk(msgpack_buffer_t* b)
@@ -158,7 +159,6 @@ size_t msgpack_buffer_read_to_string_nonblock(msgpack_buffer_t* b, VALUE string,
158
159
  {
159
160
  size_t avail = msgpack_buffer_top_readable_size(b);
160
161
 
161
- #ifndef DISABLE_BUFFER_READ_REFERENCE_OPTIMIZE
162
162
  /* optimize */
163
163
  if(length <= avail && RSTRING_LEN(string) == 0 &&
164
164
  b->head->mapped_string != NO_MAPPED_STRING &&
@@ -170,7 +170,6 @@ size_t msgpack_buffer_read_to_string_nonblock(msgpack_buffer_t* b, VALUE string,
170
170
  _msgpack_buffer_consumed(b, length);
171
171
  return length;
172
172
  }
173
- #endif
174
173
 
175
174
  size_t const length_orig = length;
176
175
 
@@ -252,12 +251,14 @@ bool _msgpack_buffer_read_all2(msgpack_buffer_t* b, char* buffer, size_t length)
252
251
 
253
252
  static inline msgpack_buffer_chunk_t* _msgpack_buffer_alloc_new_chunk(msgpack_buffer_t* b)
254
253
  {
255
- msgpack_buffer_chunk_t* reuse = b->free_list;
256
- if(reuse == NULL) {
257
- return xmalloc(sizeof(msgpack_buffer_chunk_t));
254
+ msgpack_buffer_chunk_t* chunk = b->free_list;
255
+ if (chunk) {
256
+ b->free_list = b->free_list->next;
257
+ } else {
258
+ chunk = xmalloc(sizeof(msgpack_buffer_chunk_t));
258
259
  }
259
- b->free_list = b->free_list->next;
260
- return reuse;
260
+ memset(chunk, 0, sizeof(msgpack_buffer_chunk_t));
261
+ return chunk;
261
262
  }
262
263
 
263
264
  static inline void _msgpack_buffer_add_new_chunk(msgpack_buffer_t* b)
@@ -283,15 +284,11 @@ static inline void _msgpack_buffer_add_new_chunk(msgpack_buffer_t* b)
283
284
 
284
285
  msgpack_buffer_chunk_t* nc = _msgpack_buffer_alloc_new_chunk(b);
285
286
 
286
- #ifndef DISABLE_RMEM
287
- #ifndef DISABLE_RMEM_REUSE_INTERNAL_FRAGMENT
288
287
  if(b->rmem_last == b->tail_buffer_end) {
289
288
  /* reuse unused rmem space */
290
289
  size_t unused = b->tail_buffer_end - b->tail.last;
291
290
  b->rmem_last -= unused;
292
291
  }
293
- #endif
294
- #endif
295
292
 
296
293
  /* rebuild tail */
297
294
  *nc = b->tail;
@@ -300,19 +297,47 @@ static inline void _msgpack_buffer_add_new_chunk(msgpack_buffer_t* b)
300
297
  }
301
298
  }
302
299
 
303
- void _msgpack_buffer_append_long_string(msgpack_buffer_t* b, VALUE string)
300
+ static inline void _msgpack_buffer_append_reference(msgpack_buffer_t* b, VALUE string)
304
301
  {
305
- size_t length = RSTRING_LEN(string);
302
+ VALUE mapped_string;
303
+ if(ENCODING_GET_INLINED(string) == msgpack_rb_encindex_ascii8bit && RB_OBJ_FROZEN_RAW(string)) {
304
+ mapped_string = string;
305
+ } else {
306
+ mapped_string = rb_str_dup(string);
307
+ ENCODING_SET(mapped_string, msgpack_rb_encindex_ascii8bit);
308
+ }
309
+
310
+ _msgpack_buffer_add_new_chunk(b);
311
+
312
+ char* data;
313
+ size_t length;
314
+ RSTRING_GETMEM(mapped_string, data, length);
306
315
 
316
+ b->tail.first = (char*) data;
317
+ b->tail.last = (char*) data + length;
318
+ b->tail.mapped_string = mapped_string;
319
+ b->tail.mem = NULL;
320
+
321
+ /* msgpack_buffer_writable_size should return 0 for mapped chunk */
322
+ b->tail_buffer_end = b->tail.last;
323
+
324
+ /* consider read_buffer */
325
+ if(b->head == &b->tail) {
326
+ b->read_buffer = b->tail.first;
327
+ }
328
+ }
329
+
330
+ void _msgpack_buffer_append_long_string(msgpack_buffer_t* b, VALUE string)
331
+ {
307
332
  if(b->io != Qnil) {
308
333
  msgpack_buffer_flush(b);
309
- if (ENCODING_GET(string) == msgpack_rb_encindex_ascii8bit) {
334
+ if (ENCODING_GET_INLINED(string) == msgpack_rb_encindex_ascii8bit) {
310
335
  rb_funcall(b->io, b->io_write_all_method, 1, string);
311
336
  } else {
312
- msgpack_buffer_append(b, RSTRING_PTR(string), length);
337
+ msgpack_buffer_append(b, RSTRING_PTR(string), RSTRING_LEN(string));
313
338
  }
314
339
  } else {
315
- msgpack_buffer_append(b, RSTRING_PTR(string), length);
340
+ _msgpack_buffer_append_reference(b, string);
316
341
  }
317
342
  }
318
343
 
@@ -320,11 +345,10 @@ static inline void* _msgpack_buffer_chunk_malloc(
320
345
  msgpack_buffer_t* b, msgpack_buffer_chunk_t* c,
321
346
  size_t required_size, size_t* allocated_size)
322
347
  {
323
- #ifndef DISABLE_RMEM
324
348
  if(required_size <= MSGPACK_RMEM_PAGE_SIZE) {
325
- #ifndef DISABLE_RMEM_REUSE_INTERNAL_FRAGMENT
349
+ c->rmem = true;
350
+
326
351
  if((size_t)(b->rmem_end - b->rmem_last) < required_size) {
327
- #endif
328
352
  /* alloc new rmem page */
329
353
  *allocated_size = MSGPACK_RMEM_PAGE_SIZE;
330
354
  char* buffer = msgpack_rmem_alloc(&s_rmem);
@@ -335,8 +359,6 @@ static inline void* _msgpack_buffer_chunk_malloc(
335
359
  b->rmem_last = b->rmem_end = buffer + MSGPACK_RMEM_PAGE_SIZE;
336
360
 
337
361
  return buffer;
338
-
339
- #ifndef DISABLE_RMEM_REUSE_INTERNAL_FRAGMENT
340
362
  } else {
341
363
  /* reuse unused rmem */
342
364
  *allocated_size = (size_t)(b->rmem_end - b->rmem_last);
@@ -350,18 +372,13 @@ static inline void* _msgpack_buffer_chunk_malloc(
350
372
 
351
373
  return buffer;
352
374
  }
353
- #endif
354
- }
355
- #else
356
- if(required_size < 72) {
357
- required_size = 72;
358
375
  }
359
- #endif
360
376
 
361
377
  // TODO alignment?
362
378
  *allocated_size = required_size;
363
379
  void* mem = xmalloc(required_size);
364
380
  c->mem = mem;
381
+ c->rmem = false;
365
382
  return mem;
366
383
  }
367
384
 
@@ -411,11 +428,7 @@ void _msgpack_buffer_expand(msgpack_buffer_t* b, const char* data, size_t length
411
428
  size_t capacity = b->tail.last - b->tail.first;
412
429
 
413
430
  /* can't realloc mapped chunk or rmem page */
414
- if(b->tail.mapped_string != NO_MAPPED_STRING
415
- #ifndef DISABLE_RMEM
416
- || capacity <= MSGPACK_RMEM_PAGE_SIZE
417
- #endif
418
- ) {
431
+ if(b->tail.mapped_string != NO_MAPPED_STRING || capacity <= MSGPACK_RMEM_PAGE_SIZE) {
419
432
  /* allocate new chunk */
420
433
  _msgpack_buffer_add_new_chunk(b);
421
434
 
data/ext/msgpack/buffer.h CHANGED
@@ -78,20 +78,7 @@ struct msgpack_buffer_chunk_t {
78
78
  void* mem;
79
79
  msgpack_buffer_chunk_t* next;
80
80
  VALUE mapped_string; /* RBString or NO_MAPPED_STRING */
81
- };
82
-
83
- union msgpack_buffer_cast_block_t {
84
- char buffer[8];
85
- uint8_t u8;
86
- uint16_t u16;
87
- uint32_t u32;
88
- uint64_t u64;
89
- int8_t i8;
90
- int16_t i16;
91
- int32_t i32;
92
- int64_t i64;
93
- float f;
94
- double d;
81
+ bool rmem;
95
82
  };
96
83
 
97
84
  struct msgpack_buffer_t {
@@ -102,13 +89,9 @@ struct msgpack_buffer_t {
102
89
  msgpack_buffer_chunk_t* head;
103
90
  msgpack_buffer_chunk_t* free_list;
104
91
 
105
- #ifndef DISABLE_RMEM
106
92
  char* rmem_last;
107
93
  char* rmem_end;
108
94
  void** rmem_owner;
109
- #endif
110
-
111
- union msgpack_buffer_cast_block_t cast_block;
112
95
 
113
96
  VALUE io;
114
97
  VALUE io_buffer;
@@ -118,25 +101,25 @@ struct msgpack_buffer_t {
118
101
  size_t write_reference_threshold;
119
102
  size_t read_reference_threshold;
120
103
  size_t io_buffer_size;
121
-
122
- VALUE owner;
123
104
  };
124
105
 
125
106
  /*
126
107
  * initialization functions
127
108
  */
128
- void msgpack_buffer_static_init();
109
+ void msgpack_buffer_static_init(void);
129
110
 
130
- void msgpack_buffer_static_destroy();
111
+ void msgpack_buffer_static_destroy(void);
131
112
 
132
113
  void msgpack_buffer_init(msgpack_buffer_t* b);
133
114
 
134
115
  void msgpack_buffer_destroy(msgpack_buffer_t* b);
135
116
 
136
- void msgpack_buffer_mark(msgpack_buffer_t* b);
117
+ void msgpack_buffer_mark(void* b);
137
118
 
138
119
  void msgpack_buffer_clear(msgpack_buffer_t* b);
139
120
 
121
+ size_t msgpack_buffer_memsize(const msgpack_buffer_t* b);
122
+
140
123
  static inline void msgpack_buffer_set_write_reference_threshold(msgpack_buffer_t* b, size_t length)
141
124
  {
142
125
  if(length < MSGPACK_BUFFER_STRING_WRITE_REFERENCE_MINIMUM) {
@@ -254,13 +237,14 @@ void _msgpack_buffer_append_long_string(msgpack_buffer_t* b, VALUE string);
254
237
 
255
238
  static inline size_t msgpack_buffer_append_string(msgpack_buffer_t* b, VALUE string)
256
239
  {
257
- size_t length = RSTRING_LEN(string);
240
+ size_t length;
241
+ char *ptr;
242
+ RSTRING_GETMEM(string, ptr, length);
258
243
 
259
244
  if(length > b->write_reference_threshold) {
260
245
  _msgpack_buffer_append_long_string(b, string);
261
-
262
246
  } else {
263
- msgpack_buffer_append(b, RSTRING_PTR(string), length);
247
+ msgpack_buffer_append(b, ptr, length);
264
248
  }
265
249
 
266
250
  return length;
@@ -269,14 +253,9 @@ static inline size_t msgpack_buffer_append_string(msgpack_buffer_t* b, VALUE str
269
253
  static inline size_t msgpack_buffer_append_string_reference(msgpack_buffer_t* b, VALUE string)
270
254
  {
271
255
  size_t length = RSTRING_LEN(string);
272
-
273
- if(length > MSGPACK_BUFFER_STRING_WRITE_REFERENCE_MINIMUM) {
256
+ if (length > 0) {
274
257
  _msgpack_buffer_append_long_string(b, string);
275
-
276
- } else {
277
- msgpack_buffer_append(b, RSTRING_PTR(string), length);
278
258
  }
279
-
280
259
  return length;
281
260
  }
282
261
 
@@ -389,14 +368,6 @@ static inline size_t msgpack_buffer_skip_nonblock(msgpack_buffer_t* b, size_t le
389
368
  return length;
390
369
  }
391
370
 
392
- static inline union msgpack_buffer_cast_block_t* msgpack_buffer_read_cast_block(msgpack_buffer_t* b, size_t n)
393
- {
394
- if(!msgpack_buffer_read_all(b, b->cast_block.buffer, n)) {
395
- return NULL;
396
- }
397
- return &b->cast_block;
398
- }
399
-
400
371
  size_t msgpack_buffer_read_to_string_nonblock(msgpack_buffer_t* b, VALUE string, size_t length);
401
372
 
402
373
  static inline size_t msgpack_buffer_read_to_string(msgpack_buffer_t* b, VALUE string, size_t length)
@@ -444,7 +415,6 @@ static inline VALUE _msgpack_buffer_refer_head_mapped_string(msgpack_buffer_t* b
444
415
 
445
416
  static inline VALUE msgpack_buffer_read_top_as_string(msgpack_buffer_t* b, size_t length, bool will_be_frozen, bool utf8)
446
417
  {
447
- #ifndef DISABLE_BUFFER_READ_REFERENCE_OPTIMIZE
448
418
  /* optimize */
449
419
  if(!will_be_frozen &&
450
420
  b->head->mapped_string != NO_MAPPED_STRING &&
@@ -454,7 +424,6 @@ static inline VALUE msgpack_buffer_read_top_as_string(msgpack_buffer_t* b, size_
454
424
  _msgpack_buffer_consumed(b, length);
455
425
  return result;
456
426
  }
457
- #endif
458
427
 
459
428
  VALUE result;
460
429
 
@@ -483,7 +452,6 @@ static inline VALUE msgpack_buffer_read_top_as_string(msgpack_buffer_t* b, size_
483
452
  result = rb_str_new(b->read_buffer, length);
484
453
  }
485
454
 
486
- #if STR_UMINUS_DEDUPE
487
455
  if (will_be_frozen) {
488
456
  #if STR_UMINUS_DEDUPE_FROZEN
489
457
  // Starting from MRI 2.8 it is preferable to freeze the string
@@ -495,7 +463,6 @@ static inline VALUE msgpack_buffer_read_top_as_string(msgpack_buffer_t* b, size_
495
463
  // frozen.
496
464
  result = rb_funcall(result, s_uminus, 0);
497
465
  }
498
- #endif // STR_UMINUS_DEDUPE
499
466
  _msgpack_buffer_consumed(b, length);
500
467
  return result;
501
468
 
@@ -507,4 +474,131 @@ static inline VALUE msgpack_buffer_read_top_as_symbol(msgpack_buffer_t* b, size_
507
474
  return rb_str_intern(msgpack_buffer_read_top_as_string(b, length, true, utf8));
508
475
  }
509
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
+
510
604
  #endif