msgpack 1.4.2 → 1.6.0

Sign up to get free protection for your applications and to get access to all the features.
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)