msgpack 1.4.2 → 1.6.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 (64) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yaml +57 -0
  3. data/ChangeLog +60 -0
  4. data/README.md +25 -1
  5. data/Rakefile +1 -2
  6. data/bench/bench.rb +78 -0
  7. data/bin/console +8 -0
  8. data/doclib/msgpack/factory.rb +47 -3
  9. data/doclib/msgpack/packer.rb +5 -4
  10. data/doclib/msgpack/unpacker.rb +2 -2
  11. data/ext/java/org/msgpack/jruby/Buffer.java +23 -16
  12. data/ext/java/org/msgpack/jruby/Decoder.java +29 -21
  13. data/ext/java/org/msgpack/jruby/Encoder.java +68 -30
  14. data/ext/java/org/msgpack/jruby/ExtensionRegistry.java +37 -49
  15. data/ext/java/org/msgpack/jruby/ExtensionValue.java +5 -8
  16. data/ext/java/org/msgpack/jruby/Factory.java +47 -7
  17. data/ext/java/org/msgpack/jruby/Packer.java +29 -17
  18. data/ext/java/org/msgpack/jruby/Unpacker.java +66 -42
  19. data/ext/msgpack/buffer.c +38 -57
  20. data/ext/msgpack/buffer.h +19 -10
  21. data/ext/msgpack/buffer_class.c +90 -52
  22. data/ext/msgpack/compat.h +0 -99
  23. data/ext/msgpack/extconf.rb +9 -22
  24. data/ext/msgpack/factory_class.c +133 -43
  25. data/ext/msgpack/packer.c +60 -36
  26. data/ext/msgpack/packer.h +27 -18
  27. data/ext/msgpack/packer_class.c +84 -77
  28. data/ext/msgpack/packer_class.h +11 -0
  29. data/ext/msgpack/packer_ext_registry.c +24 -32
  30. data/ext/msgpack/packer_ext_registry.h +40 -33
  31. data/ext/msgpack/sysdep.h +5 -2
  32. data/ext/msgpack/unpacker.c +128 -97
  33. data/ext/msgpack/unpacker.h +17 -10
  34. data/ext/msgpack/unpacker_class.c +75 -80
  35. data/ext/msgpack/unpacker_class.h +11 -0
  36. data/ext/msgpack/unpacker_ext_registry.c +42 -18
  37. data/ext/msgpack/unpacker_ext_registry.h +23 -16
  38. data/lib/msgpack/bigint.rb +69 -0
  39. data/lib/msgpack/factory.rb +103 -0
  40. data/lib/msgpack/symbol.rb +21 -4
  41. data/lib/msgpack/time.rb +1 -1
  42. data/lib/msgpack/version.rb +1 -1
  43. data/lib/msgpack.rb +5 -7
  44. data/msgpack.gemspec +2 -2
  45. data/spec/bigint_spec.rb +26 -0
  46. data/spec/cruby/buffer_spec.rb +17 -0
  47. data/spec/factory_spec.rb +351 -12
  48. data/spec/msgpack_spec.rb +1 -1
  49. data/spec/packer_spec.rb +18 -0
  50. data/spec/spec_helper.rb +20 -3
  51. data/spec/timestamp_spec.rb +38 -0
  52. data/spec/unpacker_spec.rb +54 -4
  53. metadata +25 -41
  54. data/.travis.yml +0 -39
  55. data/bench/pack.rb +0 -23
  56. data/bench/pack_log.rb +0 -33
  57. data/bench/pack_log_long.rb +0 -65
  58. data/bench/pack_symbols.rb +0 -28
  59. data/bench/run.sh +0 -14
  60. data/bench/run_long.sh +0 -35
  61. data/bench/run_symbols.sh +0 -26
  62. data/bench/unpack.rb +0 -21
  63. data/bench/unpack_log.rb +0 -34
  64. data/bench/unpack_log_long.rb +0 -67
@@ -28,18 +28,14 @@ VALUE cMessagePack_Packer;
28
28
  static ID s_to_msgpack;
29
29
  static ID s_write;
30
30
 
31
+ static VALUE sym_compatibility_mode;
32
+
31
33
  //static VALUE s_packer_value;
32
34
  //static msgpack_packer_t* s_packer;
33
35
 
34
- #define PACKER(from, name) \
35
- msgpack_packer_t* name; \
36
- Data_Get_Struct(from, msgpack_packer_t, name); \
37
- if(name == NULL) { \
38
- rb_raise(rb_eArgError, "NULL found for " # name " when shouldn't be."); \
39
- }
40
-
41
- static void Packer_free(msgpack_packer_t* pk)
36
+ static void Packer_free(void *ptr)
42
37
  {
38
+ msgpack_packer_t* pk = ptr;
43
39
  if(pk == NULL) {
44
40
  return;
45
41
  }
@@ -48,52 +44,66 @@ static void Packer_free(msgpack_packer_t* pk)
48
44
  xfree(pk);
49
45
  }
50
46
 
51
- static void Packer_mark(msgpack_packer_t* pk)
47
+ static void Packer_mark(void *ptr)
52
48
  {
49
+ msgpack_packer_t* pk = ptr;
53
50
  msgpack_packer_mark(pk);
54
51
  msgpack_packer_ext_registry_mark(&pk->ext_registry);
55
52
  }
56
53
 
57
- VALUE MessagePack_Packer_alloc(VALUE klass)
54
+ static size_t Packer_memsize(const void *ptr)
58
55
  {
59
- msgpack_packer_t* pk = ZALLOC_N(msgpack_packer_t, 1);
60
- msgpack_packer_init(pk);
56
+ const msgpack_packer_t* pk = ptr;
57
+ return sizeof(msgpack_packer_t) + msgpack_buffer_memsize(&pk->buffer);
58
+ }
61
59
 
62
- VALUE self = Data_Wrap_Struct(klass, Packer_mark, Packer_free, pk);
60
+ const rb_data_type_t packer_data_type = {
61
+ .wrap_struct_name = "msgpack:packer",
62
+ .function = {
63
+ .dmark = Packer_mark,
64
+ .dfree = Packer_free,
65
+ .dsize = Packer_memsize,
66
+ },
67
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY
68
+ };
63
69
 
64
- msgpack_packer_set_to_msgpack_method(pk, s_to_msgpack, self);
65
70
 
71
+ VALUE MessagePack_Packer_alloc(VALUE klass)
72
+ {
73
+ msgpack_packer_t* pk;
74
+ VALUE self = TypedData_Make_Struct(klass, msgpack_packer_t, &packer_data_type, pk);
75
+ msgpack_packer_init(pk);
76
+ msgpack_packer_set_to_msgpack_method(pk, s_to_msgpack, self);
66
77
  return self;
67
78
  }
68
79
 
69
80
  VALUE MessagePack_Packer_initialize(int argc, VALUE* argv, VALUE self)
70
81
  {
82
+ if(argc > 2) {
83
+ rb_raise(rb_eArgError, "wrong number of arguments (%d for 0..2)", argc);
84
+ }
85
+
71
86
  VALUE io = Qnil;
72
87
  VALUE options = Qnil;
73
88
 
74
- if(argc == 0 || (argc == 1 && argv[0] == Qnil)) {
75
- /* Qnil */
76
-
77
- } else if(argc == 1) {
78
- VALUE v = argv[0];
79
- if(rb_type(v) == T_HASH) {
80
- options = v;
81
- } else {
82
- io = v;
83
- }
84
-
85
- } else if(argc == 2) {
89
+ if(argc >= 1) {
86
90
  io = argv[0];
91
+ }
92
+
93
+ if(argc == 2) {
87
94
  options = argv[1];
88
- if(rb_type(options) != T_HASH) {
89
- rb_raise(rb_eArgError, "expected Hash but found %s.", rb_obj_classname(options));
90
- }
95
+ }
91
96
 
92
- } else {
93
- rb_raise(rb_eArgError, "wrong number of arguments (%d for 0..2)", argc);
97
+ if (options == Qnil && rb_type(io) == T_HASH) {
98
+ options = io;
99
+ io = Qnil;
100
+ }
101
+
102
+ if(options != Qnil) {
103
+ Check_Type(options, T_HASH);
94
104
  }
95
105
 
96
- PACKER(self, pk);
106
+ msgpack_packer_t *pk = MessagePack_Packer_get(self);
97
107
 
98
108
  msgpack_packer_ext_registry_init(&pk->ext_registry);
99
109
  pk->buffer_ref = MessagePack_Buffer_wrap(PACKER_BUFFER_(pk), self);
@@ -103,7 +113,7 @@ VALUE MessagePack_Packer_initialize(int argc, VALUE* argv, VALUE self)
103
113
  if(options != Qnil) {
104
114
  VALUE v;
105
115
 
106
- v = rb_hash_aref(options, ID2SYM(rb_intern("compatibility_mode")));
116
+ v = rb_hash_aref(options, sym_compatibility_mode);
107
117
  msgpack_packer_set_compat(pk, RTEST(v));
108
118
  }
109
119
 
@@ -112,54 +122,54 @@ VALUE MessagePack_Packer_initialize(int argc, VALUE* argv, VALUE self)
112
122
 
113
123
  static VALUE Packer_compatibility_mode_p(VALUE self)
114
124
  {
115
- PACKER(self, pk);
125
+ msgpack_packer_t *pk = MessagePack_Packer_get(self);
116
126
  return pk->compatibility_mode ? Qtrue : Qfalse;
117
127
  }
118
128
 
119
129
  static VALUE Packer_buffer(VALUE self)
120
130
  {
121
- PACKER(self, pk);
131
+ msgpack_packer_t *pk = MessagePack_Packer_get(self);
122
132
  return pk->buffer_ref;
123
133
  }
124
134
 
125
135
  static VALUE Packer_write(VALUE self, VALUE v)
126
136
  {
127
- PACKER(self, pk);
137
+ msgpack_packer_t *pk = MessagePack_Packer_get(self);
128
138
  msgpack_packer_write_value(pk, v);
129
139
  return self;
130
140
  }
131
141
 
132
142
  static VALUE Packer_write_nil(VALUE self)
133
143
  {
134
- PACKER(self, pk);
144
+ msgpack_packer_t *pk = MessagePack_Packer_get(self);
135
145
  msgpack_packer_write_nil(pk);
136
146
  return self;
137
147
  }
138
148
 
139
149
  static VALUE Packer_write_true(VALUE self)
140
150
  {
141
- PACKER(self, pk);
151
+ msgpack_packer_t *pk = MessagePack_Packer_get(self);
142
152
  msgpack_packer_write_true(pk);
143
153
  return self;
144
154
  }
145
155
 
146
156
  static VALUE Packer_write_false(VALUE self)
147
157
  {
148
- PACKER(self, pk);
158
+ msgpack_packer_t *pk = MessagePack_Packer_get(self);
149
159
  msgpack_packer_write_false(pk);
150
160
  return self;
151
161
  }
152
162
 
153
163
  static VALUE Packer_write_float(VALUE self, VALUE obj)
154
164
  {
155
- PACKER(self, pk);
165
+ msgpack_packer_t *pk = MessagePack_Packer_get(self);
156
166
  msgpack_packer_write_float_value(pk, obj);
157
167
  return self;
158
168
  }
159
169
 
160
170
  static VALUE Packer_write_string(VALUE self, VALUE obj)
161
171
  {
162
- PACKER(self, pk);
172
+ msgpack_packer_t *pk = MessagePack_Packer_get(self);
163
173
  Check_Type(obj, T_STRING);
164
174
  msgpack_packer_write_string_value(pk, obj);
165
175
  return self;
@@ -167,7 +177,7 @@ static VALUE Packer_write_string(VALUE self, VALUE obj)
167
177
 
168
178
  static VALUE Packer_write_bin(VALUE self, VALUE obj)
169
179
  {
170
- PACKER(self, pk);
180
+ msgpack_packer_t *pk = MessagePack_Packer_get(self);
171
181
  Check_Type(obj, T_STRING);
172
182
 
173
183
  VALUE enc = rb_enc_from_encoding(rb_ascii8bit_encoding());
@@ -179,7 +189,7 @@ static VALUE Packer_write_bin(VALUE self, VALUE obj)
179
189
 
180
190
  static VALUE Packer_write_array(VALUE self, VALUE obj)
181
191
  {
182
- PACKER(self, pk);
192
+ msgpack_packer_t *pk = MessagePack_Packer_get(self);
183
193
  Check_Type(obj, T_ARRAY);
184
194
  msgpack_packer_write_array_value(pk, obj);
185
195
  return self;
@@ -187,7 +197,7 @@ static VALUE Packer_write_array(VALUE self, VALUE obj)
187
197
 
188
198
  static VALUE Packer_write_hash(VALUE self, VALUE obj)
189
199
  {
190
- PACKER(self, pk);
200
+ msgpack_packer_t *pk = MessagePack_Packer_get(self);
191
201
  Check_Type(obj, T_HASH);
192
202
  msgpack_packer_write_hash_value(pk, obj);
193
203
  return self;
@@ -195,7 +205,7 @@ static VALUE Packer_write_hash(VALUE self, VALUE obj)
195
205
 
196
206
  static VALUE Packer_write_symbol(VALUE self, VALUE obj)
197
207
  {
198
- PACKER(self, pk);
208
+ msgpack_packer_t *pk = MessagePack_Packer_get(self);
199
209
  Check_Type(obj, T_SYMBOL);
200
210
  msgpack_packer_write_symbol_value(pk, obj);
201
211
  return self;
@@ -203,7 +213,7 @@ static VALUE Packer_write_symbol(VALUE self, VALUE obj)
203
213
 
204
214
  static VALUE Packer_write_int(VALUE self, VALUE obj)
205
215
  {
206
- PACKER(self, pk);
216
+ msgpack_packer_t *pk = MessagePack_Packer_get(self);
207
217
 
208
218
  if (FIXNUM_P(obj)) {
209
219
  msgpack_packer_write_fixnum_value(pk, obj);
@@ -216,7 +226,7 @@ static VALUE Packer_write_int(VALUE self, VALUE obj)
216
226
 
217
227
  static VALUE Packer_write_extension(VALUE self, VALUE obj)
218
228
  {
219
- PACKER(self, pk);
229
+ msgpack_packer_t *pk = MessagePack_Packer_get(self);
220
230
  Check_Type(obj, T_STRUCT);
221
231
 
222
232
  int ext_type = FIX2INT(RSTRUCT_GET(obj, 0));
@@ -232,21 +242,21 @@ static VALUE Packer_write_extension(VALUE self, VALUE obj)
232
242
 
233
243
  static VALUE Packer_write_array_header(VALUE self, VALUE n)
234
244
  {
235
- PACKER(self, pk);
245
+ msgpack_packer_t *pk = MessagePack_Packer_get(self);
236
246
  msgpack_packer_write_array_header(pk, NUM2UINT(n));
237
247
  return self;
238
248
  }
239
249
 
240
250
  static VALUE Packer_write_map_header(VALUE self, VALUE n)
241
251
  {
242
- PACKER(self, pk);
252
+ msgpack_packer_t *pk = MessagePack_Packer_get(self);
243
253
  msgpack_packer_write_map_header(pk, NUM2UINT(n));
244
254
  return self;
245
255
  }
246
256
 
247
257
  static VALUE Packer_write_bin_header(VALUE self, VALUE n)
248
258
  {
249
- PACKER(self, pk);
259
+ msgpack_packer_t *pk = MessagePack_Packer_get(self);
250
260
  msgpack_packer_write_bin_header(pk, NUM2UINT(n));
251
261
  return self;
252
262
  }
@@ -257,14 +267,14 @@ static VALUE Packer_write_float32(VALUE self, VALUE numeric)
257
267
  rb_raise(rb_eArgError, "Expected numeric");
258
268
  }
259
269
 
260
- PACKER(self, pk);
270
+ msgpack_packer_t *pk = MessagePack_Packer_get(self);
261
271
  msgpack_packer_write_float(pk, (float)rb_num2dbl(numeric));
262
272
  return self;
263
273
  }
264
274
 
265
275
  static VALUE Packer_write_ext(VALUE self, VALUE type, VALUE data)
266
276
  {
267
- PACKER(self, pk);
277
+ msgpack_packer_t *pk = MessagePack_Packer_get(self);
268
278
  int ext_type = NUM2INT(type);
269
279
  if(ext_type < -128 || ext_type > 127) {
270
280
  rb_raise(rb_eRangeError, "integer %d too big to convert to `signed char'", ext_type);
@@ -276,28 +286,28 @@ static VALUE Packer_write_ext(VALUE self, VALUE type, VALUE data)
276
286
 
277
287
  static VALUE Packer_flush(VALUE self)
278
288
  {
279
- PACKER(self, pk);
289
+ msgpack_packer_t *pk = MessagePack_Packer_get(self);
280
290
  msgpack_buffer_flush(PACKER_BUFFER_(pk));
281
291
  return self;
282
292
  }
283
293
 
284
- static VALUE Packer_clear(VALUE self)
294
+ static VALUE Packer_reset(VALUE self)
285
295
  {
286
- PACKER(self, pk);
296
+ msgpack_packer_t *pk = MessagePack_Packer_get(self);
287
297
  msgpack_buffer_clear(PACKER_BUFFER_(pk));
288
298
  return Qnil;
289
299
  }
290
300
 
291
301
  static VALUE Packer_size(VALUE self)
292
302
  {
293
- PACKER(self, pk);
303
+ msgpack_packer_t *pk = MessagePack_Packer_get(self);
294
304
  size_t size = msgpack_buffer_all_readable_size(PACKER_BUFFER_(pk));
295
305
  return SIZET2NUM(size);
296
306
  }
297
307
 
298
308
  static VALUE Packer_empty_p(VALUE self)
299
309
  {
300
- PACKER(self, pk);
310
+ msgpack_packer_t *pk = MessagePack_Packer_get(self);
301
311
  if(msgpack_buffer_top_readable_size(PACKER_BUFFER_(pk)) == 0) {
302
312
  return Qtrue;
303
313
  } else {
@@ -307,26 +317,26 @@ static VALUE Packer_empty_p(VALUE self)
307
317
 
308
318
  static VALUE Packer_to_str(VALUE self)
309
319
  {
310
- PACKER(self, pk);
320
+ msgpack_packer_t *pk = MessagePack_Packer_get(self);
311
321
  return msgpack_buffer_all_as_string(PACKER_BUFFER_(pk));
312
322
  }
313
323
 
314
324
  static VALUE Packer_to_a(VALUE self)
315
325
  {
316
- PACKER(self, pk);
326
+ msgpack_packer_t *pk = MessagePack_Packer_get(self);
317
327
  return msgpack_buffer_all_as_string_array(PACKER_BUFFER_(pk));
318
328
  }
319
329
 
320
330
  static VALUE Packer_write_to(VALUE self, VALUE io)
321
331
  {
322
- PACKER(self, pk);
332
+ msgpack_packer_t *pk = MessagePack_Packer_get(self);
323
333
  size_t sz = msgpack_buffer_flush_to_io(PACKER_BUFFER_(pk), io, s_write, true);
324
- return ULONG2NUM(sz);
334
+ return SIZET2NUM(sz);
325
335
  }
326
336
 
327
337
  //static VALUE Packer_append(VALUE self, VALUE string_or_buffer)
328
338
  //{
329
- // PACKER(self, pk);
339
+ // msgpack_packer_t *pk = MessagePack_Packer_get(self);
330
340
  //
331
341
  // // TODO if string_or_buffer is a Buffer
332
342
  // VALUE string = string_or_buffer;
@@ -338,17 +348,16 @@ static VALUE Packer_write_to(VALUE self, VALUE io)
338
348
 
339
349
  static VALUE Packer_registered_types_internal(VALUE self)
340
350
  {
341
- PACKER(self, pk);
342
- #ifdef HAVE_RB_HASH_DUP
343
- return rb_hash_dup(pk->ext_registry.hash);
344
- #else
345
- return rb_funcall(pk->ext_registry.hash, rb_intern("dup"), 0);
346
- #endif
351
+ msgpack_packer_t *pk = MessagePack_Packer_get(self);
352
+ if (RTEST(pk->ext_registry.hash)) {
353
+ return rb_hash_dup(pk->ext_registry.hash);
354
+ }
355
+ return rb_hash_new();
347
356
  }
348
357
 
349
358
  static VALUE Packer_register_type(int argc, VALUE* argv, VALUE self)
350
359
  {
351
- PACKER(self, pk);
360
+ msgpack_packer_t *pk = MessagePack_Packer_get(self);
352
361
 
353
362
  int ext_type;
354
363
  VALUE ext_module;
@@ -359,12 +368,7 @@ static VALUE Packer_register_type(int argc, VALUE* argv, VALUE self)
359
368
  case 2:
360
369
  /* register_type(0x7f, Time) {|obj| block... } */
361
370
  rb_need_block();
362
- #ifdef HAVE_RB_BLOCK_LAMBDA
363
371
  proc = rb_block_lambda();
364
- #else
365
- /* MRI 1.8 */
366
- proc = rb_block_proc();
367
- #endif
368
372
  arg = proc;
369
373
  break;
370
374
  case 3:
@@ -386,7 +390,7 @@ static VALUE Packer_register_type(int argc, VALUE* argv, VALUE self)
386
390
  rb_raise(rb_eArgError, "expected Module/Class but found %s.", rb_obj_classname(ext_module));
387
391
  }
388
392
 
389
- msgpack_packer_ext_registry_put(&pk->ext_registry, ext_module, ext_type, proc, arg);
393
+ msgpack_packer_ext_registry_put(&pk->ext_registry, ext_module, ext_type, 0, proc, arg);
390
394
 
391
395
  if (ext_module == rb_cSymbol) {
392
396
  pk->has_symbol_ext_type = true;
@@ -399,7 +403,7 @@ VALUE Packer_full_pack(VALUE self)
399
403
  {
400
404
  VALUE retval;
401
405
 
402
- PACKER(self, pk);
406
+ msgpack_packer_t *pk = MessagePack_Packer_get(self);
403
407
 
404
408
  if(msgpack_buffer_has_io(PACKER_BUFFER_(pk))) {
405
409
  msgpack_buffer_flush(PACKER_BUFFER_(pk));
@@ -418,6 +422,8 @@ void MessagePack_Packer_module_init(VALUE mMessagePack)
418
422
  s_to_msgpack = rb_intern("to_msgpack");
419
423
  s_write = rb_intern("write");
420
424
 
425
+ sym_compatibility_mode = ID2SYM(rb_intern("compatibility_mode"));
426
+
421
427
  msgpack_packer_static_init();
422
428
  msgpack_packer_ext_registry_static_init();
423
429
 
@@ -449,7 +455,8 @@ void MessagePack_Packer_module_init(VALUE mMessagePack)
449
455
  rb_define_method(cMessagePack_Packer, "flush", Packer_flush, 0);
450
456
 
451
457
  /* delegation methods */
452
- rb_define_method(cMessagePack_Packer, "clear", Packer_clear, 0);
458
+ rb_define_method(cMessagePack_Packer, "reset", Packer_reset, 0);
459
+ rb_define_alias(cMessagePack_Packer, "clear", "reset");
453
460
  rb_define_method(cMessagePack_Packer, "size", Packer_size, 0);
454
461
  rb_define_method(cMessagePack_Packer, "empty?", Packer_empty_p, 0);
455
462
  rb_define_method(cMessagePack_Packer, "write_to", Packer_write_to, 1);
@@ -22,6 +22,17 @@
22
22
 
23
23
  extern VALUE cMessagePack_Packer;
24
24
 
25
+ extern const rb_data_type_t packer_data_type;
26
+
27
+ static inline msgpack_packer_t *MessagePack_Packer_get(VALUE object) {
28
+ msgpack_packer_t *packer;
29
+ TypedData_Get_Struct(object, msgpack_packer_t, &packer_data_type, packer);
30
+ if (!packer) {
31
+ rb_raise(rb_eArgError, "Uninitialized Packer object");
32
+ }
33
+ return packer;
34
+ }
35
+
25
36
  void MessagePack_Packer_module_init(VALUE mMessagePack);
26
37
 
27
38
  VALUE MessagePack_Packer_alloc(VALUE klass);
@@ -20,18 +20,18 @@
20
20
 
21
21
  static ID s_call;
22
22
 
23
- void msgpack_packer_ext_registry_static_init()
23
+ void msgpack_packer_ext_registry_static_init(void)
24
24
  {
25
25
  s_call = rb_intern("call");
26
26
  }
27
27
 
28
- void msgpack_packer_ext_registry_static_destroy()
28
+ void msgpack_packer_ext_registry_static_destroy(void)
29
29
  { }
30
30
 
31
31
  void msgpack_packer_ext_registry_init(msgpack_packer_ext_registry_t* pkrg)
32
32
  {
33
- pkrg->hash = rb_hash_new();
34
- pkrg->cache = rb_hash_new();
33
+ pkrg->hash = Qnil;
34
+ pkrg->cache = Qnil;
35
35
  }
36
36
 
37
37
  void msgpack_packer_ext_registry_mark(msgpack_packer_ext_registry_t* pkrg)
@@ -43,37 +43,29 @@ void msgpack_packer_ext_registry_mark(msgpack_packer_ext_registry_t* pkrg)
43
43
  void msgpack_packer_ext_registry_dup(msgpack_packer_ext_registry_t* src,
44
44
  msgpack_packer_ext_registry_t* dst)
45
45
  {
46
- #ifdef HAVE_RB_HASH_DUP
47
- dst->hash = rb_hash_dup(src->hash);
48
- dst->cache = rb_hash_dup(src->cache);
49
- #else
50
- dst->hash = rb_funcall(src->hash, rb_intern("dup"), 0);
51
- dst->cache = rb_funcall(src->cache, rb_intern("dup"), 0);
52
- #endif
53
- }
54
-
55
- #ifndef HAVE_RB_HASH_CLEAR
56
-
57
- static int
58
- __rb_hash_clear_clear_i(key, value, dummy)
59
- VALUE key, value, dummy;
60
- {
61
- return ST_DELETE;
46
+ if(RTEST(src->hash) && !rb_obj_frozen_p(src->hash)) {
47
+ dst->hash = rb_hash_dup(src->hash);
48
+ dst->cache = RTEST(src->cache) ? rb_hash_dup(src->cache) : Qnil;
49
+ } else {
50
+ // If the type registry is frozen we can safely share it, and share the cache as well.
51
+ dst->hash = src->hash;
52
+ dst->cache = src->cache;
53
+ }
62
54
  }
63
55
 
64
- #endif
65
-
66
56
  VALUE msgpack_packer_ext_registry_put(msgpack_packer_ext_registry_t* pkrg,
67
- VALUE ext_module, int ext_type, VALUE proc, VALUE arg)
57
+ VALUE ext_module, int ext_type, int flags, VALUE proc, VALUE arg)
68
58
  {
69
- VALUE e = rb_ary_new3(3, INT2FIX(ext_type), proc, arg);
70
- /* clear lookup cache not to miss added type */
71
- #ifdef HAVE_RB_HASH_CLEAR
72
- rb_hash_clear(pkrg->cache);
73
- #else
74
- if(FIX2INT(rb_funcall(pkrg->cache, rb_intern("size"), 0)) > 0) {
75
- rb_hash_foreach(pkrg->cache, __rb_hash_clear_clear_i, 0);
59
+ if (!RTEST(pkrg->hash)) {
60
+ pkrg->hash = rb_hash_new();
61
+ }
62
+
63
+ if (RTEST(pkrg->cache)) {
64
+ /* clear lookup cache not to miss added type */
65
+ rb_hash_clear(pkrg->cache);
76
66
  }
77
- #endif
78
- return rb_hash_aset(pkrg->hash, ext_module, e);
67
+
68
+ // TODO: Ruby embeded array limit is 3, merging `proc` and `arg` would be good.
69
+ VALUE entry = rb_ary_new3(4, INT2FIX(ext_type), proc, arg, INT2FIX(flags));
70
+ return rb_hash_aset(pkrg->hash, ext_module, entry);
79
71
  }
@@ -21,6 +21,8 @@
21
21
  #include "compat.h"
22
22
  #include "ruby.h"
23
23
 
24
+ #define MSGPACK_EXT_RECURSIVE 0b0001
25
+
24
26
  struct msgpack_packer_ext_registry_t;
25
27
  typedef struct msgpack_packer_ext_registry_t msgpack_packer_ext_registry_t;
26
28
 
@@ -29,9 +31,9 @@ struct msgpack_packer_ext_registry_t {
29
31
  VALUE cache; // lookup cache for ext types inherited from a super class
30
32
  };
31
33
 
32
- void msgpack_packer_ext_registry_static_init();
34
+ void msgpack_packer_ext_registry_static_init(void);
33
35
 
34
- void msgpack_packer_ext_registry_static_destroy();
36
+ void msgpack_packer_ext_registry_static_destroy(void);
35
37
 
36
38
  void msgpack_packer_ext_registry_init(msgpack_packer_ext_registry_t* pkrg);
37
39
 
@@ -44,7 +46,7 @@ void msgpack_packer_ext_registry_dup(msgpack_packer_ext_registry_t* src,
44
46
  msgpack_packer_ext_registry_t* dst);
45
47
 
46
48
  VALUE msgpack_packer_ext_registry_put(msgpack_packer_ext_registry_t* pkrg,
47
- VALUE ext_module, int ext_type, VALUE proc, VALUE arg);
49
+ VALUE ext_module, int ext_type, int flags, VALUE proc, VALUE arg);
48
50
 
49
51
  static int msgpack_packer_ext_find_superclass(VALUE key, VALUE value, VALUE arg)
50
52
  {
@@ -60,59 +62,60 @@ static int msgpack_packer_ext_find_superclass(VALUE key, VALUE value, VALUE arg)
60
62
  }
61
63
 
62
64
  static inline VALUE msgpack_packer_ext_registry_fetch(msgpack_packer_ext_registry_t* pkrg,
63
- VALUE lookup_class, int* ext_type_result)
65
+ VALUE lookup_class, int* ext_type_result, int* ext_flags_result)
64
66
  {
65
67
  // fetch lookup_class from hash, which is a hash to register classes
66
68
  VALUE type = rb_hash_lookup(pkrg->hash, lookup_class);
67
69
  if(type != Qnil) {
68
70
  *ext_type_result = FIX2INT(rb_ary_entry(type, 0));
71
+ *ext_flags_result = FIX2INT(rb_ary_entry(type, 3));
69
72
  return rb_ary_entry(type, 1);
70
73
  }
71
74
 
72
75
  // fetch lookup_class from cache, which stores results of searching ancestors from pkrg->hash
73
- VALUE type_inht = rb_hash_lookup(pkrg->cache, lookup_class);
74
- if(type_inht != Qnil) {
75
- *ext_type_result = FIX2INT(rb_ary_entry(type_inht, 0));
76
- return rb_ary_entry(type_inht, 1);
76
+ if (RTEST(pkrg->cache)) {
77
+ VALUE type_inht = rb_hash_lookup(pkrg->cache, lookup_class);
78
+ if(type_inht != Qnil) {
79
+ *ext_type_result = FIX2INT(rb_ary_entry(type_inht, 0));
80
+ *ext_flags_result = FIX2INT(rb_ary_entry(type_inht, 3));
81
+ return rb_ary_entry(type_inht, 1);
82
+ }
77
83
  }
78
84
 
79
85
  return Qnil;
80
86
  }
81
87
 
82
88
  static inline VALUE msgpack_packer_ext_registry_lookup(msgpack_packer_ext_registry_t* pkrg,
83
- VALUE instance, int* ext_type_result)
89
+ VALUE instance, int* ext_type_result, int* ext_flags_result)
84
90
  {
85
- VALUE lookup_class;
86
91
  VALUE type;
87
92
 
88
- /*
89
- * 1. check whether singleton_class of this instance is registered (or resolved in past) or not.
90
- *
91
- * Objects of type Integer (Fixnum, Bignum), Float, Symbol and frozen
92
- * String have no singleton class and raise a TypeError when trying to get
93
- * it. See implementation of #singleton_class in ruby's source code:
94
- * VALUE rb_singleton_class(VALUE obj);
95
- *
96
- * Since all but symbols are already filtered out when reaching this code
97
- * only symbols are checked here.
98
- */
99
- if (!SYMBOL_P(instance)) {
100
- lookup_class = rb_singleton_class(instance);
101
-
102
- type = msgpack_packer_ext_registry_fetch(pkrg, lookup_class, ext_type_result);
93
+ if (pkrg->hash == Qnil) { // No extensions registered
94
+ return Qnil;
95
+ }
103
96
 
104
- if(type != Qnil) {
105
- return type;
106
- }
97
+ /*
98
+ * 1. check whether singleton_class or class of this instance is registered (or resolved in past) or not.
99
+ *
100
+ * Objects of type Integer (Fixnum, Bignum), Float, Symbol and frozen
101
+ * `rb_class_of` returns the singleton_class if the object has one, or the "real class" otherwise.
102
+ */
103
+ VALUE lookup_class = rb_class_of(instance);
104
+ type = msgpack_packer_ext_registry_fetch(pkrg, lookup_class, ext_type_result, ext_flags_result);
105
+ if(type != Qnil) {
106
+ return type;
107
107
  }
108
108
 
109
109
  /*
110
- * 2. check the class of instance is registered (or resolved in past) or not.
110
+ * 2. If the object had a singleton_class check if the real class of instance is registered
111
+ * (or resolved in past) or not.
111
112
  */
112
- type = msgpack_packer_ext_registry_fetch(pkrg, rb_obj_class(instance), ext_type_result);
113
-
114
- if(type != Qnil) {
115
- return type;
113
+ VALUE real_class = rb_obj_class(instance);
114
+ if(lookup_class != real_class) {
115
+ type = msgpack_packer_ext_registry_fetch(pkrg, real_class, ext_type_result, ext_flags_result);
116
+ if(type != Qnil) {
117
+ return type;
118
+ }
116
119
  }
117
120
 
118
121
  /*
@@ -126,8 +129,12 @@ static inline VALUE msgpack_packer_ext_registry_lookup(msgpack_packer_ext_regist
126
129
  VALUE superclass = args[1];
127
130
  if(superclass != Qnil) {
128
131
  VALUE superclass_type = rb_hash_lookup(pkrg->hash, superclass);
132
+ if (!RTEST(pkrg->cache)) {
133
+ pkrg->cache = rb_hash_new();
134
+ }
129
135
  rb_hash_aset(pkrg->cache, lookup_class, superclass_type);
130
136
  *ext_type_result = FIX2INT(rb_ary_entry(superclass_type, 0));
137
+ *ext_flags_result = FIX2INT(rb_ary_entry(superclass_type, 3));
131
138
  return rb_ary_entry(superclass_type, 1);
132
139
  }
133
140
 
data/ext/msgpack/sysdep.h CHANGED
@@ -35,8 +35,11 @@
35
35
  # define _msgpack_be16(x) ((uint16_t)_byteswap_ushort((unsigned short)x))
36
36
  # else
37
37
  # define _msgpack_be16(x) ( \
38
- ((((uint16_t)x) << 8) ) | \
39
- ((((uint16_t)x) >> 8) ) )
38
+ ( \
39
+ ((((uint16_t)x) << 8) ) | \
40
+ ((((uint16_t)x) >> 8) ) \
41
+ ) \
42
+ & 0x0000FFFF )
40
43
  # endif
41
44
  #else
42
45
  # define _msgpack_be16(x) ntohs(x)