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.
- checksums.yaml +4 -4
- data/ChangeLog +50 -0
- data/README.md +48 -12
- data/ext/java/org/msgpack/jruby/Buffer.java +3 -3
- data/ext/java/org/msgpack/jruby/ExtensionRegistry.java +11 -20
- data/ext/java/org/msgpack/jruby/ExtensionValue.java +1 -1
- data/ext/java/org/msgpack/jruby/Factory.java +11 -50
- data/ext/java/org/msgpack/jruby/Packer.java +9 -24
- data/ext/java/org/msgpack/jruby/Unpacker.java +15 -32
- data/ext/msgpack/buffer.c +69 -56
- data/ext/msgpack/buffer.h +138 -44
- data/ext/msgpack/buffer_class.c +132 -31
- data/ext/msgpack/buffer_class.h +1 -0
- data/ext/msgpack/extconf.rb +20 -30
- data/ext/msgpack/factory_class.c +75 -86
- data/ext/msgpack/packer.c +13 -16
- data/ext/msgpack/packer.h +24 -21
- data/ext/msgpack/packer_class.c +72 -98
- data/ext/msgpack/packer_class.h +11 -0
- data/ext/msgpack/packer_ext_registry.c +31 -28
- data/ext/msgpack/packer_ext_registry.h +10 -14
- data/ext/msgpack/rbinit.c +1 -1
- data/ext/msgpack/rmem.c +3 -4
- data/ext/msgpack/sysdep.h +5 -2
- data/ext/msgpack/unpacker.c +201 -113
- data/ext/msgpack/unpacker.h +22 -15
- data/ext/msgpack/unpacker_class.c +87 -92
- data/ext/msgpack/unpacker_class.h +11 -0
- data/ext/msgpack/unpacker_ext_registry.c +4 -16
- data/ext/msgpack/unpacker_ext_registry.h +3 -7
- data/lib/msgpack/buffer.rb +9 -0
- data/lib/msgpack/factory.rb +90 -63
- data/lib/msgpack/packer.rb +10 -1
- data/lib/msgpack/unpacker.rb +14 -1
- data/lib/msgpack/version.rb +1 -1
- data/lib/msgpack.rb +1 -0
- data/msgpack.gemspec +8 -3
- metadata +21 -51
- data/.github/workflows/ci.yaml +0 -57
- data/.gitignore +0 -23
- data/.rubocop.yml +0 -36
- data/Gemfile +0 -9
- data/Rakefile +0 -70
- data/appveyor.yml +0 -18
- data/bench/bench.rb +0 -78
- data/doclib/msgpack/buffer.rb +0 -193
- data/doclib/msgpack/core_ext.rb +0 -101
- data/doclib/msgpack/error.rb +0 -19
- data/doclib/msgpack/extension_value.rb +0 -9
- data/doclib/msgpack/factory.rb +0 -145
- data/doclib/msgpack/packer.rb +0 -209
- data/doclib/msgpack/time.rb +0 -22
- data/doclib/msgpack/timestamp.rb +0 -44
- data/doclib/msgpack/unpacker.rb +0 -183
- data/doclib/msgpack.rb +0 -87
- data/msgpack.org.md +0 -46
- data/spec/bigint_spec.rb +0 -26
- data/spec/cases.json +0 -1
- data/spec/cases.msg +0 -0
- data/spec/cases_compact.msg +0 -0
- data/spec/cases_spec.rb +0 -39
- data/spec/cruby/buffer_io_spec.rb +0 -255
- data/spec/cruby/buffer_packer.rb +0 -29
- data/spec/cruby/buffer_spec.rb +0 -575
- data/spec/cruby/buffer_unpacker.rb +0 -19
- data/spec/cruby/unpacker_spec.rb +0 -70
- data/spec/ext_value_spec.rb +0 -99
- data/spec/exttypes.rb +0 -51
- data/spec/factory_spec.rb +0 -688
- data/spec/format_spec.rb +0 -301
- data/spec/jruby/benchmarks/shootout_bm.rb +0 -73
- data/spec/jruby/benchmarks/symbolize_keys_bm.rb +0 -25
- data/spec/jruby/unpacker_spec.rb +0 -186
- data/spec/msgpack_spec.rb +0 -214
- data/spec/pack_spec.rb +0 -61
- data/spec/packer_spec.rb +0 -575
- data/spec/random_compat.rb +0 -24
- data/spec/spec_helper.rb +0 -71
- data/spec/timestamp_spec.rb +0 -159
- data/spec/unpack_spec.rb +0 -57
- 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
|
-
|
76
|
-
|
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
|
-
|
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*
|
256
|
-
if(
|
257
|
-
|
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
|
-
|
260
|
-
return
|
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
|
300
|
+
static inline void _msgpack_buffer_append_reference(msgpack_buffer_t* b, VALUE string)
|
304
301
|
{
|
305
|
-
|
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 (
|
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),
|
337
|
+
msgpack_buffer_append(b, RSTRING_PTR(string), RSTRING_LEN(string));
|
313
338
|
}
|
314
339
|
} else {
|
315
|
-
|
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
|
-
|
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(
|
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
|
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,
|
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
|