|
|
|
@ -51,6 +51,32 @@ VALUE get_def_obj(const void* def) { |
|
|
|
|
return rb_hash_aref(upb_def_to_ruby_obj_map, ULL2NUM((intptr_t)def)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static VALUE cached_empty_string = Qnil; |
|
|
|
|
static VALUE cached_empty_bytes = Qnil; |
|
|
|
|
|
|
|
|
|
static VALUE create_frozen_string(const char* str, size_t size, bool binary) { |
|
|
|
|
VALUE str_rb = rb_str_new(str, size); |
|
|
|
|
|
|
|
|
|
rb_enc_associate(str_rb, |
|
|
|
|
binary ? kRubyString8bitEncoding : kRubyStringUtf8Encoding); |
|
|
|
|
rb_obj_freeze(str_rb); |
|
|
|
|
return str_rb; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
VALUE get_frozen_string(const char* str, size_t size, bool binary) { |
|
|
|
|
if (size == 0) { |
|
|
|
|
return binary ? cached_empty_bytes : cached_empty_string; |
|
|
|
|
} else { |
|
|
|
|
// It is harder to memoize non-empty strings. The obvious approach would be
|
|
|
|
|
// to use a Ruby hash keyed by string as memo table, but looking up in such a table
|
|
|
|
|
// requires constructing a string (the very thing we're trying to avoid).
|
|
|
|
|
//
|
|
|
|
|
// Since few fields have defaults, we will just optimize the empty string
|
|
|
|
|
// case for now.
|
|
|
|
|
return create_frozen_string(str, size, binary); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
|
// Utilities.
|
|
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
@ -118,4 +144,9 @@ void Init_protobuf_c() { |
|
|
|
|
|
|
|
|
|
rb_gc_register_address(&upb_def_to_ruby_obj_map); |
|
|
|
|
upb_def_to_ruby_obj_map = rb_hash_new(); |
|
|
|
|
|
|
|
|
|
rb_gc_register_address(&cached_empty_string); |
|
|
|
|
rb_gc_register_address(&cached_empty_bytes); |
|
|
|
|
cached_empty_string = create_frozen_string("", 0, false); |
|
|
|
|
cached_empty_bytes = create_frozen_string("", 0, true); |
|
|
|
|
} |
|
|
|
|