mirror of
https://github.com/ruby/ruby.git
synced 2026-10-28 16:36:20 +08:00
Allow sharing middlesubstring if the terminator is present
Sharing middle substrings have been behind a compilation flags for a very long time, and it's unclear if we'll ever make it the default. However, we can still share middle substrings without breaking the zero-terminated contract if the source string happens to have the necessary NUL characters at that specific offset. This is the case for some file formats such as FlatBuffers, BSON keys and a few others.
This commit is contained in:
1 parent
13926009ba
commit
fcd210086c
2 files changed
+42
-15
Notes:
git
2026-04-07 08:26:56 +00:00
No files matched your search
@@ -198,15 +198,30 @@ VALUE rb_cSymbol;
|
||||
|
||||
#define STR_ENC_GET(str) get_encoding(str)
|
||||
|
||||
static inline bool
|
||||
zero_filled(const char *s, int n)
|
||||
{
|
||||
for (; n > 0; --n) {
|
||||
if (*s++) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
#if !defined SHARABLE_MIDDLE_SUBSTRING
|
||||
# define SHARABLE_MIDDLE_SUBSTRING 0
|
||||
#endif
|
||||
#if !SHARABLE_MIDDLE_SUBSTRING
|
||||
#define SHARABLE_SUBSTRING_P(beg, len, end) ((beg) + (len) == (end))
|
||||
#else
|
||||
#define SHARABLE_SUBSTRING_P(beg, len, end) 1
|
||||
#endif
|
||||
|
||||
static inline bool
|
||||
SHARABLE_SUBSTRING_P(VALUE str, long beg, long len)
|
||||
{
|
||||
#if SHARABLE_MIDDLE_SUBSTRING
|
||||
return true;
|
||||
#else
|
||||
long end = beg + len;
|
||||
long source_len = RSTRING_LEN(str);
|
||||
return end == source_len || zero_filled(RSTRING_PTR(str) + end, TERM_LEN(str));
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline long
|
||||
str_embed_capa(VALUE str)
|
||||
@@ -2810,15 +2825,6 @@ rb_string_value_ptr(volatile VALUE *ptr)
|
||||
return RSTRING_PTR(str);
|
||||
}
|
||||
|
||||
static int
|
||||
zero_filled(const char *s, int n)
|
||||
{
|
||||
for (; n > 0; --n) {
|
||||
if (*s++) return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static const char *
|
||||
str_null_char(const char *s, long len, const int minlen, rb_encoding *enc)
|
||||
{
|
||||
@@ -3138,7 +3144,7 @@ str_subseq(VALUE str, long beg, long len)
|
||||
RUBY_ASSERT(beg+len <= RSTRING_LEN(str));
|
||||
|
||||
const int termlen = TERM_LEN(str);
|
||||
if (!SHARABLE_SUBSTRING_P(beg, len, RSTRING_LEN(str))) {
|
||||
if (!SHARABLE_SUBSTRING_P(str, beg, len)) {
|
||||
str2 = rb_enc_str_new(RSTRING_PTR(str) + beg, len, rb_str_enc_get(str));
|
||||
if (ENC_CODERANGE(str) == ENC_CODERANGE_7BIT) {
|
||||
ENC_CODERANGE_SET(str2, ENC_CODERANGE_7BIT);
|
||||
|
||||
@@ -3461,6 +3461,27 @@ CODE
|
||||
assert_equal(false, ("\u3042"*10).byteslice(0, 20).valid_encoding?, bug7954)
|
||||
end
|
||||
|
||||
def test_shared_middle_string_terminator
|
||||
ten = "0123456789"
|
||||
hundred = ten * 10
|
||||
str = "#{hundred}\0#{hundred}".freeze
|
||||
|
||||
require 'objspace'
|
||||
|
||||
substr = str.byteslice(0, hundred.bytesize)
|
||||
assert_equal hundred, substr
|
||||
assert_includes ObjectSpace.dump(substr), ' "shared":true,'
|
||||
|
||||
# Larger terminator
|
||||
substr.force_encoding(Encoding::UTF_16BE)
|
||||
assert_equal hundred.dup.force_encoding(Encoding::UTF_16BE), substr
|
||||
refute_includes ObjectSpace.dump(substr), ' "shared":true,'
|
||||
|
||||
substr = str.byteslice(0, hundred.bytesize + 1)
|
||||
assert_equal hundred + "\0", substr
|
||||
refute_includes ObjectSpace.dump(substr), ' "shared":true,'
|
||||
end
|
||||
|
||||
def test_unknown_string_option
|
||||
str = nil
|
||||
assert_nothing_raised(SyntaxError) do
|
||||
|
||||
Reference in new issue
Block a user