msgpack 1.4.5 → 1.5.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yaml +5 -5
  3. data/ChangeLog +32 -0
  4. data/README.md +25 -1
  5. data/bench/bench.rb +78 -0
  6. data/doclib/msgpack/factory.rb +45 -2
  7. data/ext/java/org/msgpack/jruby/Buffer.java +6 -0
  8. data/ext/java/org/msgpack/jruby/Decoder.java +23 -19
  9. data/ext/java/org/msgpack/jruby/Encoder.java +46 -18
  10. data/ext/java/org/msgpack/jruby/ExtensionRegistry.java +24 -31
  11. data/ext/java/org/msgpack/jruby/Factory.java +40 -5
  12. data/ext/java/org/msgpack/jruby/Packer.java +21 -11
  13. data/ext/java/org/msgpack/jruby/Unpacker.java +44 -22
  14. data/ext/msgpack/buffer.c +9 -36
  15. data/ext/msgpack/buffer.h +9 -1
  16. data/ext/msgpack/buffer_class.c +18 -9
  17. data/ext/msgpack/compat.h +0 -99
  18. data/ext/msgpack/extconf.rb +9 -11
  19. data/ext/msgpack/factory_class.c +62 -5
  20. data/ext/msgpack/packer.c +42 -29
  21. data/ext/msgpack/packer.h +25 -7
  22. data/ext/msgpack/packer_class.c +23 -20
  23. data/ext/msgpack/packer_ext_registry.c +13 -4
  24. data/ext/msgpack/packer_ext_registry.h +10 -5
  25. data/ext/msgpack/unpacker.c +99 -68
  26. data/ext/msgpack/unpacker.h +10 -6
  27. data/ext/msgpack/unpacker_class.c +16 -8
  28. data/ext/msgpack/unpacker_ext_registry.c +3 -2
  29. data/ext/msgpack/unpacker_ext_registry.h +5 -2
  30. data/lib/msgpack/bigint.rb +69 -0
  31. data/lib/msgpack/factory.rb +103 -0
  32. data/lib/msgpack/version.rb +1 -1
  33. data/lib/msgpack.rb +4 -5
  34. data/msgpack.gemspec +1 -0
  35. data/spec/bigint_spec.rb +26 -0
  36. data/spec/factory_spec.rb +248 -0
  37. data/spec/spec_helper.rb +9 -1
  38. data/spec/timestamp_spec.rb +2 -2
  39. data/spec/unpacker_spec.rb +12 -0
  40. metadata +20 -13
  41. data/bench/pack.rb +0 -23
  42. data/bench/pack_log.rb +0 -33
  43. data/bench/pack_log_long.rb +0 -65
  44. data/bench/pack_symbols.rb +0 -28
  45. data/bench/run.sh +0 -14
  46. data/bench/run_long.sh +0 -35
  47. data/bench/run_symbols.sh +0 -26
  48. data/bench/unpack.rb +0 -21
  49. data/bench/unpack_log.rb +0 -34
  50. data/bench/unpack_log_long.rb +0 -67
@@ -12,6 +12,8 @@ import org.jruby.RubyInteger;
12
12
  import org.jruby.RubyFixnum;
13
13
  import org.jruby.RubyString;
14
14
  import org.jruby.RubySymbol;
15
+ import org.jruby.RubyProc;
16
+ import org.jruby.RubyMethod;
15
17
  import org.jruby.runtime.builtin.IRubyObject;
16
18
  import org.jruby.anno.JRubyClass;
17
19
  import org.jruby.anno.JRubyMethod;
@@ -25,14 +27,16 @@ import static org.jruby.runtime.Visibility.PRIVATE;
25
27
  public class Factory extends RubyObject {
26
28
  private static final long serialVersionUID = 8441284623445322492L;
27
29
  private final Ruby runtime;
28
- private final ExtensionRegistry extensionRegistry;
30
+ private ExtensionRegistry extensionRegistry;
29
31
  private boolean hasSymbolExtType;
32
+ private boolean hasBigIntExtType;
30
33
 
31
34
  public Factory(Ruby runtime, RubyClass type) {
32
35
  super(runtime, type);
33
36
  this.runtime = runtime;
34
37
  this.extensionRegistry = new ExtensionRegistry();
35
38
  this.hasSymbolExtType = false;
39
+ this.hasBigIntExtType = false;
36
40
  }
37
41
 
38
42
  static class FactoryAllocator implements ObjectAllocator {
@@ -50,9 +54,17 @@ public class Factory extends RubyObject {
50
54
  return this;
51
55
  }
52
56
 
53
- @JRubyMethod(name = "packer", optional = 1)
57
+ @JRubyMethod(name = "dup")
58
+ public IRubyObject dup() {
59
+ Factory clone = (Factory)super.dup();
60
+ clone.extensionRegistry = extensionRegistry();
61
+ clone.hasSymbolExtType = hasSymbolExtType;
62
+ return clone;
63
+ }
64
+
65
+ @JRubyMethod(name = "packer", optional = 2)
54
66
  public Packer packer(ThreadContext ctx, IRubyObject[] args) {
55
- return Packer.newPacker(ctx, extensionRegistry(), hasSymbolExtType, args);
67
+ return Packer.newPacker(ctx, extensionRegistry(), hasSymbolExtType, hasBigIntExtType, args);
56
68
  }
57
69
 
58
70
  @JRubyMethod(name = "unpacker", optional = 2)
@@ -77,6 +89,8 @@ public class Factory extends RubyObject {
77
89
  IRubyObject packerArg;
78
90
  IRubyObject unpackerArg;
79
91
 
92
+ RubyHash options = null;
93
+
80
94
  if (isFrozen()) {
81
95
  throw runtime.newRuntimeError("can't modify frozen Factory");
82
96
  }
@@ -86,7 +100,7 @@ public class Factory extends RubyObject {
86
100
  unpackerArg = runtime.newSymbol("from_msgpack_ext");
87
101
  } else if (args.length == 3) {
88
102
  if (args[args.length - 1] instanceof RubyHash) {
89
- RubyHash options = (RubyHash) args[args.length - 1];
103
+ options = (RubyHash) args[args.length - 1];
90
104
  packerArg = options.fastARef(runtime.newSymbol("packer"));
91
105
  unpackerArg = options.fastARef(runtime.newSymbol("unpacker"));
92
106
  IRubyObject optimizedSymbolsParsingArg = options.fastARef(runtime.newSymbol("optimized_symbols_parsing"));
@@ -118,17 +132,38 @@ public class Factory extends RubyObject {
118
132
  if (unpackerArg != null) {
119
133
  if (unpackerArg instanceof RubyString || unpackerArg instanceof RubySymbol) {
120
134
  unpackerProc = extModule.method(unpackerArg.callMethod(ctx, "to_sym"));
135
+ } else if (unpackerArg instanceof RubyProc || unpackerArg instanceof RubyMethod) {
136
+ unpackerProc = unpackerArg;
121
137
  } else {
122
138
  unpackerProc = unpackerArg.callMethod(ctx, "method", runtime.newSymbol("call"));
123
139
  }
124
140
  }
125
141
 
126
- extensionRegistry.put(extModule, (int) typeId, packerProc, packerArg, unpackerProc, unpackerArg);
142
+ boolean recursive = false;
143
+ if (options != null) {
144
+ IRubyObject recursiveExtensionArg = options.fastARef(runtime.newSymbol("recursive"));
145
+ if (recursiveExtensionArg != null && recursiveExtensionArg.isTrue()) {
146
+ recursive = true;
147
+ }
148
+ }
149
+
150
+ extensionRegistry.put(extModule, (int) typeId, recursive, packerProc, packerArg, unpackerProc, unpackerArg);
127
151
 
128
152
  if (extModule == runtime.getSymbol()) {
129
153
  hasSymbolExtType = true;
130
154
  }
131
155
 
156
+ if (options != null) {
157
+ IRubyObject oversizedIntegerExtensionArg = options.fastARef(runtime.newSymbol("oversized_integer_extension"));
158
+ if (oversizedIntegerExtensionArg != null && oversizedIntegerExtensionArg.isTrue()) {
159
+ if (extModule == runtime.getModule("Integer")) {
160
+ hasBigIntExtType = true;
161
+ } else {
162
+ throw runtime.newArgumentError("oversized_integer_extension: true is only for Integer class");
163
+ }
164
+ }
165
+ }
166
+
132
167
  return runtime.getNil();
133
168
  }
134
169
  }
@@ -32,17 +32,19 @@ public class Packer extends RubyObject {
32
32
  private Buffer buffer;
33
33
  private Encoder encoder;
34
34
  private boolean hasSymbolExtType;
35
+ private boolean hasBigintExtType;
35
36
  private Encoding binaryEncoding;
36
37
 
37
- public Packer(Ruby runtime, RubyClass type, ExtensionRegistry registry, boolean hasSymbolExtType) {
38
+ public Packer(Ruby runtime, RubyClass type, ExtensionRegistry registry, boolean hasSymbolExtType, boolean hasBigintExtType) {
38
39
  super(runtime, type);
39
40
  this.registry = registry;
40
41
  this.hasSymbolExtType = hasSymbolExtType;
42
+ this.hasBigintExtType = hasBigintExtType;
41
43
  }
42
44
 
43
45
  static class PackerAllocator implements ObjectAllocator {
44
46
  public IRubyObject allocate(Ruby runtime, RubyClass type) {
45
- return new Packer(runtime, type, null, false);
47
+ return new Packer(runtime, type, null, false, false);
46
48
  }
47
49
  }
48
50
 
@@ -50,25 +52,33 @@ public class Packer extends RubyObject {
50
52
  public IRubyObject initialize(ThreadContext ctx, IRubyObject[] args) {
51
53
  boolean compatibilityMode = false;
52
54
  Ruby runtime = ctx.runtime;
53
- if (args.length > 0 && args[args.length - 1] instanceof RubyHash) {
54
- RubyHash options = (RubyHash) args[args.length - 1];
55
- IRubyObject mode = options.fastARef(runtime.newSymbol("compatibility_mode"));
56
- compatibilityMode = (mode != null) && mode.isTrue();
55
+ if (args.length > 0) {
56
+ RubyHash options = null;
57
+ if (args[args.length - 1] instanceof RubyHash) {
58
+ options = (RubyHash) args[args.length - 1];
59
+ } else if (args.length > 1 && args[args.length - 2] instanceof RubyHash) {
60
+ options = (RubyHash) args[args.length - 2];
61
+ }
62
+
63
+ if (options != null) {
64
+ IRubyObject mode = options.fastARef(runtime.newSymbol("compatibility_mode"));
65
+ compatibilityMode = (mode != null) && mode.isTrue();
66
+ }
57
67
  }
58
68
  if (registry == null) {
59
69
  // registry is null when allocate -> initialize
60
70
  // registry is already initialized (and somthing might be registered) when newPacker from Factory
61
71
  this.registry = new ExtensionRegistry();
62
72
  }
63
- this.encoder = new Encoder(runtime, compatibilityMode, registry, hasSymbolExtType);
73
+ this.encoder = new Encoder(runtime, this, compatibilityMode, registry, hasSymbolExtType, hasBigintExtType);
64
74
  this.buffer = new Buffer(runtime, runtime.getModule("MessagePack").getClass("Buffer"));
65
75
  this.buffer.initialize(ctx, args);
66
76
  this.binaryEncoding = runtime.getEncodingService().getAscii8bitEncoding();
67
77
  return this;
68
78
  }
69
79
 
70
- public static Packer newPacker(ThreadContext ctx, ExtensionRegistry extRegistry, boolean hasSymbolExtType, IRubyObject[] args) {
71
- Packer packer = new Packer(ctx.runtime, ctx.runtime.getModule("MessagePack").getClass("Packer"), extRegistry, hasSymbolExtType);
80
+ public static Packer newPacker(ThreadContext ctx, ExtensionRegistry extRegistry, boolean hasSymbolExtType, boolean hasBigintExtType, IRubyObject[] args) {
81
+ Packer packer = new Packer(ctx.runtime, ctx.runtime.getModule("MessagePack").getClass("Packer"), extRegistry, hasSymbolExtType, hasBigintExtType);
72
82
  packer.initialize(ctx, args);
73
83
  return packer;
74
84
  }
@@ -114,7 +124,7 @@ public class Packer extends RubyObject {
114
124
  }
115
125
  RubyModule extModule = (RubyModule) mod;
116
126
 
117
- registry.put(extModule, (int) typeId, proc, arg, null, null);
127
+ registry.put(extModule, (int) typeId, false, proc, arg, null, null);
118
128
 
119
129
  if (extModule == runtime.getSymbol()) {
120
130
  encoder.hasSymbolExtType = true;
@@ -257,7 +267,7 @@ public class Packer extends RubyObject {
257
267
  return buffer.size(ctx);
258
268
  }
259
269
 
260
- @JRubyMethod(name = "clear")
270
+ @JRubyMethod(name = "clear", alias = { "reset" })
261
271
  public IRubyObject clear(ThreadContext ctx) {
262
272
  return buffer.clear(ctx);
263
273
  }
@@ -56,30 +56,48 @@ public class Unpacker extends RubyObject {
56
56
 
57
57
  @JRubyMethod(name = "initialize", optional = 2, visibility = PRIVATE)
58
58
  public IRubyObject initialize(ThreadContext ctx, IRubyObject[] args) {
59
+ Ruby runtime = ctx.runtime;
60
+
59
61
  symbolizeKeys = false;
60
62
  allowUnknownExt = false;
61
63
  freeze = false;
62
- if (args.length > 0) {
63
- Ruby runtime = ctx.runtime;
64
- if (args[args.length - 1] instanceof RubyHash) {
65
- RubyHash options = (RubyHash) args[args.length - 1];
66
- IRubyObject sk = options.fastARef(runtime.newSymbol("symbolize_keys"));
67
- if (sk != null) {
68
- symbolizeKeys = sk.isTrue();
69
- }
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"));
75
- if (au != null) {
76
- allowUnknownExt = au.isTrue();
77
- }
64
+
65
+ IRubyObject io = null;
66
+ RubyHash options = null;
67
+
68
+ if (args.length >= 1) {
69
+ io = args[0];
70
+ }
71
+
72
+ if (args.length >= 2 && args[1] != runtime.getNil()) {
73
+ options = (RubyHash)args[1];
74
+ }
75
+
76
+ if (options == null && io != null && io instanceof RubyHash) {
77
+ options = (RubyHash)io;
78
+ io = null;
79
+ }
80
+
81
+ if (options != null) {
82
+ IRubyObject sk = options.fastARef(runtime.newSymbol("symbolize_keys"));
83
+ if (sk != null) {
84
+ symbolizeKeys = sk.isTrue();
78
85
  }
79
- if (args[0] != runtime.getNil() && !(args[0] instanceof RubyHash)) {
80
- setStream(ctx, args[0]);
86
+ IRubyObject f = options.fastARef(runtime.newSymbol("freeze"));
87
+ if (f != null) {
88
+ freeze = f.isTrue();
81
89
  }
90
+ IRubyObject au = options.fastARef(runtime.newSymbol("allow_unknown_ext"));
91
+ if (au != null) {
92
+ allowUnknownExt = au.isTrue();
93
+ }
94
+
82
95
  }
96
+
97
+ if (io != null && io != runtime.getNil()) {
98
+ setStream(ctx, io);
99
+ }
100
+
83
101
  return this;
84
102
  }
85
103
 
@@ -139,7 +157,7 @@ public class Unpacker extends RubyObject {
139
157
  throw runtime.newRangeError(String.format("integer %d too big to convert to `signed char'", typeId));
140
158
  }
141
159
 
142
- registry.put(extModule, (int) typeId, null, null, proc, arg);
160
+ registry.put(extModule, (int) typeId, false, null, null, proc, arg);
143
161
  return runtime.getNil();
144
162
  }
145
163
 
@@ -157,7 +175,7 @@ public class Unpacker extends RubyObject {
157
175
  if (limit == -1) {
158
176
  limit = byteList.length() - offset;
159
177
  }
160
- Decoder decoder = new Decoder(ctx.runtime, registry, byteList.unsafeBytes(), byteList.begin() + offset, limit, symbolizeKeys, freeze, allowUnknownExt);
178
+ Decoder decoder = new Decoder(ctx.runtime, this, byteList.unsafeBytes(), byteList.begin() + offset, limit, symbolizeKeys, freeze, allowUnknownExt);
161
179
  try {
162
180
  data = null;
163
181
  data = decoder.next();
@@ -187,7 +205,7 @@ public class Unpacker extends RubyObject {
187
205
  public IRubyObject feed(ThreadContext ctx, IRubyObject data) {
188
206
  ByteList byteList = data.asString().getByteList();
189
207
  if (decoder == null) {
190
- decoder = new Decoder(ctx.runtime, registry, byteList.unsafeBytes(), byteList.begin(), byteList.length(), symbolizeKeys, freeze, allowUnknownExt);
208
+ decoder = new Decoder(ctx.runtime, this, byteList.unsafeBytes(), byteList.begin(), byteList.length(), symbolizeKeys, freeze, allowUnknownExt);
191
209
  } else {
192
210
  decoder.feed(byteList.unsafeBytes(), byteList.begin(), byteList.length());
193
211
  }
@@ -325,7 +343,11 @@ public class Unpacker extends RubyObject {
325
343
  ByteList byteList = str.getByteList();
326
344
  this.stream = stream;
327
345
  this.decoder = null;
328
- this.decoder = new Decoder(ctx.runtime, registry, byteList.unsafeBytes(), byteList.begin(), byteList.length(), symbolizeKeys, freeze, allowUnknownExt);
346
+ this.decoder = new Decoder(ctx.runtime, this, byteList.unsafeBytes(), byteList.begin(), byteList.length(), symbolizeKeys, freeze, allowUnknownExt);
329
347
  return getStream(ctx);
330
348
  }
349
+
350
+ public ExtensionRegistry.ExtensionEntry lookupExtensionByTypeId(int typeId) {
351
+ return registry.lookupExtensionByTypeId(typeId);
352
+ }
331
353
  }
data/ext/msgpack/buffer.c CHANGED
@@ -300,30 +300,6 @@ static inline void _msgpack_buffer_add_new_chunk(msgpack_buffer_t* b)
300
300
  }
301
301
  }
302
302
 
303
- static inline void _msgpack_buffer_append_reference(msgpack_buffer_t* b, VALUE string)
304
- {
305
- VALUE mapped_string = rb_str_dup(string);
306
- ENCODING_SET(mapped_string, msgpack_rb_encindex_ascii8bit);
307
-
308
- _msgpack_buffer_add_new_chunk(b);
309
-
310
- char* data = RSTRING_PTR(mapped_string);
311
- size_t length = RSTRING_LEN(mapped_string);
312
-
313
- b->tail.first = (char*) data;
314
- b->tail.last = (char*) data + length;
315
- b->tail.mapped_string = mapped_string;
316
- b->tail.mem = NULL;
317
-
318
- /* msgpack_buffer_writable_size should return 0 for mapped chunk */
319
- b->tail_buffer_end = b->tail.last;
320
-
321
- /* consider read_buffer */
322
- if(b->head == &b->tail) {
323
- b->read_buffer = b->tail.first;
324
- }
325
- }
326
-
327
303
  void _msgpack_buffer_append_long_string(msgpack_buffer_t* b, VALUE string)
328
304
  {
329
305
  size_t length = RSTRING_LEN(string);
@@ -332,16 +308,9 @@ void _msgpack_buffer_append_long_string(msgpack_buffer_t* b, VALUE string)
332
308
  msgpack_buffer_flush(b);
333
309
  if (ENCODING_GET(string) == msgpack_rb_encindex_ascii8bit) {
334
310
  rb_funcall(b->io, b->io_write_all_method, 1, string);
335
- } else if(!STR_DUP_LIKELY_DOES_COPY(string)) {
336
- VALUE s = rb_str_dup(string);
337
- ENCODING_SET(s, msgpack_rb_encindex_ascii8bit);
338
- rb_funcall(b->io, b->io_write_all_method, 1, s);
339
311
  } else {
340
312
  msgpack_buffer_append(b, RSTRING_PTR(string), length);
341
313
  }
342
- } else if(!STR_DUP_LIKELY_DOES_COPY(string)) {
343
- _msgpack_buffer_append_reference(b, string);
344
-
345
314
  } else {
346
315
  msgpack_buffer_append(b, RSTRING_PTR(string), length);
347
316
  }
@@ -619,13 +588,13 @@ size_t msgpack_buffer_flush_to_io(msgpack_buffer_t* b, VALUE io, ID write_method
619
588
  size_t _msgpack_buffer_feed_from_io(msgpack_buffer_t* b)
620
589
  {
621
590
  if(b->io_buffer == Qnil) {
622
- b->io_buffer = rb_funcall(b->io, b->io_partial_read_method, 1, LONG2NUM(b->io_buffer_size));
591
+ b->io_buffer = rb_funcall(b->io, b->io_partial_read_method, 1, SIZET2NUM(b->io_buffer_size));
623
592
  if(b->io_buffer == Qnil) {
624
593
  rb_raise(rb_eEOFError, "IO reached end of file");
625
594
  }
626
595
  StringValue(b->io_buffer);
627
596
  } else {
628
- VALUE ret = rb_funcall(b->io, b->io_partial_read_method, 2, LONG2NUM(b->io_buffer_size), b->io_buffer);
597
+ VALUE ret = rb_funcall(b->io, b->io_partial_read_method, 2, SIZET2NUM(b->io_buffer_size), b->io_buffer);
629
598
  if(ret == Qnil) {
630
599
  rb_raise(rb_eEOFError, "IO reached end of file");
631
600
  }
@@ -644,9 +613,11 @@ size_t _msgpack_buffer_feed_from_io(msgpack_buffer_t* b)
644
613
 
645
614
  size_t _msgpack_buffer_read_from_io_to_string(msgpack_buffer_t* b, VALUE string, size_t length)
646
615
  {
616
+ #define MIN(x, y) (((x) < (y)) ? (x) : (y))
617
+
647
618
  if(RSTRING_LEN(string) == 0) {
648
619
  /* direct read */
649
- VALUE ret = rb_funcall(b->io, b->io_partial_read_method, 2, LONG2NUM(length), string);
620
+ VALUE ret = rb_funcall(b->io, b->io_partial_read_method, 2, SIZET2NUM(MIN(b->io_buffer_size, length)), string);
650
621
  if(ret == Qnil) {
651
622
  return 0;
652
623
  }
@@ -658,7 +629,7 @@ size_t _msgpack_buffer_read_from_io_to_string(msgpack_buffer_t* b, VALUE string,
658
629
  b->io_buffer = rb_str_buf_new(0);
659
630
  }
660
631
 
661
- VALUE ret = rb_funcall(b->io, b->io_partial_read_method, 2, LONG2NUM(length), b->io_buffer);
632
+ VALUE ret = rb_funcall(b->io, b->io_partial_read_method, 2, SIZET2NUM(MIN(b->io_buffer_size, length)), b->io_buffer);
662
633
  if(ret == Qnil) {
663
634
  return 0;
664
635
  }
@@ -666,6 +637,8 @@ size_t _msgpack_buffer_read_from_io_to_string(msgpack_buffer_t* b, VALUE string,
666
637
 
667
638
  rb_str_buf_cat(string, (const void*)RSTRING_PTR(b->io_buffer), rl);
668
639
  return rl;
640
+
641
+ #undef MIN
669
642
  }
670
643
 
671
644
  size_t _msgpack_buffer_skip_from_io(msgpack_buffer_t* b, size_t length)
@@ -674,7 +647,7 @@ size_t _msgpack_buffer_skip_from_io(msgpack_buffer_t* b, size_t length)
674
647
  b->io_buffer = rb_str_buf_new(0);
675
648
  }
676
649
 
677
- VALUE ret = rb_funcall(b->io, b->io_partial_read_method, 2, LONG2NUM(length), b->io_buffer);
650
+ VALUE ret = rb_funcall(b->io, b->io_partial_read_method, 2, SIZET2NUM(length), b->io_buffer);
678
651
  if(ret == Qnil) {
679
652
  return 0;
680
653
  }
data/ext/msgpack/buffer.h CHANGED
@@ -49,6 +49,10 @@
49
49
 
50
50
  #define NO_MAPPED_STRING ((VALUE)0)
51
51
 
52
+ #ifndef RB_ENC_INTERNED_STR_NULL_CHECK
53
+ #define RB_ENC_INTERNED_STR_NULL_CHECK 0
54
+ #endif
55
+
52
56
  extern int msgpack_rb_encindex_utf8;
53
57
  extern int msgpack_rb_encindex_usascii;
54
58
  extern int msgpack_rb_encindex_ascii8bit;
@@ -456,7 +460,11 @@ static inline VALUE msgpack_buffer_read_top_as_string(msgpack_buffer_t* b, size_
456
460
 
457
461
  #ifdef HAVE_RB_ENC_INTERNED_STR
458
462
  if (will_be_frozen) {
459
- result = rb_enc_interned_str(b->read_buffer, length, utf8 ? rb_utf8_encoding() : rb_ascii8bit_encoding());
463
+ if (RB_ENC_INTERNED_STR_NULL_CHECK && length == 0) {
464
+ result = rb_enc_interned_str("", length, utf8 ? rb_utf8_encoding() : rb_ascii8bit_encoding());
465
+ } else {
466
+ result = rb_enc_interned_str(b->read_buffer, length, utf8 ? rb_utf8_encoding() : rb_ascii8bit_encoding());
467
+ }
460
468
  } else {
461
469
  if (utf8) {
462
470
  result = rb_utf8_str_new(b->read_buffer, length);
@@ -29,6 +29,11 @@ static ID s_write;
29
29
  static ID s_append;
30
30
  static ID s_close;
31
31
 
32
+ static VALUE sym_read_reference_threshold;
33
+ static VALUE sym_write_reference_threshold;
34
+ static VALUE sym_io_buffer_size;
35
+
36
+
32
37
  #define BUFFER(from, name) \
33
38
  msgpack_buffer_t *name = NULL; \
34
39
  Data_Get_Struct(from, msgpack_buffer_t, name); \
@@ -89,19 +94,19 @@ void MessagePack_Buffer_set_options(msgpack_buffer_t* b, VALUE io, VALUE options
89
94
  if(options != Qnil) {
90
95
  VALUE v;
91
96
 
92
- v = rb_hash_aref(options, ID2SYM(rb_intern("read_reference_threshold")));
97
+ v = rb_hash_aref(options, sym_read_reference_threshold);
93
98
  if(v != Qnil) {
94
- msgpack_buffer_set_read_reference_threshold(b, NUM2ULONG(v));
99
+ msgpack_buffer_set_read_reference_threshold(b, NUM2SIZET(v));
95
100
  }
96
101
 
97
- v = rb_hash_aref(options, ID2SYM(rb_intern("write_reference_threshold")));
102
+ v = rb_hash_aref(options, sym_write_reference_threshold);
98
103
  if(v != Qnil) {
99
- msgpack_buffer_set_write_reference_threshold(b, NUM2ULONG(v));
104
+ msgpack_buffer_set_write_reference_threshold(b, NUM2SIZET(v));
100
105
  }
101
106
 
102
- v = rb_hash_aref(options, ID2SYM(rb_intern("io_buffer_size")));
107
+ v = rb_hash_aref(options, sym_io_buffer_size);
103
108
  if(v != Qnil) {
104
- msgpack_buffer_set_io_buffer_size(b, NUM2ULONG(v));
109
+ msgpack_buffer_set_io_buffer_size(b, NUM2SIZET(v));
105
110
  }
106
111
  }
107
112
  }
@@ -296,11 +301,11 @@ static VALUE Buffer_skip(VALUE self, VALUE sn)
296
301
 
297
302
  /* do nothing */
298
303
  if(n == 0) {
299
- return ULONG2NUM(0);
304
+ return INT2NUM(0);
300
305
  }
301
306
 
302
307
  size_t sz = read_until_eof(b, Qnil, n);
303
- return ULONG2NUM(sz);
308
+ return SIZET2NUM(sz);
304
309
  }
305
310
 
306
311
  static VALUE Buffer_skip_all(VALUE self, VALUE sn)
@@ -468,7 +473,7 @@ static VALUE Buffer_write_to(VALUE self, VALUE io)
468
473
  {
469
474
  BUFFER(self, b);
470
475
  size_t sz = msgpack_buffer_flush_to_io(b, io, s_write, true);
471
- return ULONG2NUM(sz);
476
+ return SIZET2NUM(sz);
472
477
  }
473
478
 
474
479
  void MessagePack_Buffer_module_init(VALUE mMessagePack)
@@ -479,6 +484,10 @@ void MessagePack_Buffer_module_init(VALUE mMessagePack)
479
484
  s_append = rb_intern("<<");
480
485
  s_close = rb_intern("close");
481
486
 
487
+ sym_read_reference_threshold = ID2SYM(rb_intern("read_reference_threshold"));
488
+ sym_write_reference_threshold = ID2SYM(rb_intern("write_reference_threshold"));
489
+ sym_io_buffer_size = ID2SYM(rb_intern("io_buffer_size"));
490
+
482
491
  msgpack_buffer_static_init();
483
492
 
484
493
  cMessagePack_Buffer = rb_define_class_under(mMessagePack, "Buffer", rb_cObject);
data/ext/msgpack/compat.h CHANGED
@@ -22,104 +22,5 @@
22
22
  #include "ruby.h"
23
23
  #include "ruby/encoding.h"
24
24
 
25
- #if defined(HAVE_RUBY_ST_H)
26
- # include "ruby/st.h" /* ruby hash on Ruby 1.9 */
27
- #elif defined(HAVE_ST_H)
28
- # include "st.h" /* ruby hash on Ruby 1.8 */
29
- #endif
30
-
31
-
32
- /*
33
- * ZALLOC_N (ruby 2.2 or later)
34
- */
35
- #ifndef RB_ZALLOC_N
36
- # define RB_ZALLOC_N(type,n) ((type*)ruby_xcalloc((size_t)(n),sizeof(type)))
37
- #endif
38
- #ifndef ZALLOC_N
39
- # define ZALLOC_N(type,n) RB_ZALLOC_N(type,n)
40
- #endif
41
-
42
-
43
- /*
44
- * define STR_DUP_LIKELY_DOES_COPY
45
- * check rb_str_dup actually copies the string or not
46
- */
47
- #if defined(RUBY_VM) && defined(FL_ALL) && defined(FL_USER1) && defined(FL_USER3) /* MRI 1.9 */
48
- # define STR_DUP_LIKELY_DOES_COPY(str) FL_ALL(str, FL_USER1|FL_USER3) /* same as STR_ASSOC_P(str) */
49
-
50
- #elif defined(FL_TEST) && defined(ELTS_SHARED) /* MRI 1.8 */
51
- # define STR_DUP_LIKELY_DOES_COPY(str) (!FL_TEST(str, ELTS_SHARED))
52
-
53
- //#elif defined(RUBINIUS) || defined(JRUBY) /* Rubinius and JRuby */
54
- #else
55
- # define STR_DUP_LIKELY_DOES_COPY(str) (1)
56
-
57
- #endif
58
-
59
-
60
- /*
61
- * SIZET2NUM
62
- */
63
- #ifndef SIZET2NUM /* MRI 1.8 */
64
- # define SIZET2NUM(v) ULL2NUM(v)
65
- #endif
66
-
67
-
68
- /*
69
- * rb_errinfo()
70
- */
71
- #if defined(RUBY_VM) /* MRI 1.9 */
72
- # define COMPAT_RERAISE rb_exc_raise(rb_errinfo())
73
-
74
- #elif defined(JRUBY) /* JRuby */
75
- # define COMPAT_RERAISE rb_exc_raise(rb_gv_get("$!"))
76
-
77
- #else /* MRI 1.8 and Rubinius */
78
- # define COMPAT_RERAISE rb_exc_raise(ruby_errinfo)
79
- #endif
80
-
81
-
82
- /*
83
- * RBIGNUM_POSITIVE_P
84
- */
85
- #ifndef RBIGNUM_POSITIVE_P
86
- # if defined(RUBINIUS) /* Rubinius <= v1.2.3 */
87
- # define RBIGNUM_POSITIVE_P(b) (rb_funcall(b, rb_intern(">="), 1, INT2FIX(0)) == Qtrue)
88
-
89
- # elif defined(JRUBY) /* JRuby */
90
- # define RBIGNUM_POSITIVE_P(b) (rb_funcall(b, rb_intern(">="), 1, INT2FIX(0)) == Qtrue)
91
- # define rb_big2ull(b) rb_num2ull(b)
92
- /*#define rb_big2ll(b) rb_num2ll(b)*/
93
-
94
- # else /* MRI 1.8 */
95
- # define RBIGNUM_POSITIVE_P(b) (RBIGNUM(b)->sign)
96
- # endif
97
- #endif
98
-
99
-
100
- /*
101
- * RSTRING_PTR, RSTRING_LEN
102
- */
103
- #ifndef RSTRING_PTR /* MRI 1.8.5 */
104
- # define RSTRING_PTR(s) (RSTRING(s)->ptr)
105
- #endif
106
-
107
- #ifndef RSTRING_LEN /* MRI 1.8.5 */
108
- # define RSTRING_LEN(s) (RSTRING(s)->len)
109
- #endif
110
-
111
-
112
- /*
113
- * RSTRUCT_GET
114
- */
115
- #ifndef RSTRUCT_GET
116
- # ifdef RSTRUCT_PTR /* MRI <= 2.0.0 */
117
- # define RSTRUCT_GET(st, idx) (RSTRUCT_PTR(st)[idx])
118
- # else /* Rubinius */
119
- # define RSTRUCT_GET(st, idx) (rb_struct_aref(st, INT2FIX(idx)))
120
- # endif
121
- #endif
122
-
123
-
124
25
  #endif
125
26
 
@@ -2,24 +2,23 @@ require 'mkmf'
2
2
 
3
3
  have_header("ruby/st.h")
4
4
  have_header("st.h")
5
- have_func("rb_enc_interned_str", "ruby.h")
5
+ have_func("rb_enc_interned_str", "ruby.h") # Ruby 3.0+
6
+ have_func("rb_hash_new_capa", "ruby.h") # Ruby 3.2+
6
7
 
7
8
  unless RUBY_PLATFORM.include? 'mswin'
8
- $CFLAGS << %[ -I.. -Wall -O3 -g -std=gnu99]
9
+ $CFLAGS << %[ -I.. -Wall -O3 #{RbConfig::CONFIG["debugflags"]} -std=gnu99]
9
10
  end
10
11
  #$CFLAGS << %[ -DDISABLE_RMEM]
11
12
  #$CFLAGS << %[ -DDISABLE_RMEM_REUSE_INTERNAL_FRAGMENT]
12
13
  #$CFLAGS << %[ -DDISABLE_BUFFER_READ_REFERENCE_OPTIMIZE]
13
14
  #$CFLAGS << %[ -DDISABLE_BUFFER_READ_TO_S_OPTIMIZE]
14
15
 
15
- if defined?(RUBY_ENGINE) && RUBY_ENGINE == 'rbx'
16
- # msgpack-ruby doesn't modify data came from RSTRING_PTR(str)
17
- $CFLAGS << %[ -DRSTRING_NOT_MODIFIED]
18
- # Rubinius C extensions don't grab GVL while rmem is not thread safe
19
- $CFLAGS << %[ -DDISABLE_RMEM]
16
+ if RUBY_VERSION.start_with?('3.0.')
17
+ # https://bugs.ruby-lang.org/issues/18772
18
+ $CFLAGS << ' -DRB_ENC_INTERNED_STR_NULL_CHECK=1 '
20
19
  end
21
20
 
22
- # checking if Hash#[]= (rb_hash_aset) dedupes string keys
21
+ # checking if Hash#[]= (rb_hash_aset) dedupes string keys (Ruby 2.6+)
23
22
  h = {}
24
23
  x = {}
25
24
  r = rand.to_s
@@ -32,7 +31,7 @@ else
32
31
  end
33
32
 
34
33
 
35
- # checking if String#-@ (str_uminus) dedupes... '
34
+ # checking if String#-@ (str_uminus) dedupes... ' (Ruby 2.5+)
36
35
  begin
37
36
  a = -(%w(t e s t).join)
38
37
  b = -(%w(t e s t).join)
@@ -45,7 +44,7 @@ rescue NoMethodError
45
44
  $CFLAGS << ' -DSTR_UMINUS_DEDUPE=0 '
46
45
  end
47
46
 
48
- # checking if String#-@ (str_uminus) directly interns frozen strings... '
47
+ # checking if String#-@ (str_uminus) directly interns frozen strings... ' (Ruby 3.0+)
49
48
  begin
50
49
  s = rand.to_s.freeze
51
50
  if (-s).equal?(s) && (-s.dup).equal?(s)
@@ -62,4 +61,3 @@ if warnflags = CONFIG['warnflags']
62
61
  end
63
62
 
64
63
  create_makefile('msgpack/msgpack')
65
-