msgpack 1.2.6 → 1.4.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yaml +56 -0
  3. data/.gitignore +3 -1
  4. data/.rubocop.yml +4 -1
  5. data/ChangeLog +59 -0
  6. data/Gemfile +3 -0
  7. data/README.md +242 -0
  8. data/Rakefile +3 -8
  9. data/doclib/msgpack/factory.rb +1 -0
  10. data/doclib/msgpack/packer.rb +20 -0
  11. data/doclib/msgpack/time.rb +22 -0
  12. data/doclib/msgpack/timestamp.rb +44 -0
  13. data/doclib/msgpack.rb +2 -2
  14. data/ext/java/org/msgpack/jruby/Buffer.java +21 -16
  15. data/ext/java/org/msgpack/jruby/Decoder.java +29 -10
  16. data/ext/java/org/msgpack/jruby/Encoder.java +38 -19
  17. data/ext/java/org/msgpack/jruby/ExtensionRegistry.java +9 -9
  18. data/ext/java/org/msgpack/jruby/ExtensionValue.java +5 -8
  19. data/ext/java/org/msgpack/jruby/Factory.java +8 -3
  20. data/ext/java/org/msgpack/jruby/Packer.java +31 -8
  21. data/ext/java/org/msgpack/jruby/Unpacker.java +40 -27
  22. data/ext/msgpack/buffer.c +4 -16
  23. data/ext/msgpack/buffer.h +60 -5
  24. data/ext/msgpack/compat.h +1 -12
  25. data/ext/msgpack/extconf.rb +39 -7
  26. data/ext/msgpack/factory_class.c +10 -5
  27. data/ext/msgpack/packer.c +18 -5
  28. data/ext/msgpack/packer.h +0 -16
  29. data/ext/msgpack/packer_class.c +21 -9
  30. data/ext/msgpack/packer_ext_registry.c +0 -22
  31. data/ext/msgpack/unpacker.c +41 -49
  32. data/ext/msgpack/unpacker.h +8 -0
  33. data/ext/msgpack/unpacker_class.c +23 -13
  34. data/lib/msgpack/symbol.rb +14 -4
  35. data/lib/msgpack/time.rb +29 -0
  36. data/lib/msgpack/timestamp.rb +76 -0
  37. data/lib/msgpack/version.rb +4 -7
  38. data/lib/msgpack.rb +8 -10
  39. data/msgpack.gemspec +3 -7
  40. data/spec/cruby/buffer_spec.rb +6 -1
  41. data/spec/factory_spec.rb +17 -0
  42. data/spec/msgpack_spec.rb +44 -1
  43. data/spec/packer_spec.rb +54 -0
  44. data/spec/spec_helper.rb +27 -0
  45. data/spec/timestamp_spec.rb +161 -0
  46. data/spec/unpacker_spec.rb +113 -1
  47. metadata +19 -51
  48. data/.travis.yml +0 -41
  49. data/README.rdoc +0 -201
@@ -27,6 +27,7 @@ import static org.jruby.runtime.Visibility.PRIVATE;
27
27
 
28
28
  @JRubyClass(name="MessagePack::Unpacker")
29
29
  public class Unpacker extends RubyObject {
30
+ private static final long serialVersionUID = 8451264671199362492L;
30
31
  private final ExtensionRegistry registry;
31
32
 
32
33
  private IRubyObject stream;
@@ -34,6 +35,7 @@ public class Unpacker extends RubyObject {
34
35
  private Decoder decoder;
35
36
  private final RubyClass underflowErrorClass;
36
37
  private boolean symbolizeKeys;
38
+ private boolean freeze;
37
39
  private boolean allowUnknownExt;
38
40
 
39
41
  public Unpacker(Ruby runtime, RubyClass type) {
@@ -56,19 +58,25 @@ public class Unpacker extends RubyObject {
56
58
  public IRubyObject initialize(ThreadContext ctx, IRubyObject[] args) {
57
59
  symbolizeKeys = false;
58
60
  allowUnknownExt = false;
61
+ freeze = false;
59
62
  if (args.length > 0) {
63
+ Ruby runtime = ctx.runtime;
60
64
  if (args[args.length - 1] instanceof RubyHash) {
61
65
  RubyHash options = (RubyHash) args[args.length - 1];
62
- IRubyObject sk = options.fastARef(ctx.getRuntime().newSymbol("symbolize_keys"));
66
+ IRubyObject sk = options.fastARef(runtime.newSymbol("symbolize_keys"));
63
67
  if (sk != null) {
64
68
  symbolizeKeys = sk.isTrue();
65
69
  }
66
- IRubyObject au = options.fastARef(ctx.getRuntime().newSymbol("allow_unknown_ext"));
70
+ IRubyObject f = options.fastARef(runtime.newSymbol("freeze"));
71
+ if (f != null) {
72
+ freeze = f.isTrue();
73
+ }
74
+ IRubyObject au = options.fastARef(runtime.newSymbol("allow_unknown_ext"));
67
75
  if (au != null) {
68
76
  allowUnknownExt = au.isTrue();
69
77
  }
70
78
  }
71
- if (args[0] != ctx.getRuntime().getNil() && !(args[0] instanceof RubyHash)) {
79
+ if (args[0] != runtime.getNil() && !(args[0] instanceof RubyHash)) {
72
80
  setStream(ctx, args[0]);
73
81
  }
74
82
  }
@@ -76,19 +84,24 @@ public class Unpacker extends RubyObject {
76
84
  }
77
85
 
78
86
  public static Unpacker newUnpacker(ThreadContext ctx, ExtensionRegistry extRegistry, IRubyObject[] args) {
79
- Unpacker unpacker = new Unpacker(ctx.getRuntime(), ctx.getRuntime().getModule("MessagePack").getClass("Unpacker"), extRegistry);
87
+ Unpacker unpacker = new Unpacker(ctx.runtime, ctx.runtime.getModule("MessagePack").getClass("Unpacker"), extRegistry);
80
88
  unpacker.initialize(ctx, args);
81
89
  return unpacker;
82
90
  }
83
91
 
84
92
  @JRubyMethod(name = "symbolize_keys?")
85
93
  public IRubyObject isSymbolizeKeys(ThreadContext ctx) {
86
- return symbolizeKeys ? ctx.getRuntime().getTrue() : ctx.getRuntime().getFalse();
94
+ return symbolizeKeys ? ctx.runtime.getTrue() : ctx.runtime.getFalse();
95
+ }
96
+
97
+ @JRubyMethod(name = "freeze?")
98
+ public IRubyObject isFreeze(ThreadContext ctx) {
99
+ return freeze ? ctx.runtime.getTrue() : ctx.runtime.getFalse();
87
100
  }
88
101
 
89
102
  @JRubyMethod(name = "allow_unknown_ext?")
90
103
  public IRubyObject isAllowUnknownExt(ThreadContext ctx) {
91
- return allowUnknownExt ? ctx.getRuntime().getTrue() : ctx.getRuntime().getFalse();
104
+ return allowUnknownExt ? ctx.runtime.getTrue() : ctx.runtime.getFalse();
92
105
  }
93
106
 
94
107
  @JRubyMethod(name = "registered_types_internal", visibility = PRIVATE)
@@ -98,7 +111,7 @@ public class Unpacker extends RubyObject {
98
111
 
99
112
  @JRubyMethod(name = "register_type", required = 1, optional = 2)
100
113
  public IRubyObject registerType(ThreadContext ctx, IRubyObject[] args, final Block block) {
101
- Ruby runtime = ctx.getRuntime();
114
+ Ruby runtime = ctx.runtime;
102
115
  IRubyObject type = args[0];
103
116
 
104
117
  RubyModule extModule;
@@ -144,7 +157,7 @@ public class Unpacker extends RubyObject {
144
157
  if (limit == -1) {
145
158
  limit = byteList.length() - offset;
146
159
  }
147
- Decoder decoder = new Decoder(ctx.getRuntime(), registry, byteList.unsafeBytes(), byteList.begin() + offset, limit, symbolizeKeys, allowUnknownExt);
160
+ Decoder decoder = new Decoder(ctx.runtime, registry, byteList.unsafeBytes(), byteList.begin() + offset, limit, symbolizeKeys, freeze, allowUnknownExt);
148
161
  try {
149
162
  data = null;
150
163
  data = decoder.next();
@@ -153,13 +166,13 @@ public class Unpacker extends RubyObject {
153
166
  throw re;
154
167
  }
155
168
  }
156
- return ctx.getRuntime().newFixnum(decoder.offset());
169
+ return ctx.runtime.newFixnum(decoder.offset());
157
170
  }
158
171
 
159
172
  @JRubyMethod(name = "data")
160
173
  public IRubyObject getData(ThreadContext ctx) {
161
174
  if (data == null) {
162
- return ctx.getRuntime().getNil();
175
+ return ctx.runtime.getNil();
163
176
  } else {
164
177
  return data;
165
178
  }
@@ -167,14 +180,14 @@ public class Unpacker extends RubyObject {
167
180
 
168
181
  @JRubyMethod(name = "finished?")
169
182
  public IRubyObject finished_p(ThreadContext ctx) {
170
- return data == null ? ctx.getRuntime().getFalse() : ctx.getRuntime().getTrue();
183
+ return data == null ? ctx.runtime.getFalse() : ctx.runtime.getTrue();
171
184
  }
172
185
 
173
- @JRubyMethod(required = 1)
186
+ @JRubyMethod(required = 1, name = "feed", alias = { "feed_reference" })
174
187
  public IRubyObject feed(ThreadContext ctx, IRubyObject data) {
175
188
  ByteList byteList = data.asString().getByteList();
176
189
  if (decoder == null) {
177
- decoder = new Decoder(ctx.getRuntime(), registry, byteList.unsafeBytes(), byteList.begin(), byteList.length(), symbolizeKeys, allowUnknownExt);
190
+ decoder = new Decoder(ctx.runtime, registry, byteList.unsafeBytes(), byteList.begin(), byteList.length(), symbolizeKeys, freeze, allowUnknownExt);
178
191
  } else {
179
192
  decoder.feed(byteList.unsafeBytes(), byteList.begin(), byteList.length());
180
193
  }
@@ -191,7 +204,7 @@ public class Unpacker extends RubyObject {
191
204
  feed(ctx, data);
192
205
  if (block.isGiven()) {
193
206
  each(ctx, block);
194
- return ctx.getRuntime().getNil();
207
+ return ctx.runtime.getNil();
195
208
  } else {
196
209
  return callMethod(ctx, "to_enum");
197
210
  }
@@ -219,7 +232,7 @@ public class Unpacker extends RubyObject {
219
232
 
220
233
  @JRubyMethod
221
234
  public IRubyObject fill(ThreadContext ctx) {
222
- return ctx.getRuntime().getNil();
235
+ return ctx.runtime.getNil();
223
236
  }
224
237
 
225
238
  @JRubyMethod
@@ -227,13 +240,13 @@ public class Unpacker extends RubyObject {
227
240
  if (decoder != null) {
228
241
  decoder.reset();
229
242
  }
230
- return ctx.getRuntime().getNil();
243
+ return ctx.runtime.getNil();
231
244
  }
232
245
 
233
246
  @JRubyMethod(name = "read", alias = { "unpack" })
234
247
  public IRubyObject read(ThreadContext ctx) {
235
248
  if (decoder == null) {
236
- throw ctx.getRuntime().newEOFError();
249
+ throw ctx.runtime.newEOFError();
237
250
  }
238
251
  try {
239
252
  return decoder.next();
@@ -241,19 +254,19 @@ public class Unpacker extends RubyObject {
241
254
  if (re.getException().getType() != underflowErrorClass) {
242
255
  throw re;
243
256
  } else {
244
- throw ctx.getRuntime().newEOFError();
257
+ throw ctx.runtime.newEOFError();
245
258
  }
246
259
  }
247
260
  }
248
261
 
249
262
  @JRubyMethod(name = "skip")
250
263
  public IRubyObject skip(ThreadContext ctx) {
251
- throw ctx.getRuntime().newNotImplementedError("Not supported yet in JRuby implementation");
264
+ throw ctx.runtime.newNotImplementedError("Not supported yet in JRuby implementation");
252
265
  }
253
266
 
254
267
  @JRubyMethod(name = "skip_nil")
255
268
  public IRubyObject skipNil(ThreadContext ctx) {
256
- throw ctx.getRuntime().newNotImplementedError("Not supported yet in JRuby implementation");
269
+ throw ctx.runtime.newNotImplementedError("Not supported yet in JRuby implementation");
257
270
  }
258
271
 
259
272
  @JRubyMethod
@@ -265,11 +278,11 @@ public class Unpacker extends RubyObject {
265
278
  if (re.getException().getType() != underflowErrorClass) {
266
279
  throw re;
267
280
  } else {
268
- throw ctx.getRuntime().newEOFError();
281
+ throw ctx.runtime.newEOFError();
269
282
  }
270
283
  }
271
284
  }
272
- return ctx.getRuntime().getNil();
285
+ return ctx.runtime.getNil();
273
286
  }
274
287
 
275
288
  @JRubyMethod
@@ -281,17 +294,17 @@ public class Unpacker extends RubyObject {
281
294
  if (re.getException().getType() != underflowErrorClass) {
282
295
  throw re;
283
296
  } else {
284
- throw ctx.getRuntime().newEOFError();
297
+ throw ctx.runtime.newEOFError();
285
298
  }
286
299
  }
287
300
  }
288
- return ctx.getRuntime().getNil();
301
+ return ctx.runtime.getNil();
289
302
  }
290
303
 
291
304
  @JRubyMethod(name = "stream")
292
305
  public IRubyObject getStream(ThreadContext ctx) {
293
306
  if (stream == null) {
294
- return ctx.getRuntime().getNil();
307
+ return ctx.runtime.getNil();
295
308
  } else {
296
309
  return stream;
297
310
  }
@@ -307,12 +320,12 @@ public class Unpacker extends RubyObject {
307
320
  } else if (stream.respondsTo("read")) {
308
321
  str = stream.callMethod(ctx, "read").asString();
309
322
  } else {
310
- throw ctx.getRuntime().newTypeError(stream, "IO");
323
+ throw ctx.runtime.newTypeError(stream, "IO");
311
324
  }
312
325
  ByteList byteList = str.getByteList();
313
326
  this.stream = stream;
314
327
  this.decoder = null;
315
- this.decoder = new Decoder(ctx.getRuntime(), registry, byteList.unsafeBytes(), byteList.begin(), byteList.length(), symbolizeKeys, allowUnknownExt);
328
+ this.decoder = new Decoder(ctx.runtime, registry, byteList.unsafeBytes(), byteList.begin(), byteList.length(), symbolizeKeys, freeze, allowUnknownExt);
316
329
  return getStream(ctx);
317
330
  }
318
331
  }
data/ext/msgpack/buffer.c CHANGED
@@ -23,11 +23,11 @@
23
23
  static ID s_replace;
24
24
  #endif
25
25
 
26
- #ifdef COMPAT_HAVE_ENCODING /* see compat.h*/
27
26
  int msgpack_rb_encindex_utf8;
28
27
  int msgpack_rb_encindex_usascii;
29
28
  int msgpack_rb_encindex_ascii8bit;
30
- #endif
29
+
30
+ ID s_uminus;
31
31
 
32
32
  #ifndef DISABLE_RMEM
33
33
  static msgpack_rmem_t s_rmem;
@@ -35,11 +35,11 @@ static msgpack_rmem_t s_rmem;
35
35
 
36
36
  void msgpack_buffer_static_init()
37
37
  {
38
- #ifdef COMPAT_HAVE_ENCODING
38
+ s_uminus = rb_intern("-@");
39
+
39
40
  msgpack_rb_encindex_utf8 = rb_utf8_encindex();
40
41
  msgpack_rb_encindex_usascii = rb_usascii_encindex();
41
42
  msgpack_rb_encindex_ascii8bit = rb_ascii8bit_encindex();
42
- #endif
43
43
 
44
44
  #ifndef DISABLE_RMEM
45
45
  msgpack_rmem_init(&s_rmem);
@@ -164,12 +164,7 @@ size_t msgpack_buffer_read_to_string_nonblock(msgpack_buffer_t* b, VALUE string,
164
164
  b->head->mapped_string != NO_MAPPED_STRING &&
165
165
  length >= b->read_reference_threshold) {
166
166
  VALUE s = _msgpack_buffer_refer_head_mapped_string(b, length);
167
- #ifndef HAVE_RB_STR_REPLACE
168
- /* TODO MRI 1.8 */
169
- rb_funcall(string, s_replace, 1, s);
170
- #else
171
167
  rb_str_replace(string, s);
172
- #endif
173
168
  /* here doesn't have to call ENCODING_SET because
174
169
  * encoding of s is always ASCII-8BIT */
175
170
  _msgpack_buffer_consumed(b, length);
@@ -308,9 +303,7 @@ static inline void _msgpack_buffer_add_new_chunk(msgpack_buffer_t* b)
308
303
  static inline void _msgpack_buffer_append_reference(msgpack_buffer_t* b, VALUE string)
309
304
  {
310
305
  VALUE mapped_string = rb_str_dup(string);
311
- #ifdef COMPAT_HAVE_ENCODING
312
306
  ENCODING_SET(mapped_string, msgpack_rb_encindex_ascii8bit);
313
- #endif
314
307
 
315
308
  _msgpack_buffer_add_new_chunk(b);
316
309
 
@@ -337,7 +330,6 @@ void _msgpack_buffer_append_long_string(msgpack_buffer_t* b, VALUE string)
337
330
 
338
331
  if(b->io != Qnil) {
339
332
  msgpack_buffer_flush(b);
340
- #ifdef COMPAT_HAVE_ENCODING
341
333
  if (ENCODING_GET(string) == msgpack_rb_encindex_ascii8bit) {
342
334
  rb_funcall(b->io, b->io_write_all_method, 1, string);
343
335
  } else if(!STR_DUP_LIKELY_DOES_COPY(string)) {
@@ -347,10 +339,6 @@ void _msgpack_buffer_append_long_string(msgpack_buffer_t* b, VALUE string)
347
339
  } else {
348
340
  msgpack_buffer_append(b, RSTRING_PTR(string), length);
349
341
  }
350
- #else
351
- rb_funcall(b->io, b->io_write_all_method, 1, string);
352
- #endif
353
-
354
342
  } else if(!STR_DUP_LIKELY_DOES_COPY(string)) {
355
343
  _msgpack_buffer_append_reference(b, string);
356
344
 
data/ext/msgpack/buffer.h CHANGED
@@ -49,11 +49,11 @@
49
49
 
50
50
  #define NO_MAPPED_STRING ((VALUE)0)
51
51
 
52
- #ifdef COMPAT_HAVE_ENCODING /* see compat.h*/
53
52
  extern int msgpack_rb_encindex_utf8;
54
53
  extern int msgpack_rb_encindex_usascii;
55
54
  extern int msgpack_rb_encindex_ascii8bit;
56
- #endif
55
+
56
+ extern ID s_uminus;
57
57
 
58
58
  struct msgpack_buffer_chunk_t;
59
59
  typedef struct msgpack_buffer_chunk_t msgpack_buffer_chunk_t;
@@ -262,6 +262,20 @@ static inline size_t msgpack_buffer_append_string(msgpack_buffer_t* b, VALUE str
262
262
  return length;
263
263
  }
264
264
 
265
+ static inline size_t msgpack_buffer_append_string_reference(msgpack_buffer_t* b, VALUE string)
266
+ {
267
+ size_t length = RSTRING_LEN(string);
268
+
269
+ if(length > MSGPACK_BUFFER_STRING_WRITE_REFERENCE_MINIMUM) {
270
+ _msgpack_buffer_append_long_string(b, string);
271
+
272
+ } else {
273
+ msgpack_buffer_append(b, RSTRING_PTR(string), length);
274
+ }
275
+
276
+ return length;
277
+ }
278
+
265
279
 
266
280
  /*
267
281
  * IO functions
@@ -424,7 +438,7 @@ static inline VALUE _msgpack_buffer_refer_head_mapped_string(msgpack_buffer_t* b
424
438
  return rb_str_substr(b->head->mapped_string, offset, length);
425
439
  }
426
440
 
427
- static inline VALUE msgpack_buffer_read_top_as_string(msgpack_buffer_t* b, size_t length, bool will_be_frozen)
441
+ static inline VALUE msgpack_buffer_read_top_as_string(msgpack_buffer_t* b, size_t length, bool will_be_frozen, bool utf8)
428
442
  {
429
443
  #ifndef DISABLE_BUFFER_READ_REFERENCE_OPTIMIZE
430
444
  /* optimize */
@@ -432,16 +446,57 @@ static inline VALUE msgpack_buffer_read_top_as_string(msgpack_buffer_t* b, size_
432
446
  b->head->mapped_string != NO_MAPPED_STRING &&
433
447
  length >= b->read_reference_threshold) {
434
448
  VALUE result = _msgpack_buffer_refer_head_mapped_string(b, length);
449
+ if (utf8) ENCODING_SET(result, msgpack_rb_encindex_utf8);
435
450
  _msgpack_buffer_consumed(b, length);
436
451
  return result;
437
452
  }
438
453
  #endif
439
454
 
440
- VALUE result = rb_str_new(b->read_buffer, length);
455
+ VALUE result;
456
+
457
+ #ifdef HAVE_RB_ENC_INTERNED_STR
458
+ if (will_be_frozen) {
459
+ result = rb_enc_interned_str(b->read_buffer, length, utf8 ? rb_utf8_encoding() : rb_ascii8bit_encoding());
460
+ } else {
461
+ if (utf8) {
462
+ result = rb_utf8_str_new(b->read_buffer, length);
463
+ } else {
464
+ result = rb_str_new(b->read_buffer, length);
465
+ }
466
+ }
441
467
  _msgpack_buffer_consumed(b, length);
442
468
  return result;
469
+
470
+ #else
471
+
472
+ if (utf8) {
473
+ result = rb_utf8_str_new(b->read_buffer, length);
474
+ } else {
475
+ result = rb_str_new(b->read_buffer, length);
476
+ }
477
+
478
+ #if STR_UMINUS_DEDUPE
479
+ if (will_be_frozen) {
480
+ #if STR_UMINUS_DEDUPE_FROZEN
481
+ // Starting from MRI 2.8 it is preferable to freeze the string
482
+ // before deduplication so that it can be interned directly
483
+ // otherwise it would be duplicated first which is wasteful.
484
+ rb_str_freeze(result);
485
+ #endif //STR_UMINUS_DEDUPE_FROZEN
486
+ // MRI 2.5 and older do not deduplicate strings that are already
487
+ // frozen.
488
+ result = rb_funcall(result, s_uminus, 0);
489
+ }
490
+ #endif // STR_UMINUS_DEDUPE
491
+ _msgpack_buffer_consumed(b, length);
492
+ return result;
493
+
494
+ #endif // HAVE_RB_ENC_INTERNED_STR
443
495
  }
444
496
 
497
+ static inline VALUE msgpack_buffer_read_top_as_symbol(msgpack_buffer_t* b, size_t length)
498
+ {
499
+ return rb_str_intern(msgpack_buffer_read_top_as_string(b, length, true, false));
500
+ }
445
501
 
446
502
  #endif
447
-
data/ext/msgpack/compat.h CHANGED
@@ -20,6 +20,7 @@
20
20
 
21
21
  #include <stdbool.h>
22
22
  #include "ruby.h"
23
+ #include "ruby/encoding.h"
23
24
 
24
25
  #if defined(HAVE_RUBY_ST_H)
25
26
  # include "ruby/st.h" /* ruby hash on Ruby 1.9 */
@@ -38,18 +39,6 @@
38
39
  # define ZALLOC_N(type,n) RB_ZALLOC_N(type,n)
39
40
  #endif
40
41
 
41
- /*
42
- * COMPAT_HAVE_ENCODING
43
- */
44
- #ifdef HAVE_RUBY_ENCODING_H
45
- # include "ruby/encoding.h"
46
- # define COMPAT_HAVE_ENCODING
47
- #endif
48
-
49
- #if defined(__MACRUBY__) /* MacRuby */
50
- # undef COMPAT_HAVE_ENCODING
51
- #endif
52
-
53
42
 
54
43
  /*
55
44
  * define STR_DUP_LIKELY_DOES_COPY
@@ -2,13 +2,7 @@ require 'mkmf'
2
2
 
3
3
  have_header("ruby/st.h")
4
4
  have_header("st.h")
5
- have_func("rb_str_replace", ["ruby.h"])
6
- have_func("rb_intern_str", ["ruby.h"])
7
- have_func("rb_sym2str", ["ruby.h"])
8
- have_func("rb_str_intern", ["ruby.h"])
9
- have_func("rb_block_lambda", ["ruby.h"])
10
- have_func("rb_hash_dup", ["ruby.h"])
11
- have_func("rb_hash_clear", ["ruby.h"])
5
+ have_func("rb_enc_interned_str", "ruby.h")
12
6
 
13
7
  unless RUBY_PLATFORM.include? 'mswin'
14
8
  $CFLAGS << %[ -I.. -Wall -O3 -g -std=gnu99]
@@ -25,6 +19,44 @@ if defined?(RUBY_ENGINE) && RUBY_ENGINE == 'rbx'
25
19
  $CFLAGS << %[ -DDISABLE_RMEM]
26
20
  end
27
21
 
22
+ # checking if Hash#[]= (rb_hash_aset) dedupes string keys
23
+ h = {}
24
+ x = {}
25
+ r = rand.to_s
26
+ h[%W(#{r}).join('')] = :foo
27
+ x[%W(#{r}).join('')] = :foo
28
+ if x.keys[0].equal?(h.keys[0])
29
+ $CFLAGS << ' -DHASH_ASET_DEDUPE=1 '
30
+ else
31
+ $CFLAGS << ' -DHASH_ASET_DEDUPE=0 '
32
+ end
33
+
34
+
35
+ # checking if String#-@ (str_uminus) dedupes... '
36
+ begin
37
+ a = -(%w(t e s t).join)
38
+ b = -(%w(t e s t).join)
39
+ if a.equal?(b)
40
+ $CFLAGS << ' -DSTR_UMINUS_DEDUPE=1 '
41
+ else
42
+ $CFLAGS += ' -DSTR_UMINUS_DEDUPE=0 '
43
+ end
44
+ rescue NoMethodError
45
+ $CFLAGS << ' -DSTR_UMINUS_DEDUPE=0 '
46
+ end
47
+
48
+ # checking if String#-@ (str_uminus) directly interns frozen strings... '
49
+ begin
50
+ s = rand.to_s.freeze
51
+ if (-s).equal?(s) && (-s.dup).equal?(s)
52
+ $CFLAGS << ' -DSTR_UMINUS_DEDUPE_FROZEN=1 '
53
+ else
54
+ $CFLAGS << ' -DSTR_UMINUS_DEDUPE_FROZEN=0 '
55
+ end
56
+ rescue NoMethodError
57
+ $CFLAGS << ' -DSTR_UMINUS_DEDUPE_FROZEN=0 '
58
+ end
59
+
28
60
  if warnflags = CONFIG['warnflags']
29
61
  warnflags.slice!(/ -Wdeclaration-after-statement/)
30
62
  end
@@ -32,6 +32,8 @@ struct msgpack_factory_t {
32
32
  msgpack_packer_ext_registry_t pkrg;
33
33
  msgpack_unpacker_ext_registry_t ukrg;
34
34
  bool has_symbol_ext_type;
35
+ bool optimized_symbol_ext_type;
36
+ int symbol_ext_type;
35
37
  };
36
38
 
37
39
  #define FACTORY(from, name) \
@@ -114,6 +116,8 @@ VALUE MessagePack_Factory_unpacker(int argc, VALUE* argv, VALUE self)
114
116
 
115
117
  msgpack_unpacker_ext_registry_destroy(&uk->ext_registry);
116
118
  msgpack_unpacker_ext_registry_dup(&fc->ukrg, &uk->ext_registry);
119
+ uk->optimized_symbol_ext_type = fc->optimized_symbol_ext_type;
120
+ uk->symbol_ext_type = fc->symbol_ext_type;
117
121
 
118
122
  return unpacker;
119
123
  }
@@ -128,11 +132,7 @@ static VALUE Factory_registered_types_internal(VALUE self)
128
132
  rb_hash_aset(uk_mapping, INT2FIX(i - 128), fc->ukrg.array[i]);
129
133
  }
130
134
  }
131
- #ifdef HAVE_RB_HASH_DUP
132
135
  return rb_ary_new3(2, rb_hash_dup(fc->pkrg.hash), uk_mapping);
133
- #else
134
- return rb_ary_new3(2, rb_funcall(fc->pkrg.hash, rb_intern("dup"), 0), uk_mapping);
135
- #endif
136
136
  }
137
137
 
138
138
  static VALUE Factory_register_type(int argc, VALUE* argv, VALUE self)
@@ -141,7 +141,7 @@ static VALUE Factory_register_type(int argc, VALUE* argv, VALUE self)
141
141
 
142
142
  int ext_type;
143
143
  VALUE ext_module;
144
- VALUE options;
144
+ VALUE options = Qnil;
145
145
  VALUE packer_arg, unpacker_arg;
146
146
  VALUE packer_proc, unpacker_proc;
147
147
 
@@ -188,6 +188,8 @@ static VALUE Factory_register_type(int argc, VALUE* argv, VALUE self)
188
188
  if(unpacker_arg != Qnil) {
189
189
  if(rb_type(unpacker_arg) == T_SYMBOL || rb_type(unpacker_arg) == T_STRING) {
190
190
  unpacker_proc = rb_obj_method(ext_module, unpacker_arg);
191
+ } else if (rb_respond_to(unpacker_arg, rb_intern("call"))) {
192
+ unpacker_proc = unpacker_arg;
191
193
  } else {
192
194
  unpacker_proc = rb_funcall(unpacker_arg, rb_intern("method"), 1, ID2SYM(rb_intern("call")));
193
195
  }
@@ -197,6 +199,9 @@ static VALUE Factory_register_type(int argc, VALUE* argv, VALUE self)
197
199
 
198
200
  if (ext_module == rb_cSymbol) {
199
201
  fc->has_symbol_ext_type = true;
202
+ if(RB_TEST(options) && RB_TEST(rb_hash_aref(options, ID2SYM(rb_intern("optimized_symbols_parsing"))))) {
203
+ fc->optimized_symbol_ext_type = true;
204
+ }
200
205
  }
201
206
 
202
207
  msgpack_unpacker_ext_registry_put(&fc->ukrg, ext_module, ext_type, unpacker_proc, unpacker_arg);
data/ext/msgpack/packer.c CHANGED
@@ -121,7 +121,7 @@ void msgpack_packer_write_hash_value(msgpack_packer_t* pk, VALUE v)
121
121
  #endif
122
122
  }
123
123
 
124
- void msgpack_packer_write_other_value(msgpack_packer_t* pk, VALUE v)
124
+ bool msgpack_packer_try_write_with_ext_type_lookup(msgpack_packer_t* pk, VALUE v)
125
125
  {
126
126
  int ext_type;
127
127
 
@@ -131,7 +131,14 @@ void msgpack_packer_write_other_value(msgpack_packer_t* pk, VALUE v)
131
131
  VALUE payload = rb_funcall(proc, s_call, 1, v);
132
132
  StringValue(payload);
133
133
  msgpack_packer_write_ext(pk, ext_type, payload);
134
- } else {
134
+ return true;
135
+ }
136
+ return false;
137
+ }
138
+
139
+ void msgpack_packer_write_other_value(msgpack_packer_t* pk, VALUE v)
140
+ {
141
+ if(!(msgpack_packer_try_write_with_ext_type_lookup(pk, v))) {
135
142
  rb_funcall(v, pk->to_msgpack_method, 1, pk->to_msgpack_arg);
136
143
  }
137
144
  }
@@ -155,13 +162,19 @@ void msgpack_packer_write_value(msgpack_packer_t* pk, VALUE v)
155
162
  msgpack_packer_write_symbol_value(pk, v);
156
163
  break;
157
164
  case T_STRING:
158
- msgpack_packer_write_string_value(pk, v);
165
+ if(rb_class_of(v) == rb_cString || !msgpack_packer_try_write_with_ext_type_lookup(pk, v)) {
166
+ msgpack_packer_write_string_value(pk, v);
167
+ }
159
168
  break;
160
169
  case T_ARRAY:
161
- msgpack_packer_write_array_value(pk, v);
170
+ if(rb_class_of(v) == rb_cArray || !msgpack_packer_try_write_with_ext_type_lookup(pk, v)) {
171
+ msgpack_packer_write_array_value(pk, v);
172
+ }
162
173
  break;
163
174
  case T_HASH:
164
- msgpack_packer_write_hash_value(pk, v);
175
+ if(rb_class_of(v) == rb_cHash || !msgpack_packer_try_write_with_ext_type_lookup(pk, v)) {
176
+ msgpack_packer_write_hash_value(pk, v);
177
+ }
165
178
  break;
166
179
  case T_BIGNUM:
167
180
  msgpack_packer_write_bignum_value(pk, v);
data/ext/msgpack/packer.h CHANGED
@@ -396,7 +396,6 @@ static inline void msgpack_packer_write_ext(msgpack_packer_t* pk, int ext_type,
396
396
  msgpack_buffer_append_string(PACKER_BUFFER_(pk), payload);
397
397
  }
398
398
 
399
- #ifdef COMPAT_HAVE_ENCODING
400
399
  static inline bool msgpack_packer_is_binary(VALUE v, int encindex)
401
400
  {
402
401
  return encindex == msgpack_rb_encindex_ascii8bit;
@@ -414,7 +413,6 @@ static inline bool msgpack_packer_is_utf8_compat_string(VALUE v, int encindex)
414
413
  #endif
415
414
  ;
416
415
  }
417
- #endif
418
416
 
419
417
  static inline void msgpack_packer_write_string_value(msgpack_packer_t* pk, VALUE v)
420
418
  {
@@ -425,7 +423,6 @@ static inline void msgpack_packer_write_string_value(msgpack_packer_t* pk, VALUE
425
423
  rb_raise(rb_eArgError, "size of string is too long to pack: %lu bytes should be <= %lu", len, 0xffffffffUL);
426
424
  }
427
425
 
428
- #ifdef COMPAT_HAVE_ENCODING
429
426
  int encindex = ENCODING_GET(v);
430
427
  if(msgpack_packer_is_binary(v, encindex) && !pk->compatibility_mode) {
431
428
  /* write ASCII-8BIT string using Binary type */
@@ -443,24 +440,11 @@ static inline void msgpack_packer_write_string_value(msgpack_packer_t* pk, VALUE
443
440
  msgpack_packer_write_raw_header(pk, (unsigned int)len);
444
441
  msgpack_buffer_append_string(PACKER_BUFFER_(pk), v);
445
442
  }
446
- #else
447
- msgpack_packer_write_raw_header(pk, (unsigned int)len);
448
- msgpack_buffer_append_string(PACKER_BUFFER_(pk), v);
449
- #endif
450
443
  }
451
444
 
452
445
  static inline void msgpack_packer_write_symbol_string_value(msgpack_packer_t* pk, VALUE v)
453
446
  {
454
- #ifdef HAVE_RB_SYM2STR
455
- /* rb_sym2str is added since MRI 2.2.0 */
456
447
  msgpack_packer_write_string_value(pk, rb_sym2str(v));
457
- #else
458
- VALUE str = rb_id2str(SYM2ID(v));
459
- if (!str) {
460
- rb_raise(rb_eRuntimeError, "could not convert a symbol to string");
461
- }
462
- msgpack_packer_write_string_value(pk, str);
463
- #endif
464
448
  }
465
449
 
466
450
  void msgpack_packer_write_other_value(msgpack_packer_t* pk, VALUE v);