Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save frsyuki/c428f119226790ffdf8ddc11c1a0b9fa to your computer and use it in GitHub Desktop.
Save frsyuki/c428f119226790ffdf8ddc11c1a0b9fa to your computer and use it in GitHub Desktop.
diff --git a/ext/msgpack/buffer.h b/ext/msgpack/buffer.h
index 9387254..bcbe99b 100644
--- a/ext/msgpack/buffer.h
+++ b/ext/msgpack/buffer.h
@@ -424,22 +424,61 @@ static inline VALUE _msgpack_buffer_refer_head_mapped_string(msgpack_buffer_t* b
return rb_str_substr(b->head->mapped_string, offset, length);
}
-static inline VALUE msgpack_buffer_read_top_as_string(msgpack_buffer_t* b, size_t length, bool will_be_frozen)
+#ifdef COMPAT_HAVE_ENCODING
+#ifdef HAVE_RB_FSTRING_ENC_NEW
+#ifndef DISABLE_HASH_KEY_FSTRING
+extern VALUE rb_fstring_enc_new(const char *ptr, long len, rb_encoding *enc);
+#endif
+#endif
+#endif
+
+static inline VALUE msgpack_buffer_read_top_as_string(msgpack_buffer_t* b, size_t length, bool frozen, bool string_enc)
{
#ifndef DISABLE_BUFFER_READ_REFERENCE_OPTIMIZE
/* optimize */
- if(!will_be_frozen &&
+ /* don't use _msgpack_buffer_refer_head_mapped_string optimization for
+ * frozen strings because freezing strings cause copying */
+ if(!frozen &&
b->head->mapped_string != NO_MAPPED_STRING &&
length >= b->read_reference_threshold) {
VALUE result = _msgpack_buffer_refer_head_mapped_string(b, length);
+ ENCODING_SET(result,
+ string_enc ? msgpack_rb_encindex_utf8 : msgpack_rb_encindex_ascii8bit);
_msgpack_buffer_consumed(b, length);
return result;
}
#endif
+#ifdef COMPAT_HAVE_ENCODING
+#ifdef HAVE_RB_FSTRING_ENC_NEW
+#ifndef DISABLE_HASH_KEY_FSTRING
+ /* optimize */
+ if(frozen) {
+ VALUE fstring = rb_fstring_enc_new(b->read_buffer, length,
+ rb_enc_from_index(string_enc ? msgpack_rb_encindex_utf8 : msgpack_rb_encindex_ascii8bit));
+ _msgpack_buffer_consumed(b, length);
+ return fstring;
+ }
+#endif
+#endif
+
+ VALUE result = rb_str_new(b->read_buffer, length);
+ ENCODING_SET(result,
+ string_enc ? msgpack_rb_encindex_utf8 : msgpack_rb_encindex_ascii8bit);
+ if(frozen) {
+ rb_obj_freeze(result);
+ }
+ _msgpack_buffer_consumed(b, length);
+ return result;
+
+#else
VALUE result = rb_str_new(b->read_buffer, length);
_msgpack_buffer_consumed(b, length);
+ if(frozen) {
+ rb_obj_freeze(result);
+ }
return result;
+#endif
}
diff --git a/ext/msgpack/extconf.rb b/ext/msgpack/extconf.rb
index 4ca8cda..fb72137 100644
--- a/ext/msgpack/extconf.rb
+++ b/ext/msgpack/extconf.rb
@@ -6,6 +6,7 @@ have_func("rb_str_replace", ["ruby.h"])
have_func("rb_intern_str", ["ruby.h"])
have_func("rb_sym2str", ["ruby.h"])
have_func("rb_str_intern", ["ruby.h"])
+have_func("rb_fstring_enc_new", ["ruby.h"])
have_func("rb_block_lambda", ["ruby.h"])
have_func("rb_hash_dup", ["ruby.h"])
have_func("rb_hash_clear", ["ruby.h"])
@@ -17,6 +18,7 @@ end
#$CFLAGS << %[ -DDISABLE_RMEM_REUSE_INTERNAL_FRAGMENT]
#$CFLAGS << %[ -DDISABLE_BUFFER_READ_REFERENCE_OPTIMIZE]
#$CFLAGS << %[ -DDISABLE_BUFFER_READ_TO_S_OPTIMIZE]
+#$CFLAGS << %[ -DDISABLE_HASH_KEY_FSTRING]
if defined?(RUBY_ENGINE) && RUBY_ENGINE == 'rbx'
# msgpack-ruby doesn't modify data came from RSTRING_PTR(str)
diff --git a/ext/msgpack/unpacker.c b/ext/msgpack/unpacker.c
index 8b1f699..54faaa4 100644
--- a/ext/msgpack/unpacker.c
+++ b/ext/msgpack/unpacker.c
@@ -163,12 +163,8 @@ static inline int object_complete_binary(msgpack_unpacker_t* uk, VALUE str)
return object_complete(uk, str);
}
-static inline int object_complete_ext(msgpack_unpacker_t* uk, int ext_type, VALUE str)
+static inline int object_complete_ext2(msgpack_unpacker_t* uk, int ext_type, VALUE str)
{
-#ifdef COMPAT_HAVE_ENCODING
- ENCODING_SET(str, msgpack_rb_encindex_ascii8bit);
-#endif
-
VALUE proc = msgpack_unpacker_ext_registry_lookup(&uk->ext_registry, ext_type);
if(proc != Qnil) {
VALUE obj = rb_funcall(proc, s_call, 1, str);
@@ -183,6 +179,14 @@ static inline int object_complete_ext(msgpack_unpacker_t* uk, int ext_type, VALU
return PRIMITIVE_UNEXPECTED_EXT_TYPE;
}
+static inline int object_complete_ext(msgpack_unpacker_t* uk, int ext_type, VALUE str)
+{
+#ifdef COMPAT_HAVE_ENCODING
+ ENCODING_SET(str, msgpack_rb_encindex_ascii8bit);
+#endif
+ return object_complete_ext2(uk, ext_type, str);
+}
+
/* stack funcs */
static inline msgpack_unpacker_stack_t* _msgpack_unpacker_stack_top(msgpack_unpacker_t* uk)
{
@@ -288,20 +292,16 @@ static inline int read_raw_body_begin(msgpack_unpacker_t* uk, int raw_type)
/* try optimized read */
size_t length = uk->reading_raw_remaining;
if(length <= msgpack_buffer_top_readable_size(UNPACKER_BUFFER_(uk))) {
- /* don't use zerocopy for hash keys but get a frozen string directly
- * because rb_hash_aset freezes keys and it causes copying */
- bool will_freeze = is_reading_map_key(uk);
- VALUE string = msgpack_buffer_read_top_as_string(UNPACKER_BUFFER_(uk), length, will_freeze);
+ bool frozen = is_reading_map_key(uk);
+ VALUE string = msgpack_buffer_read_top_as_string(UNPACKER_BUFFER_(uk), length,
+ frozen, raw_type == RAW_TYPE_STRING);
int ret;
if(raw_type == RAW_TYPE_STRING) {
- ret = object_complete_string(uk, string);
+ ret = object_complete(uk, string);
} else if(raw_type == RAW_TYPE_BINARY) {
- ret = object_complete_binary(uk, string);
+ ret = object_complete(uk, string);
} else {
- ret = object_complete_ext(uk, raw_type, string);
- }
- if(will_freeze) {
- rb_obj_freeze(string);
+ ret = object_complete_ext2(uk, raw_type, string);
}
uk->reading_raw_remaining = 0;
return ret;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment