14#include "ruby/internal/config.h"
24#include "debug_counter.h"
28#include "internal/array.h"
29#include "internal/bits.h"
30#include "internal/compar.h"
31#include "internal/compilers.h"
32#include "internal/concurrent_set.h"
33#include "internal/encoding.h"
34#include "internal/error.h"
35#include "internal/gc.h"
36#include "internal/hash.h"
37#include "internal/numeric.h"
38#include "internal/object.h"
39#include "internal/proc.h"
40#include "internal/re.h"
41#include "internal/sanitizers.h"
42#include "internal/simd.h"
43#include "internal/string.h"
44#include "internal/transcode.h"
51#include "ruby_assert.h"
58#if defined HAVE_CRYPT_R
59# if defined HAVE_CRYPT_H
62#elif !defined HAVE_CRYPT
63# include "missing/crypt.h"
64# define HAVE_CRYPT_R 1
68#undef rb_usascii_str_new
72#undef rb_usascii_str_new_cstr
73#undef rb_utf8_str_new_cstr
74#undef rb_enc_str_new_cstr
75#undef rb_external_str_new_cstr
76#undef rb_locale_str_new_cstr
77#undef rb_str_dup_frozen
78#undef rb_str_buf_new_cstr
129#define RUBY_MAX_CHAR_LEN 16
130#define STR_PRECOMPUTED_HASH FL_USER4
131#define STR_SHARED_ROOT FL_USER5
132#define STR_BORROWED FL_USER6
133#define STR_TMPLOCK FL_USER7
134#define STR_NOFREE FL_USER18
136#define STR_SET_NOEMBED(str) do {\
137 FL_SET((str), STR_NOEMBED);\
138 FL_UNSET((str), STR_SHARED | STR_SHARED_ROOT | STR_BORROWED);\
140#define STR_SET_EMBED(str) FL_UNSET((str), STR_NOEMBED | STR_SHARED | STR_NOFREE)
142#define STR_SET_LEN(str, n) do { \
143 RSTRING(str)->len = (n); \
146#define TERM_LEN(str) (rb_str_enc_fastpath(str) ? 1 : rb_enc_mbminlen(rb_enc_from_index(ENCODING_GET(str))))
147#define TERM_FILL(ptr, termlen) do {\
148 char *const term_fill_ptr = (ptr);\
149 const int term_fill_len = (termlen);\
150 *term_fill_ptr = '\0';\
151 if (UNLIKELY(term_fill_len > 1))\
152 memset(term_fill_ptr, 0, term_fill_len);\
155#define RESIZE_CAPA(str,capacity) do {\
156 const int termlen = TERM_LEN(str);\
157 RESIZE_CAPA_TERM(str,capacity,termlen);\
159#define RESIZE_CAPA_TERM(str,capacity,termlen) do {\
160 if (STR_EMBED_P(str)) {\
161 if (str_embed_capa(str) < capacity + termlen) {\
162 char *const tmp = ALLOC_N(char, (size_t)(capacity) + (termlen));\
163 const long tlen = RSTRING_LEN(str);\
164 memcpy(tmp, RSTRING_PTR(str), str_embed_capa(str));\
165 RSTRING(str)->as.heap.ptr = tmp;\
166 RSTRING(str)->len = tlen;\
167 STR_SET_NOEMBED(str);\
168 RSTRING(str)->as.heap.aux.capa = (capacity);\
172 RUBY_ASSERT(!FL_TEST((str), STR_SHARED)); \
173 SIZED_REALLOC_N(RSTRING(str)->as.heap.ptr, char, \
174 (size_t)(capacity) + (termlen), STR_HEAP_SIZE(str)); \
175 RSTRING(str)->as.heap.aux.capa = (capacity);\
179#define STR_SET_SHARED(str, shared_str) do { \
180 if (!FL_TEST(str, STR_FAKESTR)) { \
181 RUBY_ASSERT(RSTRING_PTR(shared_str) <= RSTRING_PTR(str)); \
182 RUBY_ASSERT(RSTRING_PTR(str) <= RSTRING_PTR(shared_str) + RSTRING_LEN(shared_str)); \
183 RB_OBJ_WRITE((str), &RSTRING(str)->as.heap.aux.shared, (shared_str)); \
184 FL_SET((str), STR_SHARED); \
185 rb_gc_register_pinning_obj(str); \
186 FL_SET((shared_str), STR_SHARED_ROOT); \
187 if (RBASIC_CLASS((shared_str)) == 0) \
188 FL_SET_RAW((shared_str), STR_BORROWED); \
192#define STR_HEAP_PTR(str) (RSTRING(str)->as.heap.ptr)
193#define STR_HEAP_SIZE(str) ((size_t)RSTRING(str)->as.heap.aux.capa + TERM_LEN(str))
196#define STR_ENC_GET(str) get_encoding(str)
199zero_filled(
const char *s,
int n)
202 if (*s++)
return false;
207#if !defined SHARABLE_MIDDLE_SUBSTRING
208# define SHARABLE_MIDDLE_SUBSTRING 0
212SHARABLE_SUBSTRING_P(
VALUE str,
long beg,
long len)
214#if SHARABLE_MIDDLE_SUBSTRING
217 long end = beg +
len;
218 long source_len = RSTRING_LEN(str);
219 return end == source_len || zero_filled(RSTRING_PTR(str) + end, TERM_LEN(str));
224str_embed_capa(
VALUE str)
226 return rb_obj_shape_slot_size(str) - offsetof(
struct RString, as.
embed.ary);
230rb_str_reembeddable_p(
VALUE str)
232 return !
FL_TEST(str, STR_NOFREE|STR_SHARED_ROOT|STR_SHARED);
238rb_str_embedded_shared_root_p(
VALUE str)
240 return STR_EMBED_P(str) &&
FL_TEST(str, STR_SHARED_ROOT);
244rb_str_embed_size(
long capa,
long termlen)
252rb_str_size_as_embedded(
VALUE str)
255 if (STR_EMBED_P(str)) {
257 if (
FL_TEST_RAW(str, STR_PRECOMPUTED_HASH))
capa +=
sizeof(st_index_t);
259 real_size = rb_str_embed_size(
capa, TERM_LEN(str));
263 else if (rb_str_reembeddable_p(str)) {
265 if (
FL_TEST_RAW(str, STR_PRECOMPUTED_HASH))
capa +=
sizeof(st_index_t);
267 real_size = rb_str_embed_size(
capa, TERM_LEN(str));
270 real_size =
sizeof(
struct RString);
277STR_EMBEDDABLE_P(
long len,
long termlen)
279 return rb_gc_size_allocatable_p(rb_str_embed_size(
len, termlen));
286#define STR_COPY_MAX_EMBED_SIZE 256
290static VALUE str_new_frozen_buffer(
VALUE klass,
VALUE orig,
int copy_encoding);
291static VALUE str_new_static(
VALUE klass,
const char *
ptr,
long len,
int encindex);
293static void str_make_independent_expand(
VALUE str,
long len,
long expand,
const int termlen);
294static inline void str_modifiable(
VALUE str);
299str_make_independent(
VALUE str)
301 long len = RSTRING_LEN(str);
302 int termlen = TERM_LEN(str);
303 str_make_independent_expand((str),
len, 0L, termlen);
306static inline int str_dependent_p(
VALUE str);
309rb_str_make_independent(
VALUE str)
311 if (str_dependent_p(str)) {
312 str_make_independent(str);
317rb_str_make_embedded(
VALUE str)
322 int termlen = TERM_LEN(str);
323 char *buf =
RSTRING(str)->as.heap.ptr;
324 long old_capa =
RSTRING(str)->as.heap.aux.capa + termlen;
328 STR_SET_LEN(str,
len);
331 memcpy(RSTRING_PTR(str), buf,
len);
332 SIZED_FREE_N(buf, old_capa);
339rb_debug_rstring_null_ptr(
const char *func)
341 fprintf(stderr,
"%s is returning NULL!! "
342 "SIGSEGV is highly expected to follow immediately.\n"
343 "If you could reproduce, attach your debugger here, "
344 "and look at the passed string.\n",
349static VALUE sym_ascii, sym_turkic, sym_lithuanian, sym_fold;
352get_encoding(
VALUE str)
358mustnot_broken(
VALUE str)
360 if (is_broken_string(str)) {
361 rb_raise(rb_eArgError,
"invalid byte sequence in %s", rb_enc_name(STR_ENC_GET(str)));
366mustnot_wchar(
VALUE str)
369 if (rb_enc_mbminlen(enc) > 1) {
370 rb_raise(rb_eArgError,
"wide char encoding: %s", rb_enc_name(enc));
374static VALUE register_fstring(
VALUE str,
bool copy,
bool force_precompute_hash);
376#if SIZEOF_LONG == SIZEOF_VOIDP
377#define PRECOMPUTED_FAKESTR_HASH 1
382BARE_STRING_P(
VALUE str)
387static inline st_index_t
388str_do_hash(
VALUE str)
390 st_index_t h =
rb_memhash((
const void *)RSTRING_PTR(str), RSTRING_LEN(str));
392 if (e && !is_ascii_string(str)) {
399str_store_precomputed_hash(
VALUE str, st_index_t hash)
405 size_t used_bytes = (RSTRING_LEN(str) + TERM_LEN(str));
406 size_t free_bytes = str_embed_capa(str) - used_bytes;
410 memcpy(
RSTRING_END(str) + TERM_LEN(str), &hash,
sizeof(hash));
412 FL_SET(str, STR_PRECOMPUTED_HASH);
425 if (
FL_TEST(str, RSTRING_FSTR))
428 bare = BARE_STRING_P(str);
430 if (STR_EMBED_P(str)) {
435 if (
FL_TEST_RAW(str, STR_SHARED_ROOT | STR_SHARED) == STR_SHARED_ROOT) {
442 rb_str_resize(str, RSTRING_LEN(str));
444 fstr = register_fstring(str,
false,
false);
447 str_replace_shared_without_enc(str, fstr);
454static VALUE fstring_table_obj;
457fstring_concurrent_set_hash(
VALUE str)
459#ifdef PRECOMPUTED_FAKESTR_HASH
463 h = (st_index_t)
RSTRING(str)->as.heap.aux.capa;
480 const char *aptr, *bptr;
487 return (alen == blen &&
489 memcmp(aptr, bptr, alen) == 0);
494 bool force_precompute_hash;
498fstring_concurrent_set_create(
VALUE str,
void *data)
508 long len = RSTRING_LEN(str);
509 long capa =
len +
sizeof(st_index_t);
510 int term_len = TERM_LEN(str);
512 if (arg->force_precompute_hash && STR_EMBEDDABLE_P(
capa, term_len)) {
514 memcpy(RSTRING_PTR(new_str), RSTRING_PTR(str),
len);
515 STR_SET_LEN(new_str, RSTRING_LEN(str));
517 rb_enc_copy(new_str, str);
518 str_store_precomputed_hash(new_str, str_do_hash(str));
522 rb_enc_copy(new_str, str);
523#ifdef PRECOMPUTED_FAKESTR_HASH
524 if (
rb_str_capacity(new_str) >= RSTRING_LEN(str) + term_len +
sizeof(st_index_t)) {
525 str_store_precomputed_hash(new_str, (st_index_t)
RSTRING(str)->as.heap.aux.capa);
539 if (!
OBJ_FROZEN(str) || CHILLED_STRING_P(str)) {
542 if (STR_SHARED_P(str)) {
544 str_make_independent(str);
547 if (!BARE_STRING_P(str)) {
553 RBASIC(str)->flags |= RSTRING_FSTR;
569 .hash = fstring_concurrent_set_hash,
570 .cmp = fstring_concurrent_set_cmp,
571 .create = fstring_concurrent_set_create,
576Init_fstring_table(
void)
578 fstring_table_obj = rb_concurrent_set_new(&fstring_concurrent_set_funcs, 8192);
579 rb_gc_register_address(&fstring_table_obj);
583register_fstring(
VALUE str,
bool copy,
bool force_precompute_hash)
587 .force_precompute_hash = force_precompute_hash
590#if SIZEOF_VOIDP == SIZEOF_LONG
594 RSTRING(str)->as.heap.aux.capa = (long)str_do_hash(str);
598 VALUE result = rb_concurrent_set_find_or_insert(&fstring_table_obj, str, &args);
600 RUBY_ASSERT(!rb_objspace_garbage_object_p(result));
612rb_obj_is_fstring_table(
VALUE obj)
616 return obj == fstring_table_obj;
620rb_gc_free_fstring(
VALUE obj)
622 ASSERT_vm_locking_with_barrier();
628 rb_concurrent_set_delete_by_identity(fstring_table_obj, obj);
630 RB_DEBUG_COUNTER_INC(obj_str_fstr);
636rb_fstring_foreach_with_replace(
int (*callback)(
VALUE *str,
void *data),
void *data)
638 if (fstring_table_obj) {
639 rb_concurrent_set_foreach_with_replace(fstring_table_obj, callback, data);
644setup_fake_str(
struct RString *fake_str,
const char *name,
long len,
int encidx)
647 RBASIC_SET_FULL_SHAPE_ID((
VALUE)fake_str, ROOT_SHAPE_ID | SHAPE_ID_LAYOUT_OTHER);
660 return (
VALUE)fake_str;
669 return setup_fake_str(fake_str, name,
len, rb_enc_to_index(enc));
678rb_fstring_new(
const char *ptr,
long len)
680 struct RString fake_str = {RBASIC_INIT};
681 return register_fstring(setup_fake_str(&fake_str,
ptr,
len, ENCINDEX_US_ASCII),
false,
false);
687 struct RString fake_str = {RBASIC_INIT};
688 return register_fstring(rb_setup_fake_str(&fake_str,
ptr,
len, enc),
false,
false);
692rb_fstring_cstr(
const char *
ptr)
694 return rb_fstring_new(
ptr, strlen(
ptr));
698single_byte_optimizable(
VALUE str)
702 case ENCINDEX_ASCII_8BIT:
703 case ENCINDEX_US_ASCII:
725static inline const char *
726search_nonascii(
const char *p,
const char *e)
734#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
735# if SIZEOF_UINTPTR_T == 8
736# define NONASCII_MASK UINT64_C(0x8080808080808080)
737# elif SIZEOF_UINTPTR_T == 4
738# define NONASCII_MASK UINT32_C(0x80808080)
740# error "don't know what to do."
743# if SIZEOF_UINTPTR_T == 8
744# define NONASCII_MASK ((uintptr_t)0x80808080UL << 32 | (uintptr_t)0x80808080UL)
745# elif SIZEOF_UINTPTR_T == 4
746# define NONASCII_MASK 0x80808080UL
748# error "don't know what to do."
752 if (UNALIGNED_WORD_ACCESS || e - p >= SIZEOF_VOIDP) {
753#if !UNALIGNED_WORD_ACCESS
754 if ((uintptr_t)p % SIZEOF_VOIDP) {
755 int l = SIZEOF_VOIDP - (uintptr_t)p % SIZEOF_VOIDP;
760 case 7:
if (p[-7]&0x80)
return p-7;
761 case 6:
if (p[-6]&0x80)
return p-6;
762 case 5:
if (p[-5]&0x80)
return p-5;
763 case 4:
if (p[-4]&0x80)
return p-4;
765 case 3:
if (p[-3]&0x80)
return p-3;
766 case 2:
if (p[-2]&0x80)
return p-2;
767 case 1:
if (p[-1]&0x80)
return p-1;
772#if defined(HAVE_BUILTIN___BUILTIN_ASSUME_ALIGNED) &&! UNALIGNED_WORD_ACCESS
773#define aligned_ptr(value) \
774 __builtin_assume_aligned((value), sizeof(uintptr_t))
776#define aligned_ptr(value) (value)
779 t = (e - (SIZEOF_VOIDP-1));
781 for (;s < t; s +=
sizeof(uintptr_t)) {
783 memcpy(&word, s,
sizeof(word));
784 if (word & NONASCII_MASK) {
785#ifdef WORDS_BIGENDIAN
786 return (
const char *)s + (nlz_intptr(word&NONASCII_MASK)>>3);
788 return (
const char *)s + (ntz_intptr(word&NONASCII_MASK)>>3);
798 case 7:
if (e[-7]&0x80)
return e-7;
799 case 6:
if (e[-6]&0x80)
return e-6;
800 case 5:
if (e[-5]&0x80)
return e-5;
801 case 4:
if (e[-4]&0x80)
return e-4;
803 case 3:
if (e[-3]&0x80)
return e-3;
804 case 2:
if (e[-2]&0x80)
return e-2;
805 case 1:
if (e[-1]&0x80)
return e-1;
813 const char *e = p +
len;
815 if (rb_enc_to_index(enc) == rb_ascii8bit_encindex()) {
817 p = search_nonascii(p, e);
821 if (rb_enc_asciicompat(enc)) {
822 p = search_nonascii(p, e);
825 int ret = rb_enc_precise_mbclen(p, e, enc);
829 p = search_nonascii(p, e);
835 int ret = rb_enc_precise_mbclen(p, e, enc);
851 if (rb_enc_to_index(enc) == rb_ascii8bit_encindex()) {
854 p = search_nonascii(p, e);
858 else if (rb_enc_asciicompat(enc)) {
859 p = search_nonascii(p, e);
865 int ret = rb_enc_precise_mbclen(p, e, enc);
872 p = search_nonascii(p, e);
878 int ret = rb_enc_precise_mbclen(p, e, enc);
903 rb_enc_set_index(str1, rb_enc_get_index(str2));
911rb_enc_cr_str_copy_for_substr(
VALUE dest,
VALUE src)
916 str_enc_copy(dest, src);
917 if (RSTRING_LEN(dest) == 0) {
918 if (!rb_enc_asciicompat(STR_ENC_GET(src)))
929 if (!rb_enc_asciicompat(STR_ENC_GET(src)) ||
930 search_nonascii(RSTRING_PTR(dest),
RSTRING_END(dest)))
941rb_enc_cr_str_exact_copy(
VALUE dest,
VALUE src)
943 str_enc_copy(dest, src);
950 return coderange_scan(RSTRING_PTR(str), RSTRING_LEN(str), enc);
956 return enc_coderange_scan(str, enc);
960rbimpl_enc_str_coderange_scan(
VALUE str)
962 int cr = enc_coderange_scan(str, get_encoding(str));
967#undef rb_enc_str_coderange
974 cr = rbimpl_enc_str_coderange_scan(str);
978#define rb_enc_str_coderange rb_enc_str_coderange_inline
981rb_enc_str_asciicompat(
VALUE str)
984 return rb_str_encindex_fastpath(encindex) || rb_enc_asciicompat(rb_enc_get_from_index(encindex));
992 return rb_enc_str_asciicompat(str) && is_ascii_string(str);
1001str_mod_check(
VALUE s,
const char *p,
long len)
1003 if (RSTRING_PTR(s) != p || RSTRING_LEN(s) !=
len){
1009str_capacity(
VALUE str,
const int termlen)
1011 if (STR_EMBED_P(str)) {
1012 return str_embed_capa(str) - termlen;
1014 else if (
FL_ANY_RAW(str, STR_SHARED|STR_NOFREE)) {
1018 return RSTRING(str)->as.heap.aux.capa;
1025 return str_capacity(str, TERM_LEN(str));
1029must_not_null(
const char *
ptr)
1032 rb_raise(rb_eArgError,
"NULL pointer given");
1037str_alloc_embed(
VALUE klass,
size_t capa)
1039 size_t size = rb_str_embed_size(
capa, 0);
1046 str->as.embed.ary[0] = 0;
1052str_alloc_heap(
VALUE klass)
1057 str->as.heap.aux.capa = 0;
1058 str->as.heap.ptr = NULL;
1064empty_str_alloc(
VALUE klass)
1066 RUBY_DTRACE_CREATE_HOOK(STRING, 0);
1067 VALUE str = str_alloc_embed(klass, 0);
1068 memset(
RSTRING(str)->
as.embed.ary, 0, str_embed_capa(str));
1079 rb_raise(rb_eArgError,
"negative string size (or size too big)");
1083 enc = rb_ascii8bit_encoding();
1086 RUBY_DTRACE_CREATE_HOOK(STRING,
len);
1088 int termlen = rb_enc_mbminlen(enc);
1090 if (STR_EMBEDDABLE_P(
len, termlen)) {
1091 str = str_alloc_embed(klass,
len + termlen);
1097 str = str_alloc_heap(klass);
1103 rb_xmalloc_mul_add_mul(
sizeof(
char),
len,
sizeof(
char), termlen);
1106 rb_enc_raw_set(str, enc);
1109 memcpy(RSTRING_PTR(str),
ptr,
len);
1112 memset(RSTRING_PTR(str), 0,
len);
1115 STR_SET_LEN(str,
len);
1116 TERM_FILL(RSTRING_PTR(str) +
len, termlen);
1123 return str_enc_new(klass,
ptr,
len, rb_ascii8bit_encoding());
1158 __msan_unpoison_string(
ptr);
1178 if (rb_enc_mbminlen(enc) != 1) {
1179 rb_raise(rb_eArgError,
"wchar encoding given");
1181 return rb_enc_str_new(
ptr, strlen(
ptr), enc);
1185str_new_static(
VALUE klass,
const char *
ptr,
long len,
int encindex)
1190 rb_raise(rb_eArgError,
"negative string size (or size too big)");
1194 str = str_enc_new(klass,
ptr,
len, rb_enc_from_index(encindex));
1197 RUBY_DTRACE_CREATE_HOOK(STRING,
len);
1198 str = str_alloc_heap(klass);
1202 RBASIC(str)->flags |= STR_NOFREE;
1203 rb_enc_associate_index(str, encindex);
1218rb_str_new_owned(
char *
ptr,
long len,
long capa,
int encindex)
1220 RUBY_DTRACE_CREATE_HOOK(STRING,
len);
1227 rb_enc_associate_index(str, encindex);
1249static VALUE str_cat_conv_enc_opts(
VALUE newstr,
long ofs,
const char *
ptr,
long len,
1251 int ecflags,
VALUE ecopts);
1256 int encidx = rb_enc_to_index(enc);
1257 if (rb_enc_get_index(str) == encidx)
1258 return is_ascii_string(str);
1269 if (!to)
return str;
1270 if (!from) from = rb_enc_get(str);
1271 if (from == to)
return str;
1272 if ((rb_enc_asciicompat(to) && is_enc_ascii_string(str, from)) ||
1273 rb_is_ascii8bit_enc(to)) {
1274 if (STR_ENC_GET(str) != to) {
1276 rb_enc_associate(str, to);
1283 from, to, ecflags, ecopts);
1284 if (
NIL_P(newstr)) {
1292rb_str_cat_conv_enc_opts(
VALUE newstr,
long ofs,
const char *
ptr,
long len,
1297 olen = RSTRING_LEN(newstr);
1298 if (ofs < -olen || olen < ofs)
1300 if (ofs < 0) ofs += olen;
1302 STR_SET_LEN(newstr, ofs);
1306 rb_str_modify(newstr);
1307 return str_cat_conv_enc_opts(newstr, ofs,
ptr,
len, from,
1315 STR_SET_LEN(str, 0);
1316 rb_enc_associate(str, enc);
1322str_cat_conv_enc_opts(
VALUE newstr,
long ofs,
const char *
ptr,
long len,
1324 int ecflags,
VALUE ecopts)
1329 VALUE econv_wrapper;
1330 const unsigned char *start, *sp;
1331 unsigned char *dest, *dp;
1332 size_t converted_output = (size_t)ofs;
1337 RBASIC_CLEAR_CLASS(econv_wrapper);
1339 if (!ec)
return Qnil;
1342 sp = (
unsigned char*)
ptr;
1344 while ((dest = (
unsigned char*)RSTRING_PTR(newstr)),
1345 (dp = dest + converted_output),
1349 size_t converted_input = sp - start;
1350 size_t rest =
len - converted_input;
1351 converted_output = dp - dest;
1353 if (converted_input && converted_output &&
1354 rest < (LONG_MAX / converted_output)) {
1355 rest = (rest * converted_output) / converted_input;
1360 olen += rest < 2 ? 2 : rest;
1361 rb_str_resize(newstr, olen);
1368 len = dp - (
unsigned char*)RSTRING_PTR(newstr);
1370 rb_enc_associate(newstr, to);
1389 const int eidx = rb_enc_to_index(eenc);
1392 return rb_enc_str_new(
ptr,
len, eenc);
1396 if ((eidx == rb_ascii8bit_encindex()) ||
1397 (eidx == rb_usascii_encindex() && search_nonascii(
ptr,
ptr +
len))) {
1401 ienc = rb_default_internal_encoding();
1402 if (!ienc || eenc == ienc) {
1403 return rb_enc_str_new(
ptr,
len, eenc);
1407 if ((eidx == rb_ascii8bit_encindex()) ||
1408 (eidx == rb_usascii_encindex()) ||
1409 (rb_enc_asciicompat(eenc) && !search_nonascii(
ptr,
ptr +
len))) {
1410 return rb_enc_str_new(
ptr,
len, ienc);
1413 str = rb_enc_str_new(NULL, 0, ienc);
1416 if (
NIL_P(rb_str_cat_conv_enc_opts(str, 0,
ptr,
len, eenc, 0,
Qnil))) {
1417 rb_str_initialize(str,
ptr,
len, eenc);
1425 int eidx = rb_enc_to_index(eenc);
1426 if (eidx == rb_usascii_encindex() &&
1427 !is_ascii_string(str)) {
1428 rb_enc_associate_index(str, rb_ascii8bit_encindex());
1431 rb_enc_associate_index(str, eidx);
1490str_replace_shared_without_enc(
VALUE str2,
VALUE str)
1492 const int termlen = TERM_LEN(str);
1497 if (str_embed_capa(str2) >=
len + termlen) {
1498 char *ptr2 =
RSTRING(str2)->as.embed.ary;
1499 STR_SET_EMBED(str2);
1500 memcpy(ptr2, RSTRING_PTR(str),
len);
1501 TERM_FILL(ptr2+
len, termlen);
1505 if (STR_SHARED_P(str)) {
1506 root =
RSTRING(str)->as.heap.aux.shared;
1515 if (!STR_EMBED_P(str2) && !
FL_TEST_RAW(str2, STR_SHARED|STR_NOFREE)) {
1517 rb_fatal(
"about to free a possible shared root");
1519 char *ptr2 = STR_HEAP_PTR(str2);
1521 SIZED_FREE_N(ptr2, STR_HEAP_SIZE(str2));
1524 FL_SET(str2, STR_NOEMBED);
1526 STR_SET_SHARED(str2, root);
1529 STR_SET_LEN(str2,
len);
1537 str_replace_shared_without_enc(str2, str);
1538 rb_enc_cr_str_exact_copy(str2, str);
1545 return str_replace_shared(str_alloc_heap(klass), str);
1562rb_str_new_frozen_String(
VALUE orig)
1570rb_str_frozen_bare_string(
VALUE orig)
1572 if (RB_LIKELY(BARE_STRING_P(orig) &&
OBJ_FROZEN_RAW(orig)))
return orig;
1577rb_str_tmp_frozen_acquire(
VALUE orig)
1580 return str_new_frozen_buffer(0, orig, FALSE);
1587 if (STR_SHARED_P(orig) && !STR_EMBED_P(
RSTRING(orig)->
as.heap.aux.shared))
return rb_str_tmp_frozen_acquire(orig);
1589 VALUE str = str_alloc_heap(0);
1592 FL_SET(str, STR_SHARED_ROOT);
1594 size_t capa = str_capacity(orig, TERM_LEN(orig));
1600 if (STR_EMBED_P(orig) ||
FL_TEST_RAW(orig, STR_SHARED | STR_SHARED_ROOT | RSTRING_FSTR)) {
1601 RSTRING(str)->as.heap.ptr = rb_xmalloc_mul_add_mul(
sizeof(
char),
capa,
sizeof(
char), TERM_LEN(orig));
1608 RBASIC(str)->flags |=
RBASIC(orig)->flags & STR_NOFREE;
1609 RBASIC(orig)->flags &= ~STR_NOFREE;
1610 STR_SET_SHARED(orig, str);
1621 RSTRING(str)->as.heap.aux.capa =
capa + (TERM_LEN(orig) - TERM_LEN(str));
1629 rb_str_tmp_frozen_release(orig, tmp);
1633rb_str_tmp_frozen_release(
VALUE orig,
VALUE tmp)
1638 if (STR_EMBED_P(tmp)) {
1641 else if (
FL_TEST_RAW(orig, STR_SHARED | STR_TMPLOCK) == STR_SHARED &&
1647 RUBY_ASSERT(RSTRING_LEN(orig) == RSTRING_LEN(tmp));
1651 RSTRING(orig)->as.heap.aux.capa =
RSTRING(tmp)->as.heap.aux.capa + TERM_LEN(tmp) - TERM_LEN(orig);
1652 RBASIC(orig)->flags |=
RBASIC(tmp)->flags & STR_NOFREE;
1657 STR_SET_LEN(tmp, 0);
1665 return str_new_frozen_buffer(klass, orig, TRUE);
1674heap_str_make_shared(
VALUE klass,
VALUE orig,
int termlen)
1680 VALUE str = str_alloc_heap(klass);
1681 STR_SET_LEN(str, RSTRING_LEN(orig));
1682 RSTRING(str)->as.heap.ptr = RSTRING_PTR(orig);
1683 RSTRING(str)->as.heap.aux.capa =
RSTRING(orig)->as.heap.aux.capa + TERM_LEN(orig) - termlen;
1684 RBASIC(str)->flags |=
RBASIC(orig)->flags & STR_NOFREE;
1685 RBASIC(orig)->flags &= ~STR_NOFREE;
1686 STR_SET_SHARED(orig, str);
1693str_new_frozen_buffer(
VALUE klass,
VALUE orig,
int copy_encoding)
1697 long len = RSTRING_LEN(orig);
1698 rb_encoding *enc = copy_encoding ? STR_ENC_GET(orig) : rb_ascii8bit_encoding();
1699 int termlen = copy_encoding ? TERM_LEN(orig) : 1;
1701 if (STR_EMBED_P(orig) || STR_EMBEDDABLE_P(
len, termlen)) {
1702 str = str_enc_new(klass, RSTRING_PTR(orig),
len, enc);
1708 long ofs =
RSTRING(orig)->as.heap.ptr - RSTRING_PTR(
shared);
1709 long rest = RSTRING_LEN(
shared) - ofs - RSTRING_LEN(orig);
1715 if ((ofs > 0) || (rest > 0) ||
1718 str = str_new_shared(klass,
shared);
1720 RSTRING(str)->as.heap.ptr += ofs;
1721 STR_SET_LEN(str, RSTRING_LEN(str) - (ofs + rest));
1729 else if (STR_EMBEDDABLE_P(RSTRING_LEN(orig), TERM_LEN(orig))) {
1730 str = str_alloc_embed(klass, RSTRING_LEN(orig) + TERM_LEN(orig));
1732 memcpy(RSTRING_PTR(str), RSTRING_PTR(orig), RSTRING_LEN(orig));
1733 STR_SET_LEN(str, RSTRING_LEN(orig));
1739 str = str_new(klass, RSTRING_PTR(orig), RSTRING_LEN(orig));
1742 str = heap_str_make_shared(klass, orig, termlen);
1747 if (copy_encoding) rb_enc_cr_str_exact_copy(str, orig);
1759str_new_empty_String(
VALUE str)
1762 rb_enc_copy(v, str);
1766#define STR_BUF_MIN_SIZE 63
1771 if (STR_EMBEDDABLE_P(
capa, 1)) {
1779 RSTRING(str)->as.heap.ptr[0] =
'\0';
1799 return str_new(0, 0,
len);
1805 if (STR_EMBED_P(str)) {
1806 RB_DEBUG_COUNTER_INC(obj_str_embed);
1808 else if (
FL_TEST(str, STR_SHARED | STR_NOFREE)) {
1809 (void)RB_DEBUG_COUNTER_INC_IF(obj_str_shared,
FL_TEST(str, STR_SHARED));
1810 (void)RB_DEBUG_COUNTER_INC_IF(obj_str_shared,
FL_TEST(str, STR_NOFREE));
1813 RB_DEBUG_COUNTER_INC(obj_str_ptr);
1814 SIZED_FREE_N(STR_HEAP_PTR(str), STR_HEAP_SIZE(str));
1819rb_str_memsize(
VALUE str)
1821 if (
FL_TEST(str, STR_NOEMBED|STR_SHARED|STR_NOFREE) == STR_NOEMBED) {
1822 return STR_HEAP_SIZE(str);
1832 return rb_convert_type_with_id(str,
T_STRING,
"String", idTo_str);
1835static inline void str_discard(
VALUE str);
1836static void str_shared_replace(
VALUE str,
VALUE str2);
1841 if (str != str2) str_shared_replace(str, str2);
1852 enc = STR_ENC_GET(str2);
1855 termlen = rb_enc_mbminlen(enc);
1857 STR_SET_LEN(str, RSTRING_LEN(str2));
1859 if (str_embed_capa(str) >= RSTRING_LEN(str2) + termlen) {
1861 memcpy(RSTRING_PTR(str), RSTRING_PTR(str2), (
size_t)RSTRING_LEN(str2) + termlen);
1864 if (STR_EMBED_P(str2)) {
1866 long len = RSTRING_LEN(str2);
1869 char *new_ptr =
ALLOC_N(
char,
len + termlen);
1870 memcpy(new_ptr,
RSTRING(str2)->
as.embed.ary,
len + termlen);
1871 RSTRING(str2)->as.heap.ptr = new_ptr;
1872 STR_SET_LEN(str2,
len);
1874 STR_SET_NOEMBED(str2);
1877 STR_SET_NOEMBED(str);
1879 RSTRING(str)->as.heap.ptr = RSTRING_PTR(str2);
1881 if (
FL_TEST(str2, STR_SHARED)) {
1883 STR_SET_SHARED(str,
shared);
1886 RSTRING(str)->as.heap.aux.capa =
RSTRING(str2)->as.heap.aux.capa;
1890 STR_SET_EMBED(str2);
1891 RSTRING_PTR(str2)[0] = 0;
1892 STR_SET_LEN(str2, 0);
1897 rb_enc_raw_set(str, enc);
1910 return rb_obj_as_string_result(str, obj);
1926 len = RSTRING_LEN(str2);
1927 if (STR_SHARED_P(str2)) {
1930 STR_SET_NOEMBED(str);
1931 STR_SET_LEN(str,
len);
1932 RSTRING(str)->as.heap.ptr = RSTRING_PTR(str2);
1933 STR_SET_SHARED(str,
shared);
1934 rb_enc_cr_str_exact_copy(str, str2);
1937 str_replace_shared(str, str2);
1946 size_t size = rb_str_embed_size(
capa, 0);
1962 str->as.heap.aux.capa = 0;
1963 str->as.heap.ptr = NULL;
1973 encidx = rb_enc_get_index(str);
1974 flags &= ~ENCODING_MASK;
1977 if (encidx) rb_enc_associate_index(dup, encidx);
1986 long len = RSTRING_LEN(str);
1991 STR_SET_LEN(dup, RSTRING_LEN(str));
1992 str_duplicate_setup_encoding(str, dup, flags);
2001 root =
RSTRING(str)->as.heap.aux.shared;
2004 root = str = str_new_frozen(klass, str);
2010 RSTRING(dup)->as.heap.ptr = RSTRING_PTR(str);
2012 STR_SET_SHARED(dup, root);
2013 flags |= RSTRING_NOEMBED | STR_SHARED;
2015 STR_SET_LEN(dup, RSTRING_LEN(str));
2016 str_duplicate_setup_encoding(str, dup, flags);
2023 if (STR_EMBED_P(str) && rb_str_embed_size(RSTRING_LEN(str), 1) <= STR_COPY_MAX_EMBED_SIZE) {
2024 dup = str_alloc_embed(klass, RSTRING_LEN(str) + TERM_LEN(str));
2026 str_duplicate_setup_embed(klass, str, dup);
2029 dup = str_alloc_heap(klass);
2031 str_duplicate_setup_heap(klass, str, dup);
2045rb_str_dup_m(
VALUE str)
2047 if (LIKELY(BARE_STRING_P(str))) {
2058 RUBY_DTRACE_CREATE_HOOK(STRING, RSTRING_LEN(str));
2065 RUBY_DTRACE_CREATE_HOOK(STRING, RSTRING_LEN(str));
2069 new_str = ec_str_alloc_embed(ec, klass, RSTRING_LEN(str) + TERM_LEN(str));
2070 str_duplicate_setup_embed(klass, str, new_str);
2073 new_str = ec_str_alloc_heap(ec, klass);
2074 str_duplicate_setup_heap(klass, str, new_str);
2084rb_zjit_str_resurrect_fastpath(
VALUE str,
bool chilled,
size_t *size_out,
2086 long *len_out,
size_t *byte_size_out)
2090 if (!STR_EMBED_P(str))
return false;
2092 long len = RSTRING_LEN(str);
2093 long termlen = TERM_LEN(str);
2094 size_t size = rb_str_embed_size(
len + termlen, 0);
2095 if (!rb_gc_size_allocatable_p(size))
return false;
2103 flags &= ~FL_FREEZE;
2105 if (chilled) flags |= STR_CHILLED;
2110 *byte_size_out = (size_t)(
len + termlen);
2116rb_str_with_debug_created_info(
VALUE str,
VALUE path,
int line)
2118 VALUE debug_info = rb_ary_new_from_args(2, path,
INT2FIX(line));
2142 static ID keyword_ids[2];
2143 VALUE orig, opt, venc, vcapa;
2148 if (!keyword_ids[0]) {
2149 keyword_ids[0] = rb_id_encoding();
2150 CONST_ID(keyword_ids[1],
"capacity");
2158 if (!UNDEF_P(venc) && !
NIL_P(venc)) {
2159 enc = rb_to_encoding(venc);
2161 if (!UNDEF_P(vcapa) && !
NIL_P(vcapa)) {
2164 int termlen = enc ? rb_enc_mbminlen(enc) : 1;
2166 if (
capa < STR_BUF_MIN_SIZE) {
2167 capa = STR_BUF_MIN_SIZE;
2171 len = RSTRING_LEN(orig);
2175 if (orig == str) n = 0;
2177 str_modifiable(str);
2178 if (STR_EMBED_P(str) ||
FL_TEST(str, STR_SHARED|STR_NOFREE)) {
2180 const size_t size = (size_t)
capa + termlen;
2181 const char *
const old_ptr = RSTRING_PTR(str);
2182 const size_t osize = RSTRING_LEN(str) + TERM_LEN(str);
2183 char *new_ptr =
ALLOC_N(
char, size);
2184 if (STR_EMBED_P(str))
RUBY_ASSERT((
long)osize <= str_embed_capa(str));
2185 memcpy(new_ptr, old_ptr, osize < size ? osize : size);
2187 RSTRING(str)->as.heap.ptr = new_ptr;
2189 else if (STR_HEAP_SIZE(str) != (
size_t)
capa + termlen) {
2190 SIZED_REALLOC_N(
RSTRING(str)->
as.heap.ptr,
char,
2191 (
size_t)
capa + termlen, STR_HEAP_SIZE(str));
2193 STR_SET_LEN(str,
len);
2196 memcpy(
RSTRING(str)->
as.heap.ptr, RSTRING_PTR(orig),
len);
2197 rb_enc_cr_str_exact_copy(str, orig);
2199 FL_SET(str, STR_NOEMBED);
2206 rb_enc_associate(str, enc);
2218rb_str_s_new(
int argc,
VALUE *argv,
VALUE klass)
2224 static ID keyword_ids[2];
2234 keyword_ids[0] = rb_id_encoding();
2235 CONST_ID(keyword_ids[1],
"capacity");
2237 encoding = kwargs[0];
2238 capacity = kwargs[1];
2247 if (UNDEF_P(encoding)) {
2249 encoding = rb_obj_encoding(orig);
2253 if (!UNDEF_P(encoding)) {
2254 enc = rb_to_encoding(encoding);
2258 if (UNDEF_P(capacity)) {
2260 VALUE empty_str = str_new(klass,
"", 0);
2262 rb_enc_associate(empty_str, enc);
2266 VALUE copy = str_duplicate(klass, orig);
2267 rb_enc_associate(copy, enc);
2280 if (orig_capa >
capa) {
2285 VALUE str = str_enc_new(klass, NULL,
capa, enc);
2286 STR_SET_LEN(str, 0);
2297#define is_utf8_lead_byte(c) (((c)&0xC0) != 0x80)
2312static inline uintptr_t
2313count_utf8_lead_bytes_with_word(
const uintptr_t *s)
2318 d = (d>>6) | (~d>>7);
2319 d &= NONASCII_MASK >> 7;
2322#if defined(HAVE_BUILTIN___BUILTIN_POPCOUNT) && defined(__POPCNT__)
2324 return rb_popcount_intptr(d);
2328# if SIZEOF_VOIDP == 8
2337enc_strlen(
const char *p,
const char *e,
rb_encoding *enc,
int cr)
2343 long diff = (long)(e - p);
2344 return diff / rb_enc_mbminlen(enc) + !!(diff % rb_enc_mbminlen(enc));
2349 if ((
int)
sizeof(uintptr_t) * 2 < e - p) {
2350 const uintptr_t *s, *t;
2351 const uintptr_t lowbits =
sizeof(uintptr_t) - 1;
2352 s = (
const uintptr_t*)(~lowbits & ((uintptr_t)p + lowbits));
2353 t = (
const uintptr_t*)(~lowbits & (uintptr_t)e);
2354 while (p < (
const char *)s) {
2355 if (is_utf8_lead_byte(*p))
len++;
2359 len += count_utf8_lead_bytes_with_word(s);
2362 p = (
const char *)s;
2365 if (is_utf8_lead_byte(*p))
len++;
2371 else if (rb_enc_asciicompat(enc)) {
2375 q = search_nonascii(p, e);
2380 p += rb_enc_fast_mbclen(p, e, enc);
2386 q = search_nonascii(p, e);
2391 p += rb_enc_mbclen(p, e, enc);
2398 for (c=0; p<e; c++) {
2399 p += rb_enc_mbclen(p, e, enc);
2414rb_enc_strlen_cr(
const char *p,
const char *e,
rb_encoding *enc,
int *cr)
2422 long diff = (long)(e - p);
2423 return diff / rb_enc_mbminlen(enc) + !!(diff % rb_enc_mbminlen(enc));
2425 else if (rb_enc_asciicompat(enc)) {
2428 q = search_nonascii(p, e);
2435 ret = rb_enc_precise_mbclen(p, e, enc);
2450 for (c=0; p<e; c++) {
2451 ret = rb_enc_precise_mbclen(p, e, enc);
2458 if (p + rb_enc_mbminlen(enc) <= e)
2459 p += rb_enc_mbminlen(enc);
2475 if (single_byte_optimizable(str))
return RSTRING_LEN(str);
2476 if (!enc) enc = STR_ENC_GET(str);
2477 p = RSTRING_PTR(str);
2482 long n = rb_enc_strlen_cr(p, e, enc, &cr);
2487 return enc_strlen(p, e, enc, cr);
2494 return str_strlen(str, NULL);
2508 return LONG2NUM(str_strlen(str, NULL));
2520rb_str_bytesize(
VALUE str)
2539rb_str_empty(
VALUE str)
2541 return RBOOL(RSTRING_LEN(str) == 0);
2560 const char *ptr1, *ptr2;
2566 enc = rb_enc_check_str(str1, str2);
2569 termlen = rb_enc_mbminlen(enc);
2570 if (len1 > LONG_MAX - len2) {
2571 rb_raise(rb_eArgError,
"string size too big");
2573 str3 = str_enc_new(
rb_cString, 0, len1+len2, enc);
2574 ptr3 = RSTRING_PTR(str3);
2575 memcpy(ptr3, ptr1, len1);
2576 memcpy(ptr3+len1, ptr2, len2);
2577 TERM_FILL(&ptr3[len1+len2], termlen);
2593 MAYBE_UNUSED(
char) *ptr1, *ptr2;
2596 int enc1 = rb_enc_get_index(str1);
2597 int enc2 = rb_enc_get_index(str2);
2602 else if (enc2 < 0) {
2605 else if (enc1 != enc2) {
2608 else if (len1 > LONG_MAX - len2) {
2642 rb_enc_copy(str2, str);
2647 rb_raise(rb_eArgError,
"negative argument");
2649 if (RSTRING_LEN(str) == 1 && RSTRING_PTR(str)[0] == 0) {
2650 if (STR_EMBEDDABLE_P(
len, 1)) {
2652 memset(RSTRING_PTR(str2), 0,
len + 1);
2659 STR_SET_LEN(str2,
len);
2660 rb_enc_copy(str2, str);
2663 if (
len && LONG_MAX/
len < RSTRING_LEN(str)) {
2664 rb_raise(rb_eArgError,
"argument too big");
2667 len *= RSTRING_LEN(str);
2668 termlen = TERM_LEN(str);
2670 ptr2 = RSTRING_PTR(str2);
2672 n = RSTRING_LEN(str);
2673 memcpy(ptr2, RSTRING_PTR(str), n);
2674 while (n <=
len/2) {
2675 memcpy(ptr2 + n, ptr2, n);
2678 memcpy(ptr2 + n, ptr2,
len-n);
2680 STR_SET_LEN(str2,
len);
2681 TERM_FILL(&ptr2[
len], termlen);
2682 rb_enc_cr_str_copy_for_substr(str2, str);
2721rb_check_lockedtmp(
VALUE str)
2723 if (
FL_TEST(str, STR_TMPLOCK)) {
2730#define STR_UNMODIFIABLE_MASK (FL_FREEZE | STR_TMPLOCK | STR_CHILLED)
2732str_modifiable(
VALUE str)
2736 if (RB_UNLIKELY(
FL_ANY_RAW(str, STR_UNMODIFIABLE_MASK))) {
2737 if (CHILLED_STRING_P(str)) {
2738 CHILLED_STRING_MUTATED(str);
2740 rb_check_lockedtmp(str);
2741 rb_check_frozen(str);
2746str_dependent_p(
VALUE str)
2748 if (STR_EMBED_P(str) || !
FL_TEST(str, STR_SHARED|STR_NOFREE)) {
2758#define STR_DEPENDANT_MASK (STR_UNMODIFIABLE_MASK | STR_SHARED | STR_NOFREE)
2760str_independent(
VALUE str)
2764 if (RB_UNLIKELY(
FL_ANY_RAW(str, STR_DEPENDANT_MASK))) {
2765 str_modifiable(str);
2766 return !str_dependent_p(str);
2772str_make_independent_expand(
VALUE str,
long len,
long expand,
const int termlen)
2782 if (!STR_EMBED_P(str) && str_embed_capa(str) >=
capa + termlen) {
2787 STR_SET_LEN(str,
len);
2792 oldptr = RSTRING_PTR(str);
2794 memcpy(
ptr, oldptr,
len);
2796 if (
FL_TEST_RAW(str, STR_NOEMBED|STR_NOFREE|STR_SHARED) == STR_NOEMBED) {
2797 SIZED_FREE_N(oldptr, STR_HEAP_SIZE(str));
2799 STR_SET_NOEMBED(str);
2800 FL_UNSET(str, STR_SHARED|STR_NOFREE);
2801 TERM_FILL(
ptr +
len, termlen);
2803 STR_SET_LEN(str,
len);
2810 if (!str_independent(str))
2811 str_make_independent(str);
2820 int termlen = TERM_LEN(str);
2821 long len = RSTRING_LEN(str);
2824 rb_raise(rb_eArgError,
"negative expanding string size");
2826 if (expand >= LONG_MAX -
len) {
2827 rb_raise(rb_eArgError,
"string size too big");
2830 if (!str_independent(str)) {
2831 str_make_independent_expand(str,
len, expand, termlen);
2833 else if (expand > 0) {
2834 RESIZE_CAPA_TERM(str,
len + expand, termlen);
2841str_modify_keep_cr(
VALUE str)
2843 if (!str_independent(str))
2844 str_make_independent(str);
2851str_discard(
VALUE str)
2853 str_modifiable(str);
2854 if (!STR_EMBED_P(str) && !
FL_TEST(str, STR_SHARED|STR_NOFREE)) {
2855 SIZED_FREE_N(STR_HEAP_PTR(str), STR_HEAP_SIZE(str));
2856 RSTRING(str)->as.heap.ptr = 0;
2857 STR_SET_LEN(str, 0);
2864 int encindex = rb_enc_get_index(str);
2866 if (RB_UNLIKELY(encindex == -1)) {
2870 if (RB_LIKELY(rb_str_encindex_fastpath(encindex))) {
2875 if (!rb_enc_asciicompat(enc)) {
2897 return RSTRING_PTR(str);
2901str_null_char(
const char *s,
long len,
const int minlen,
rb_encoding *enc)
2903 const char *e = s +
len;
2905 for (; s + minlen <= e; s += rb_enc_mbclen(s, e, enc)) {
2906 if (zero_filled(s, minlen))
return s;
2912str_fill_term(
VALUE str,
char *s,
long len,
int termlen)
2917 if (str_dependent_p(str)) {
2918 if (!zero_filled(s +
len, termlen))
2919 str_make_independent_expand(str,
len, 0L, termlen);
2922 TERM_FILL(s +
len, termlen);
2925 return RSTRING_PTR(str);
2929rb_str_change_terminator_length(
VALUE str,
const int oldtermlen,
const int termlen)
2931 long capa = str_capacity(str, oldtermlen) + oldtermlen;
2932 long len = RSTRING_LEN(str);
2936 rb_check_lockedtmp(str);
2937 str_make_independent_expand(str,
len, 0L, termlen);
2939 else if (str_dependent_p(str)) {
2940 if (termlen > oldtermlen)
2941 str_make_independent_expand(str,
len, 0L, termlen);
2944 if (!STR_EMBED_P(str)) {
2949 if (termlen > oldtermlen) {
2950 TERM_FILL(RSTRING_PTR(str) +
len, termlen);
2958str_null_check(
VALUE str,
int *w)
2960 char *s = RSTRING_PTR(str);
2961 long len = RSTRING_LEN(str);
2964 if (RB_UNLIKELY(!rb_str_enc_fastpath(str))) {
2966 minlen = rb_enc_mbminlen(enc);
2970 if (str_null_char(s,
len, minlen, enc)) {
2973 return str_fill_term(str, s,
len, minlen);
2978 if (!s || memchr(s, 0,
len)) {
2982 s = str_fill_term(str, s,
len, minlen);
2987static char *str_to_cstr(
VALUE str);
2990rb_str_null_check(
VALUE str)
2998 if (RB_LIKELY(rb_str_enc_fastpath(str))) {
2999 if (!s || memchr(s, 0,
len)) {
3000 rb_raise(rb_eArgError,
"string contains null byte");
3011rb_str_to_cstr(
VALUE str)
3014 return str_null_check(str, &w);
3021 return str_to_cstr(str);
3025str_to_cstr(
VALUE str)
3028 char *s = str_null_check(str, &w);
3031 rb_raise(rb_eArgError,
"string contains null char");
3033 rb_raise(rb_eArgError,
"string contains null byte");
3039rb_str_fill_terminator(
VALUE str,
const int newminlen)
3041 char *s = RSTRING_PTR(str);
3042 long len = RSTRING_LEN(str);
3043 return str_fill_term(str, s,
len, newminlen);
3049 str = rb_check_convert_type_with_id(str,
T_STRING,
"String", idTo_str);
3075str_nth_len(
const char *p,
const char *e,
long *nthp,
rb_encoding *enc)
3084 else if (rb_enc_asciicompat(enc)) {
3085 const char *p2, *e2;
3088 while (p < e && 0 < nth) {
3094 p2 = search_nonascii(p, e2);
3102 n = rb_enc_mbclen(p, e, enc);
3113 while (p < e && nth--) {
3114 p += rb_enc_mbclen(p, e, enc);
3125 return str_nth_len(p, e, &nth, enc);
3129str_nth(
const char *p,
const char *e,
long nth,
rb_encoding *enc,
int singlebyte)
3134 p = str_nth_len(p, e, &nth, enc);
3143str_offset(
const char *p,
const char *e,
long nth,
rb_encoding *enc,
int singlebyte)
3145 const char *pp = str_nth(p, e, nth, enc, singlebyte);
3146 if (!pp)
return e - p;
3153 return str_offset(RSTRING_PTR(str),
RSTRING_END(str), pos,
3154 STR_ENC_GET(str), single_byte_optimizable(str));
3159str_utf8_nth(
const char *p,
const char *e,
long *nthp)
3162 if ((
int)SIZEOF_VOIDP * 2 < e - p && (
int)SIZEOF_VOIDP * 2 < nth) {
3163 const uintptr_t *s, *t;
3164 const uintptr_t lowbits = SIZEOF_VOIDP - 1;
3165 s = (
const uintptr_t*)(~lowbits & ((uintptr_t)p + lowbits));
3166 t = (
const uintptr_t*)(~lowbits & (uintptr_t)e);
3167 while (p < (
const char *)s) {
3168 if (is_utf8_lead_byte(*p)) nth--;
3172 nth -= count_utf8_lead_bytes_with_word(s);
3174 }
while (s < t && (
int)SIZEOF_VOIDP <= nth);
3178 if (is_utf8_lead_byte(*p)) {
3179 if (nth == 0)
break;
3189str_utf8_offset(
const char *p,
const char *e,
long nth)
3191 const char *pp = str_utf8_nth(p, e, &nth);
3200 if (single_byte_optimizable(str) || pos < 0)
3203 const char *p = RSTRING_PTR(str);
3204 return enc_strlen(p, p + pos, STR_ENC_GET(str),
ENC_CODERANGE(str));
3209str_subseq(
VALUE str,
long beg,
long len)
3217 const int termlen = TERM_LEN(str);
3218 if (!SHARABLE_SUBSTRING_P(str, beg,
len)) {
3219 str2 = rb_enc_str_new(RSTRING_PTR(str) + beg,
len, rb_str_enc_get(str));
3229 const bool root_available = STR_SHARED_P(str) ||
3231 const size_t max_embed_size = root_available ?
3232 rb_gc_size_slot_size(
sizeof(
struct RString)) : STR_COPY_MAX_EMBED_SIZE;
3233 const size_t embed_size = rb_str_embed_size(
len, termlen);
3235 if (embed_size <= max_embed_size && rb_gc_size_allocatable_p(embed_size)) {
3237 char *ptr2 =
RSTRING(str2)->as.embed.ary;
3238 memcpy(ptr2, RSTRING_PTR(str) + beg,
len);
3239 TERM_FILL(ptr2 +
len, termlen);
3241 STR_SET_LEN(str2,
len);
3250 str_replace_shared(str2, str);
3256 RSTRING(str2)->as.heap.ptr += beg;
3257 if (RSTRING_LEN(str2) >
len) {
3258 STR_SET_LEN(str2,
len);
3268 VALUE str2 = str_subseq(str, beg,
len);
3269 rb_enc_cr_str_copy_for_substr(str2, str);
3278 const long blen = RSTRING_LEN(str);
3280 const char *p, *s = RSTRING_PTR(str), *e = s + blen;
3282 if (
len < 0)
return 0;
3283 if (beg < 0 && -beg < 0)
return 0;
3287 if (single_byte_optimizable(str)) {
3288 if (beg > blen)
return 0;
3291 if (beg < 0)
return 0;
3293 if (
len > blen - beg)
3295 if (
len < 0)
return 0;
3300 if (
len > -beg)
len = -beg;
3304 while (beg-- >
len && (e = rb_enc_prev_char(s, e, e, enc)) != 0);
3307 while (
len-- > 0 && (p = rb_enc_prev_char(s, p, e, enc)) != 0);
3313 slen = str_strlen(str, enc);
3315 if (beg < 0)
return 0;
3317 if (
len == 0)
goto end;
3320 else if (beg > 0 && beg > blen) {
3324 if (beg > str_strlen(str, enc))
return 0;
3329 enc == rb_utf8_encoding()) {
3330 p = str_utf8_nth(s, e, &beg);
3331 if (beg > 0)
return 0;
3332 len = str_utf8_offset(p, e,
len);
3338 p = s + beg * char_sz;
3342 else if (
len * char_sz > e - p)
3347 else if ((p = str_nth_len(s, e, &beg, enc)) == e) {
3348 if (beg > 0)
return 0;
3352 len = str_offset(p, e,
len, enc, 0);
3360static VALUE str_substr(
VALUE str,
long beg,
long len,
int empty);
3365 return str_substr(str, beg,
len, TRUE);
3375str_substr(
VALUE str,
long beg,
long len,
int empty)
3379 if (!p)
return Qnil;
3380 if (!
len && !empty)
return Qnil;
3382 beg = p - RSTRING_PTR(str);
3384 VALUE str2 = str_subseq(str, beg,
len);
3385 rb_enc_cr_str_copy_for_substr(str2, str);
3393 if (CHILLED_STRING_P(str)) {
3398 rb_str_resize(str, RSTRING_LEN(str));
3416 if (
OBJ_FROZEN(str) || CHILLED_STRING_P(str)) {
3459str_uminus(
VALUE str)
3464 return rb_fstring(str);
3468#define rb_str_dup_frozen rb_str_new_frozen
3473 rb_check_frozen(str);
3474 if (
FL_TEST(str, STR_TMPLOCK)) {
3477 FL_SET(str, STR_TMPLOCK);
3484 rb_check_frozen(str);
3485 if (!
FL_TEST(str, STR_TMPLOCK)) {
3505 const int termlen = TERM_LEN(str);
3507 str_modifiable(str);
3508 if (STR_SHARED_P(str)) {
3511 if (
len > (
capa = (
long)str_capacity(str, termlen)) ||
len < 0) {
3512 rb_bug(
"probable buffer overflow: %ld for %ld",
len,
capa);
3523 else if (
len > RSTRING_LEN(str)) {
3527 const char *
const new_end = RSTRING_PTR(str) +
len;
3537 else if (
len < RSTRING_LEN(str)) {
3545 STR_SET_LEN(str,
len);
3546 TERM_FILL(&RSTRING_PTR(str)[
len], termlen);
3553 rb_raise(rb_eArgError,
"negative string size (or size too big)");
3556 int independent = str_independent(str);
3557 long slen = RSTRING_LEN(str);
3558 const int termlen = TERM_LEN(str);
3560 if (slen >
len || (termlen != 1 && slen <
len)) {
3566 if (STR_EMBED_P(str)) {
3567 if (
len == slen)
return str;
3568 if (str_embed_capa(str) >=
len + termlen) {
3569 STR_SET_LEN(str,
len);
3573 str_make_independent_expand(str, slen,
len - slen, termlen);
3575 else if (str_embed_capa(str) >=
len + termlen) {
3577 char *
ptr = STR_HEAP_PTR(str);
3579 if (slen >
len) slen =
len;
3582 STR_SET_LEN(str,
len);
3584 SIZED_FREE_N(
ptr,
capa + termlen);
3588 else if (!independent) {
3589 if (
len == slen)
return str;
3590 str_make_independent_expand(str, slen,
len - slen, termlen);
3594 SIZED_REALLOC_N(
RSTRING(str)->
as.heap.ptr,
char,
3595 (
size_t)
len + termlen, STR_HEAP_SIZE(str));
3598 else if (
len == slen)
return str;
3599 STR_SET_LEN(str,
len);
3606str_ensure_available_capa(
VALUE str,
long len)
3608 str_modify_keep_cr(str);
3610 const int termlen = TERM_LEN(str);
3611 long olen = RSTRING_LEN(str);
3613 if (RB_UNLIKELY(olen > LONG_MAX -
len)) {
3614 rb_raise(rb_eArgError,
"string sizes too big");
3617 long total = olen +
len;
3618 long capa = str_capacity(str, termlen);
3621 if (total >= LONG_MAX / 2) {
3624 while (total >
capa) {
3627 RESIZE_CAPA_TERM(str,
capa, termlen);
3632str_buf_cat4(
VALUE str,
const char *
ptr,
long len,
bool keep_cr)
3635 str_modify_keep_cr(str);
3640 if (
len == 0)
return 0;
3642 long total, olen,
off = -1;
3644 const int termlen = TERM_LEN(str);
3647 if (
ptr >= sptr &&
ptr <= sptr + olen) {
3651 long capa = str_capacity(str, termlen);
3653 if (olen > LONG_MAX -
len) {
3654 rb_raise(rb_eArgError,
"string sizes too big");
3658 if (total >= LONG_MAX / 2) {
3661 while (total >
capa) {
3664 RESIZE_CAPA_TERM(str,
capa, termlen);
3665 sptr = RSTRING_PTR(str);
3670 memcpy(sptr + olen,
ptr,
len);
3671 STR_SET_LEN(str, total);
3672 TERM_FILL(sptr + total, termlen);
3677#define str_buf_cat(str, ptr, len) str_buf_cat4((str), (ptr), len, false)
3678#define str_buf_cat2(str, ptr) str_buf_cat4((str), (ptr), rb_strlen_lit(ptr), false)
3683 if (
len == 0)
return str;
3685 rb_raise(rb_eArgError,
"negative string size (or size too big)");
3687 return str_buf_cat(str,
ptr,
len);
3698rb_str_buf_cat_byte(
VALUE str,
unsigned char byte)
3703 if (UNLIKELY(!str_independent(str))) {
3704 str_make_independent(str);
3707 long string_length = -1;
3708 const int null_terminator_length = 1;
3713 if (UNLIKELY(string_length > LONG_MAX - 1)) {
3714 rb_raise(rb_eArgError,
"string sizes too big");
3717 long string_capacity = str_capacity(str, null_terminator_length);
3723 if (LIKELY(string_capacity >= string_length + 1)) {
3725 sptr[string_length] = byte;
3726 STR_SET_LEN(str, string_length + 1);
3727 TERM_FILL(sptr + string_length + 1, null_terminator_length);
3731 str_buf_cat(str, (
char *)&
byte, 1);
3747 rb_enc_associate_index(str, ENCINDEX_ASCII_8BIT);
3758rb_enc_cr_str_buf_cat(
VALUE str,
const char *
ptr,
long len,
3759 int ptr_encindex,
int ptr_cr,
int *ptr_cr_ret)
3768 if (str_encindex == ptr_encindex) {
3770 ptr_cr = coderange_scan(
ptr,
len, rb_enc_from_index(ptr_encindex));
3774 str_enc = rb_enc_from_index(str_encindex);
3775 ptr_enc = rb_enc_from_index(ptr_encindex);
3776 if (!rb_enc_asciicompat(str_enc) || !rb_enc_asciicompat(ptr_enc)) {
3779 if (RSTRING_LEN(str) == 0) {
3782 rb_str_change_terminator_length(str, rb_enc_mbminlen(str_enc), rb_enc_mbminlen(ptr_enc));
3788 ptr_cr = coderange_scan(
ptr,
len, ptr_enc);
3792 str_cr = rb_enc_str_coderange(str);
3797 *ptr_cr_ret = ptr_cr;
3799 if (str_encindex != ptr_encindex &&
3802 str_enc = rb_enc_from_index(str_encindex);
3803 ptr_enc = rb_enc_from_index(ptr_encindex);
3808 res_encindex = str_encindex;
3813 res_encindex = str_encindex;
3817 res_encindex = ptr_encindex;
3822 res_encindex = str_encindex;
3829 res_encindex = str_encindex;
3835 rb_raise(rb_eArgError,
"negative string size (or size too big)");
3837 str_buf_cat(str,
ptr,
len);
3843 rb_enc_inspect_name(str_enc), rb_enc_inspect_name(ptr_enc));
3850 return rb_enc_cr_str_buf_cat(str,
ptr,
len,
3860 if (rb_enc_asciicompat(enc)) {
3861 return rb_enc_cr_str_buf_cat(str,
ptr, strlen(
ptr),
3867 unsigned int c = (
unsigned char)*
ptr;
3868 int len = rb_enc_codelen(c, enc);
3869 rb_enc_mbcput(c, buf, enc);
3870 rb_enc_cr_str_buf_cat(str, buf,
len,
3881 int str2_cr = rb_enc_str_coderange(str2);
3883 if (rb_str_enc_fastpath(str)) {
3887 str_buf_cat4(str, RSTRING_PTR(str2), RSTRING_LEN(str2),
true);
3893 str_buf_cat4(str, RSTRING_PTR(str2), RSTRING_LEN(str2),
true);
3904 rb_enc_cr_str_buf_cat(str, RSTRING_PTR(str2), RSTRING_LEN(str2),
3920rb_str_concat_literals(
size_t num,
const VALUE *strary)
3924 unsigned long len = 1;
3929 for (i = 0; i < num; ++i) {
len += RSTRING_LEN(strary[i]); }
3931 str_enc_copy_direct(str, strary[0]);
3933 for (i = s; i < num; ++i) {
3934 const VALUE v = strary[i];
3938 if (encidx != ENCINDEX_US_ASCII) {
3940 rb_enc_set_index(str, encidx);
3953rb_str_concat_multi(
int argc,
VALUE *argv,
VALUE str)
3955 str_modifiable(str);
3960 else if (argc > 1) {
3963 rb_enc_copy(arg_str, str);
3964 for (i = 0; i < argc; i++) {
3999rb_str_append_as_bytes(
int argc,
VALUE *argv,
VALUE str)
4001 long needed_capacity = 0;
4005 for (
int index = 0; index < argc; index++) {
4006 VALUE obj = argv[index];
4014 needed_capacity += RSTRING_LEN(obj);
4019 "wrong argument type %"PRIsVALUE
" (expected String or Integer)",
4026 str_ensure_available_capa(str, needed_capacity);
4029 for (
int index = 0; index < argc; index++) {
4030 VALUE obj = argv[index];
4035 argv[index] = obj = rb_int_and(obj,
INT2FIX(0xff));
4036 char byte = (char)(
NUM2INT(obj) & 0xFF);
4050 rb_bug(
"append_as_bytes arguments should have been validated");
4054 STR_SET_LEN(str, RSTRING_LEN(str) + needed_capacity);
4055 TERM_FILL(sptr, TERM_LEN(str));
4060 for (
int index = 0; index < argc; index++) {
4061 VALUE obj = argv[index];
4078 rb_bug(
"append_as_bytes arguments should have been validated");
4157 if (rb_num_to_uint(str2, &code) == 0) {
4170 encidx = rb_ascii8bit_appendable_encoding_index(enc, code);
4173 rb_str_buf_cat_byte(str1, (
unsigned char)code);
4176 long pos = RSTRING_LEN(str1);
4181 switch (
len = rb_enc_codelen(code, enc)) {
4182 case ONIGERR_INVALID_CODE_POINT_VALUE:
4183 rb_raise(
rb_eRangeError,
"invalid codepoint 0x%X in %s", code, rb_enc_name(enc));
4185 case ONIGERR_TOO_BIG_WIDE_CHAR_VALUE:
4191 rb_enc_mbcput(code, buf, enc);
4192 if (rb_enc_precise_mbclen(buf, buf +
len + 1, enc) !=
len) {
4193 rb_raise(
rb_eRangeError,
"invalid codepoint 0x%X in %s", code, rb_enc_name(enc));
4195 rb_str_resize(str1, pos+
len);
4196 memcpy(RSTRING_PTR(str1) + pos, buf,
len);
4209rb_ascii8bit_appendable_encoding_index(
rb_encoding *enc,
unsigned int code)
4211 int encidx = rb_enc_to_index(enc);
4213 if (encidx == ENCINDEX_ASCII_8BIT || encidx == ENCINDEX_US_ASCII) {
4218 if (encidx == ENCINDEX_US_ASCII && code > 127) {
4219 return ENCINDEX_ASCII_8BIT;
4241rb_str_prepend_multi(
int argc,
VALUE *argv,
VALUE str)
4243 str_modifiable(str);
4248 else if (argc > 1) {
4251 rb_enc_copy(arg_str, str);
4252 for (i = 0; i < argc; i++) {
4265 st_index_t precomputed_hash;
4266 memcpy(&precomputed_hash,
RSTRING_END(str) + TERM_LEN(str),
sizeof(precomputed_hash));
4268 RUBY_ASSERT(precomputed_hash == str_do_hash(str));
4269 return precomputed_hash;
4272 return str_do_hash(str);
4279 const char *ptr1, *ptr2;
4282 return (len1 != len2 ||
4284 memcmp(ptr1, ptr2, len1) != 0);
4296rb_str_hash_m(
VALUE str)
4302#define lesser(a,b) (((a)>(b))?(b):(a))
4310 if (RSTRING_LEN(str1) == 0)
return TRUE;
4311 if (RSTRING_LEN(str2) == 0)
return TRUE;
4314 if (idx1 == idx2)
return TRUE;
4315 rc1 = rb_enc_str_coderange(str1);
4316 rc2 = rb_enc_str_coderange(str2);
4319 if (rb_enc_asciicompat(rb_enc_from_index(idx2)))
4323 if (rb_enc_asciicompat(rb_enc_from_index(idx1)))
4333 const char *ptr1, *ptr2;
4336 if (str1 == str2)
return 0;
4339 if (ptr1 == ptr2 || (retval = memcmp(ptr1, ptr2, lesser(len1, len2))) == 0) {
4348 if (len1 > len2)
return 1;
4351 if (retval > 0)
return 1;
4385 if (str1 == str2)
return Qtrue;
4392 return rb_str_eql_internal(str1, str2);
4406 if (str1 == str2)
return Qtrue;
4408 return rb_str_eql_internal(str1, str2);
4446 return rb_invcmp(str1, str2);
4488 return str_casecmp(str1, s);
4496 const char *p1, *p1end, *p2, *p2end;
4498 enc = rb_enc_compatible(str1, str2);
4503 p1 = RSTRING_PTR(str1); p1end =
RSTRING_END(str1);
4504 p2 = RSTRING_PTR(str2); p2end =
RSTRING_END(str2);
4505 if (single_byte_optimizable(str1) && single_byte_optimizable(str2)) {
4506 while (p1 < p1end && p2 < p2end) {
4508 unsigned int c1 =
TOLOWER(*p1 & 0xff);
4509 unsigned int c2 =
TOLOWER(*p2 & 0xff);
4511 return INT2FIX(c1 < c2 ? -1 : 1);
4518 while (p1 < p1end && p2 < p2end) {
4519 int l1, c1 = rb_enc_ascget(p1, p1end, &l1, enc);
4520 int l2, c2 = rb_enc_ascget(p2, p2end, &l2, enc);
4522 if (0 <= c1 && 0 <= c2) {
4526 return INT2FIX(c1 < c2 ? -1 : 1);
4530 l1 = rb_enc_mbclen(p1, p1end, enc);
4531 l2 = rb_enc_mbclen(p2, p2end, enc);
4532 len = l1 < l2 ? l1 : l2;
4533 r = memcmp(p1, p2,
len);
4535 return INT2FIX(r < 0 ? -1 : 1);
4537 return INT2FIX(l1 < l2 ? -1 : 1);
4543 if (p1 == p1end && p2 == p2end)
return INT2FIX(0);
4544 if (p1 == p1end)
return INT2FIX(-1);
4577 return str_casecmp_p(str1, s);
4584 VALUE folded_str1, folded_str2;
4585 VALUE fold_opt = sym_fold;
4587 enc = rb_enc_compatible(str1, str2);
4592 if (is_ascii_string(str1) && is_ascii_string(str2)) {
4593 if (RSTRING_LEN(str1) != RSTRING_LEN(str2))
return Qfalse;
4594 const char *p1 = RSTRING_PTR(str1), *p1end =
RSTRING_END(str1);
4595 const char *p2 = RSTRING_PTR(str2);
4596 while (p1 < p1end) {
4597 if (*p1 != *p2 &&
TOLOWER((
unsigned char)*p1) !=
TOLOWER((
unsigned char)*p2)) {
4606 folded_str1 = rb_str_downcase(1, &fold_opt, str1);
4607 folded_str2 = rb_str_downcase(1, &fold_opt, str2);
4609 return rb_str_eql(folded_str1, folded_str2);
4613strseq_core(
const char *str_ptr,
const char *str_ptr_end,
long str_len,
4614 const char *sub_ptr,
long sub_len,
long offset,
rb_encoding *enc)
4616 const char *search_start = str_ptr;
4617 long pos, search_len = str_len - offset;
4621 pos =
rb_memsearch(sub_ptr, sub_len, search_start, search_len, enc);
4622 if (pos < 0)
return pos;
4624 if (t == search_start + pos)
break;
4625 search_len -= t - search_start;
4626 if (search_len <= 0)
return -1;
4627 offset += t - search_start;
4630 return pos + offset;
4634#define rb_str_index(str, sub, offset) rb_strseq_index(str, sub, offset, 0)
4635#define rb_str_byteindex(str, sub, offset) rb_strseq_index(str, sub, offset, 1)
4638rb_strseq_index(
VALUE str,
VALUE sub,
long offset,
int in_byte)
4640 const char *str_ptr, *str_ptr_end, *sub_ptr;
4641 long str_len, sub_len;
4644 enc = rb_enc_check(str, sub);
4645 if (is_broken_string(sub))
return -1;
4647 str_ptr = RSTRING_PTR(str);
4649 str_len = RSTRING_LEN(str);
4650 sub_ptr = RSTRING_PTR(sub);
4651 sub_len = RSTRING_LEN(sub);
4653 if (str_len < sub_len)
return -1;
4656 long str_len_char, sub_len_char;
4657 int single_byte = single_byte_optimizable(str);
4658 str_len_char = (in_byte || single_byte) ? str_len : str_strlen(str, enc);
4659 sub_len_char = in_byte ? sub_len : str_strlen(sub, enc);
4661 offset += str_len_char;
4662 if (offset < 0)
return -1;
4664 if (str_len_char - offset < sub_len_char)
return -1;
4665 if (!in_byte) offset = str_offset(str_ptr, str_ptr_end, offset, enc, single_byte);
4668 if (sub_len == 0)
return offset;
4671 return strseq_core(str_ptr, str_ptr_end, str_len, sub_ptr, sub_len, offset, enc);
4684rb_str_index_m(
int argc,
VALUE *argv,
VALUE str)
4691 if (
rb_scan_args(argc, argv,
"11", &sub, &initpos) == 2) {
4692 long slen = str_strlen(str, enc);
4694 if (pos < 0 ? (pos += slen) < 0 : pos > slen) {
4706 pos = str_offset(RSTRING_PTR(str),
RSTRING_END(str), pos,
4707 enc, single_byte_optimizable(str));
4717 pos = rb_str_index(str, sub, pos);
4731str_ensure_byte_pos(
VALUE str,
long pos)
4733 if (!single_byte_optimizable(str)) {
4734 const char *s = RSTRING_PTR(str);
4736 const char *p = s + pos;
4737 if (!at_char_boundary(s, p, e, rb_enc_get(str))) {
4739 "offset %ld does not land on character boundary", pos);
4812rb_str_byteindex_m(
int argc,
VALUE *argv,
VALUE str)
4818 if (
rb_scan_args(argc, argv,
"11", &sub, &initpos) == 2) {
4820 long slen = RSTRING_LEN(str);
4821 if (pos < 0 ? (pos += slen) < 0 : pos > slen) {
4832 str_ensure_byte_pos(str, pos);
4837 pos = RMATCH_BEG(match, 0);
4843 pos = rb_str_byteindex(str, sub, pos);
4844 if (pos >= 0)
return LONG2NUM(pos);
4852 const char *hit, *adjusted, *sbeg, *e, *t;
4854 long slen, searchlen;
4856 sbeg = RSTRING_PTR(str);
4857 slen = RSTRING_LEN(sub);
4858 if (slen == 0)
return s - sbeg;
4860 t = RSTRING_PTR(sub);
4862 searchlen = s - sbeg + 1;
4864 if (s + slen <= e && memcmp(s, t, slen) == 0) {
4869 hit = memrchr(sbeg, c, searchlen);
4872 if (hit != adjusted) {
4873 searchlen = adjusted - sbeg;
4876 if (hit + slen <= e && memcmp(hit, t, slen) == 0)
4878 searchlen = adjusted - sbeg;
4879 }
while (searchlen > 0);
4889 const char *sbeg, *s;
4893 enc = rb_enc_check(str, sub);
4894 if (is_broken_string(sub))
return -1;
4895 singlebyte = single_byte_optimizable(str);
4896 len = singlebyte ? RSTRING_LEN(str) : str_strlen(str, enc);
4897 slen = str_strlen(sub, enc);
4900 if (
len < slen)
return -1;
4902 if (
len - pos < slen) pos =
len - slen;
4903 if (
len == 0)
return pos;
4905 sbeg = RSTRING_PTR(str);
4908 if (RSTRING_LEN(sub) <= RSTRING_LEN(str) &&
4909 memcmp(sbeg, RSTRING_PTR(sub), RSTRING_LEN(sub)) == 0) {
4917 s = str_nth(sbeg,
RSTRING_END(str), pos, enc, singlebyte);
4918 return str_rindex(str, sub, s, enc);
4930rb_str_rindex_m(
int argc,
VALUE *argv,
VALUE str)
4935 long pos,
len = str_strlen(str, enc);
4937 if (
rb_scan_args(argc, argv,
"11", &sub, &initpos) == 2) {
4939 if (pos < 0 && (pos +=
len) < 0) {
4945 if (pos >
len) pos =
len;
4953 pos = str_offset(RSTRING_PTR(str),
RSTRING_END(str), pos,
4954 enc, single_byte_optimizable(str));
4964 pos = rb_str_rindex(str, sub, pos);
4974rb_str_byterindex(
VALUE str,
VALUE sub,
long pos)
4977 const char *sbeg, *s;
4980 enc = rb_enc_check(str, sub);
4981 if (is_broken_string(sub))
return -1;
4982 len = RSTRING_LEN(str);
4983 slen = RSTRING_LEN(sub);
4986 if (
len < slen)
return -1;
4987 if (
len - pos < slen) pos =
len - slen;
4988 if (
len == 0)
return pos;
4990 sbeg = RSTRING_PTR(str);
4993 if (memcmp(sbeg, RSTRING_PTR(sub), RSTRING_LEN(sub)) == 0)
5000 return str_rindex(str, sub, s, enc);
5090rb_str_byterindex_m(
int argc,
VALUE *argv,
VALUE str)
5096 if (
rb_scan_args(argc, argv,
"11", &sub, &initpos) == 2) {
5098 long len = RSTRING_LEN(str);
5099 if (pos < 0 && (pos +=
len) < 0) {
5105 if (pos >
len) pos =
len;
5108 pos = RSTRING_LEN(str);
5111 str_ensure_byte_pos(str, pos);
5116 pos = RMATCH_BEG(match, 0);
5122 pos = rb_str_byterindex(str, sub, pos);
5123 if (pos >= 0)
return LONG2NUM(pos);
5165 switch (OBJ_BUILTIN_TYPE(y)) {
5217rb_str_match_m(
int argc,
VALUE *argv,
VALUE str)
5224 result =
rb_funcallv(get_pat(re), rb_intern(
"match"), argc, argv);
5255rb_str_match_m_p(
int argc,
VALUE *argv,
VALUE str)
5259 re = get_pat(argv[0]);
5260 return rb_reg_match_p(re, str, argc > 1 ?
NUM2LONG(argv[1]) : 0);
5269static enum neighbor_char
5275 if (rb_enc_mbminlen(enc) > 1) {
5277 int r = rb_enc_precise_mbclen(p, p +
len, enc), c;
5279 return NEIGHBOR_NOT_CHAR;
5281 c = rb_enc_mbc_to_codepoint(p, p +
len, enc) + 1;
5283 if (!l)
return NEIGHBOR_NOT_CHAR;
5284 if (l !=
len)
return NEIGHBOR_WRAPPED;
5285 rb_enc_mbcput(c, p, enc);
5286 r = rb_enc_precise_mbclen(p, p +
len, enc);
5288 return NEIGHBOR_NOT_CHAR;
5290 return NEIGHBOR_FOUND;
5293 for (i =
len-1; 0 <= i && (
unsigned char)p[i] == 0xff; i--)
5296 return NEIGHBOR_WRAPPED;
5297 ++((
unsigned char*)p)[i];
5298 l = rb_enc_precise_mbclen(p, p+
len, enc);
5302 return NEIGHBOR_FOUND;
5305 memset(p+l, 0xff,
len-l);
5311 for (len2 =
len-1; 0 < len2; len2--) {
5312 l2 = rb_enc_precise_mbclen(p, p+len2, enc);
5316 memset(p+len2+1, 0xff,
len-(len2+1));
5321static enum neighbor_char
5326 if (rb_enc_mbminlen(enc) > 1) {
5328 int r = rb_enc_precise_mbclen(p, p +
len, enc), c;
5330 return NEIGHBOR_NOT_CHAR;
5332 c = rb_enc_mbc_to_codepoint(p, p +
len, enc);
5333 if (!c)
return NEIGHBOR_NOT_CHAR;
5336 if (!l)
return NEIGHBOR_NOT_CHAR;
5337 if (l !=
len)
return NEIGHBOR_WRAPPED;
5338 rb_enc_mbcput(c, p, enc);
5339 r = rb_enc_precise_mbclen(p, p +
len, enc);
5341 return NEIGHBOR_NOT_CHAR;
5343 return NEIGHBOR_FOUND;
5346 for (i =
len-1; 0 <= i && (
unsigned char)p[i] == 0; i--)
5349 return NEIGHBOR_WRAPPED;
5350 --((
unsigned char*)p)[i];
5351 l = rb_enc_precise_mbclen(p, p+
len, enc);
5355 return NEIGHBOR_FOUND;
5358 memset(p+l, 0,
len-l);
5364 for (len2 =
len-1; 0 < len2; len2--) {
5365 l2 = rb_enc_precise_mbclen(p, p+len2, enc);
5369 memset(p+len2+1, 0,
len-(len2+1));
5383static enum neighbor_char
5384enc_succ_alnum_char(
char *p,
long len,
rb_encoding *enc,
char *carry)
5386 enum neighbor_char ret;
5390 char save[ONIGENC_CODE_TO_MBC_MAXLEN];
5394 const int max_gaps = 1;
5396 c = rb_enc_mbc_to_codepoint(p, p+
len, enc);
5398 ctype = ONIGENC_CTYPE_DIGIT;
5400 ctype = ONIGENC_CTYPE_ALPHA;
5402 return NEIGHBOR_NOT_CHAR;
5405 for (
try = 0;
try <= max_gaps; ++
try) {
5406 ret = enc_succ_char(p,
len, enc);
5407 if (ret == NEIGHBOR_FOUND) {
5408 c = rb_enc_mbc_to_codepoint(p, p+
len, enc);
5410 return NEIGHBOR_FOUND;
5417 ret = enc_pred_char(p,
len, enc);
5418 if (ret == NEIGHBOR_FOUND) {
5419 c = rb_enc_mbc_to_codepoint(p, p+
len, enc);
5432 return NEIGHBOR_NOT_CHAR;
5435 if (ctype != ONIGENC_CTYPE_DIGIT) {
5437 return NEIGHBOR_WRAPPED;
5441 enc_succ_char(carry,
len, enc);
5442 return NEIGHBOR_WRAPPED;
5460 str =
rb_str_new(RSTRING_PTR(orig), RSTRING_LEN(orig));
5461 rb_enc_cr_str_copy_for_substr(str, orig);
5462 return str_succ(str);
5469 char *sbeg, *s, *e, *last_alnum = 0;
5470 int found_alnum = 0;
5472 char carry[ONIGENC_CODE_TO_MBC_MAXLEN] =
"\1";
5473 long carry_pos = 0, carry_len = 1;
5474 enum neighbor_char neighbor = NEIGHBOR_FOUND;
5476 slen = RSTRING_LEN(str);
5477 if (slen == 0)
return str;
5479 enc = STR_ENC_GET(str);
5480 sbeg = RSTRING_PTR(str);
5481 s = e = sbeg + slen;
5483 while ((s = rb_enc_prev_char(sbeg, s, e, enc)) != 0) {
5484 if (neighbor == NEIGHBOR_NOT_CHAR && last_alnum) {
5490 l = rb_enc_precise_mbclen(s, e, enc);
5491 if (!ONIGENC_MBCLEN_CHARFOUND_P(l))
continue;
5492 l = ONIGENC_MBCLEN_CHARFOUND_LEN(l);
5493 neighbor = enc_succ_alnum_char(s, l, enc, carry);
5495 case NEIGHBOR_NOT_CHAR:
5497 case NEIGHBOR_FOUND:
5499 case NEIGHBOR_WRAPPED:
5504 carry_pos = s - sbeg;
5509 while ((s = rb_enc_prev_char(sbeg, s, e, enc)) != 0) {
5510 enum neighbor_char neighbor;
5511 char tmp[ONIGENC_CODE_TO_MBC_MAXLEN];
5512 l = rb_enc_precise_mbclen(s, e, enc);
5513 if (!ONIGENC_MBCLEN_CHARFOUND_P(l))
continue;
5514 l = ONIGENC_MBCLEN_CHARFOUND_LEN(l);
5516 neighbor = enc_succ_char(tmp, l, enc);
5518 case NEIGHBOR_FOUND:
5522 case NEIGHBOR_WRAPPED:
5525 case NEIGHBOR_NOT_CHAR:
5528 if (rb_enc_precise_mbclen(s, s+l, enc) != l) {
5530 enc_succ_char(s, l, enc);
5532 if (!rb_enc_asciicompat(enc)) {
5533 MEMCPY(carry, s,
char, l);
5536 carry_pos = s - sbeg;
5540 RESIZE_CAPA(str, slen + carry_len);
5541 sbeg = RSTRING_PTR(str);
5542 s = sbeg + carry_pos;
5543 memmove(s + carry_len, s, slen - carry_pos);
5544 memmove(s, carry, carry_len);
5546 STR_SET_LEN(str, slen);
5547 TERM_FILL(&sbeg[slen], rb_enc_mbminlen(enc));
5548 rb_enc_str_coderange(str);
5563rb_str_succ_bang(
VALUE str)
5571all_digits_p(
const char *s,
long len)
5599 VALUE end, exclusive;
5603 return rb_str_upto_each(beg, end,
RTEST(exclusive), str_upto_i,
Qnil);
5609 VALUE current, after_end;
5616 enc = rb_enc_check(beg, end);
5617 ascii = (is_ascii_string(beg) && is_ascii_string(end));
5619 if (RSTRING_LEN(beg) == 1 && RSTRING_LEN(end) == 1 && ascii) {
5620 char c = RSTRING_PTR(beg)[0];
5621 char e = RSTRING_PTR(end)[0];
5623 if (c > e || (excl && c == e))
return beg;
5625 VALUE str = rb_enc_str_new(&c, 1, enc);
5627 if ((*each)(str, arg))
break;
5628 if (!excl && c == e)
break;
5630 if (excl && c == e)
break;
5635 if (ascii &&
ISDIGIT(RSTRING_PTR(beg)[0]) &&
ISDIGIT(RSTRING_PTR(end)[0]) &&
5636 all_digits_p(RSTRING_PTR(beg), RSTRING_LEN(beg)) &&
5637 all_digits_p(RSTRING_PTR(end), RSTRING_LEN(end))) {
5642 b = rb_str_to_inum(beg, 10, FALSE);
5643 e = rb_str_to_inum(end, 10, FALSE);
5650 if (excl && bi == ei)
break;
5651 if ((*each)(
rb_enc_sprintf(usascii,
"%.*ld", width, bi), arg))
break;
5656 ID op = excl ?
'<' : idLE;
5657 VALUE args[2], fmt = rb_fstring_lit(
"%.*d");
5662 if ((*each)(
rb_str_format(numberof(args), args, fmt), arg))
break;
5670 if (n > 0 || (excl && n == 0))
return beg;
5678 if ((*each)(current, arg))
break;
5679 if (
NIL_P(next))
break;
5683 if (RSTRING_LEN(current) > RSTRING_LEN(end) || RSTRING_LEN(current) == 0)
5698 if (is_ascii_string(beg) &&
ISDIGIT(RSTRING_PTR(beg)[0]) &&
5699 all_digits_p(RSTRING_PTR(beg), RSTRING_LEN(beg))) {
5700 VALUE b, args[2], fmt = rb_fstring_lit(
"%.*d");
5702 b = rb_str_to_inum(beg, 10, FALSE);
5708 if ((*each)(
rb_enc_sprintf(usascii,
"%.*ld", width, bi), arg))
break;
5716 if ((*each)(
rb_str_format(numberof(args), args, fmt), arg))
break;
5724 if ((*each)(current, arg))
break;
5727 if (RSTRING_LEN(current) == 0)
5738 if (!
rb_equal(str, *argp))
return 0;
5752 if (rb_enc_asciicompat(STR_ENC_GET(beg)) &&
5753 rb_enc_asciicompat(STR_ENC_GET(end)) &&
5754 rb_enc_asciicompat(STR_ENC_GET(val))) {
5755 const char *bp = RSTRING_PTR(beg);
5756 const char *ep = RSTRING_PTR(end);
5757 const char *vp = RSTRING_PTR(val);
5758 if (RSTRING_LEN(beg) == 1 && RSTRING_LEN(end) == 1) {
5759 if (RSTRING_LEN(val) == 0 || RSTRING_LEN(val) > 1)
5767 if (b <= v && v < e)
return Qtrue;
5768 return RBOOL(!
RTEST(exclusive) && v == e);
5775 all_digits_p(bp, RSTRING_LEN(beg)) &&
5776 all_digits_p(ep, RSTRING_LEN(end))) {
5781 rb_str_upto_each(beg, end,
RTEST(exclusive), include_range_i, (
VALUE)&val);
5783 return RBOOL(
NIL_P(val));
5806 return rb_str_subpat(str, indx,
INT2FIX(0));
5809 if (rb_str_index(str, indx, 0) != -1)
5815 long beg,
len = str_strlen(str, NULL);
5827 return str_substr(str, idx, 1, FALSE);
5844rb_str_aref_m(
int argc,
VALUE *argv,
VALUE str)
5848 return rb_str_subpat(str, argv[0], argv[1]);
5851 return rb_str_substr_two_fixnums(str, argv[0], argv[1], TRUE);
5855 return rb_str_aref(str, argv[0]);
5861 char *
ptr = RSTRING_PTR(str);
5862 long olen = RSTRING_LEN(str), nlen;
5864 str_modifiable(str);
5865 if (
len > olen)
len = olen;
5867 if (str_embed_capa(str) >= nlen + TERM_LEN(str)) {
5869 size_t old_capa =
RSTRING(str)->as.heap.aux.capa + TERM_LEN(str);
5870 int fl = (int)(
RBASIC(str)->flags & (STR_NOEMBED|STR_SHARED|STR_NOFREE));
5873 memmove(
ptr, oldptr +
len, nlen);
5874 if (fl == STR_NOEMBED) {
5875 SIZED_FREE_N(oldptr, old_capa);
5879 if (!STR_SHARED_P(str)) {
5881 rb_enc_cr_str_exact_copy(
shared, str);
5886 STR_SET_LEN(str, nlen);
5888 if (!SHARABLE_MIDDLE_SUBSTRING) {
5889 TERM_FILL(
ptr + nlen, TERM_LEN(str));
5896rb_str_update_1(
VALUE str,
long beg,
long len,
VALUE val,
long vbeg,
long vlen)
5902 if (beg == 0 && vlen == 0) {
5907 str_modify_keep_cr(str);
5911 RESIZE_CAPA(str, slen + vlen -
len);
5912 sptr = RSTRING_PTR(str);
5916 cr = rb_enc_str_coderange(val);
5921 memmove(sptr + beg + vlen,
5923 slen - (beg +
len));
5925 if (vlen < beg &&
len < 0) {
5929 memmove(sptr + beg, RSTRING_PTR(val) + vbeg, vlen);
5932 STR_SET_LEN(str, slen);
5933 TERM_FILL(&sptr[slen], TERM_LEN(str));
5940 rb_str_update_1(str, beg,
len, val, 0, RSTRING_LEN(val));
5949 int singlebyte = single_byte_optimizable(str);
5955 enc = rb_enc_check(str, val);
5956 slen = str_strlen(str, enc);
5958 if ((slen < beg) || ((beg < 0) && (beg + slen < 0))) {
5967 if (
len > slen - beg) {
5970 p = str_nth(RSTRING_PTR(str),
RSTRING_END(str), beg, enc, singlebyte);
5975 beg = p - RSTRING_PTR(str);
5977 rb_str_update_0(str, beg,
len, val);
5978 rb_enc_associate(str, enc);
5989 long start, end,
len;
5997 int num_regs = RMATCH_NREGS(match);
5998 if ((nth >= num_regs) || ((nth < 0) && (-nth >= num_regs))) {
6005 start = RMATCH_BEG(match, nth);
6009 end = RMATCH_END(match, nth);
6013 if (start +
len > RSTRING_LEN(str)) {
6017 enc = rb_enc_check_str(str, val);
6018 rb_str_update_0(str, start,
len, val);
6019 rb_enc_associate(str, enc);
6027 switch (
TYPE(indx)) {
6029 rb_str_subpat_set(str, indx,
INT2FIX(0), val);
6033 beg = rb_str_index(str, indx, 0);
6072rb_str_aset_m(
int argc,
VALUE *argv,
VALUE str)
6076 rb_str_subpat_set(str, argv[0], argv[1], argv[2]);
6084 return rb_str_aset(str, argv[0], argv[1]);
6136rb_str_slice_bang(
int argc,
VALUE *argv,
VALUE str)
6144 str_modify_keep_cr(str);
6149 int num_regs = RMATCH_NREGS(match);
6152 if ((nth += num_regs) <= 0)
return Qnil;
6154 else if (nth >= num_regs)
return Qnil;
6155 beg = RMATCH_BEG(match, nth);
6156 len = RMATCH_END(match, nth) - beg;
6158 if (beg > RSTRING_LEN(str))
return Qnil;
6159 if (
len > RSTRING_LEN(str) - beg)
len = RSTRING_LEN(str) - beg;
6162 else if (argc == 2) {
6171 beg = p - RSTRING_PTR(str);
6175 beg = rb_str_index(str, indx, 0);
6176 if (beg == -1)
return Qnil;
6177 len = RSTRING_LEN(indx);
6189 beg = p - RSTRING_PTR(str);
6198 beg = p - RSTRING_PTR(str);
6202 rb_enc_cr_str_copy_for_substr(result, str);
6210 char *sptr = RSTRING_PTR(str);
6211 long slen = RSTRING_LEN(str);
6212 if (beg +
len > slen)
6216 slen - (beg +
len));
6218 STR_SET_LEN(str, slen);
6219 TERM_FILL(&sptr[slen], TERM_LEN(str));
6230 switch (OBJ_BUILTIN_TYPE(pat)) {
6249get_pat_quoted(
VALUE pat,
int check)
6253 switch (OBJ_BUILTIN_TYPE(pat)) {
6267 if (check && is_broken_string(pat)) {
6274rb_pat_search0(
VALUE pat,
VALUE str,
long pos,
int set_backref_str,
VALUE *match)
6277 pos = rb_str_byteindex(str, pat, pos);
6278 if (set_backref_str) {
6280 str = rb_str_new_frozen_String(str);
6281 VALUE match_data = rb_backref_set_string(str, pos, RSTRING_LEN(pat));
6283 *match = match_data;
6293 return rb_reg_search0(pat, str, pos, 0, set_backref_str, match);
6298rb_pat_search(
VALUE pat,
VALUE str,
long pos,
int set_backref_str)
6300 return rb_pat_search0(pat, str, pos, set_backref_str, NULL);
6318rb_str_sub_bang(
int argc,
VALUE *argv,
VALUE str)
6333 hash = rb_check_hash_type(repl);
6340 pat = get_pat_quoted(argv[0], 1);
6342 str_modifiable(str);
6343 beg = rb_pat_search(pat, str, 0, 1);
6355 end0 = beg0 + RSTRING_LEN(pat);
6359 beg0 = RMATCH_BEG(match, 0);
6360 end0 = RMATCH_END(match, 0);
6364 if (iter || !
NIL_P(hash)) {
6365 p = RSTRING_PTR(str);
len = RSTRING_LEN(str);
6371 repl = rb_hash_aref(hash,
rb_str_subseq(str, beg0, end0 - beg0));
6374 str_mod_check(str, p,
len);
6375 rb_check_frozen(str);
6378 repl = rb_reg_regsub_match(repl, str, match);
6381 enc = rb_enc_compatible(str, repl);
6384 p = RSTRING_PTR(str);
len = RSTRING_LEN(str);
6388 rb_enc_inspect_name(str_enc),
6389 rb_enc_inspect_name(STR_ENC_GET(repl)));
6391 enc = STR_ENC_GET(repl);
6394 rb_enc_associate(str, enc);
6404 rlen = RSTRING_LEN(repl);
6405 len = RSTRING_LEN(str);
6407 RESIZE_CAPA(str,
len + rlen - plen);
6409 p = RSTRING_PTR(str);
6411 memmove(p + beg0 + rlen, p + beg0 + plen,
len - beg0 - plen);
6413 rp = RSTRING_PTR(repl);
6414 memmove(p + beg0, rp, rlen);
6416 STR_SET_LEN(str,
len);
6417 TERM_FILL(&RSTRING_PTR(str)[
len], TERM_LEN(str));
6440 rb_str_sub_bang(argc, argv, str);
6445str_gsub(
int argc,
VALUE *argv,
VALUE str,
int bang)
6448 long beg, beg0, end0;
6449 long offset, blen, slen,
len, last;
6450 enum {STR, ITER, FAST_MAP, MAP} mode = STR;
6452 int need_backref_str = -1;
6463 hash = rb_check_hash_type(repl);
6467 else if (rb_hash_default_unredefined(hash) && !
FL_TEST_RAW(hash, RHASH_PROC_DEFAULT)) {
6476 rb_error_arity(argc, 1, 2);
6479 pat = get_pat_quoted(argv[0], 1);
6480 beg = rb_pat_search0(pat, str, 0, need_backref_str, &match);
6483 if (bang)
return Qnil;
6486 if (bang) str_modify_keep_cr(str);
6489 blen = RSTRING_LEN(str) + 30;
6491 sp = RSTRING_PTR(str);
6492 slen = RSTRING_LEN(str);
6494 str_enc = STR_ENC_GET(str);
6495 rb_enc_associate(dest, str_enc);
6501 end0 = beg0 + RSTRING_LEN(pat);
6505 beg0 = RMATCH_BEG(match, 0);
6506 end0 = RMATCH_END(match, 0);
6515 struct RString fake_str = {RBASIC_INIT};
6517 if (mode == FAST_MAP) {
6526 val = rb_hash_aref(hash, key);
6529 str_mod_check(str, sp, slen);
6534 else if (need_backref_str) {
6535 val = rb_reg_regsub_match(repl, str, match);
6536 if (need_backref_str < 0) {
6537 need_backref_str = val != repl;
6544 len = beg0 - offset;
6558 if (RSTRING_LEN(str) <= end0)
break;
6559 len = rb_enc_fast_mbclen(RSTRING_PTR(str)+end0,
RSTRING_END(str), str_enc);
6561 offset = end0 +
len;
6563 cp = RSTRING_PTR(str) + offset;
6564 if (offset > RSTRING_LEN(str))
break;
6567 if (mode != FAST_MAP && mode != STR) {
6570 beg = rb_pat_search0(pat, str, offset, need_backref_str, &match);
6575 if (RSTRING_LEN(str) > offset) {
6578 rb_pat_search0(pat, str, last, 1, &match);
6580 str_shared_replace(str, dest);
6605rb_str_gsub_bang(
int argc,
VALUE *argv,
VALUE str)
6607 str_modifiable(str);
6608 return str_gsub(argc, argv, str, 1);
6658 return str_gsub(argc, argv, str, 0);
6678 str_modifiable(str);
6679 if (str == str2)
return str;
6683 return str_replace(str, str2);
6700rb_str_clear(
VALUE str)
6704 STR_SET_LEN(str, 0);
6705 RSTRING_PTR(str)[0] = 0;
6706 if (rb_enc_asciicompat(STR_ENC_GET(str)))
6722rb_str_chr(
VALUE str)
6740 pos += RSTRING_LEN(str);
6741 if (pos < 0 || RSTRING_LEN(str) <= pos)
6744 return INT2FIX((
unsigned char)RSTRING_PTR(str)[pos]);
6764 char *
ptr, *head, *left = 0;
6770 char byte = (char)(
NUM2INT(w) & 0xFF);
6772 long len = RSTRING_LEN(str);
6773 if (pos < -
len ||
len <= pos)
6778 if (!str_independent(str))
6779 str_make_independent(str);
6780 enc = STR_ENC_GET(str);
6781 head = RSTRING_PTR(str);
6783 if (!STR_EMBED_P(str)) {
6790 nlen = rb_enc_precise_mbclen(left, head+
len, enc);
6798 width = rb_enc_precise_mbclen(left, head+
len, enc);
6800 nlen = rb_enc_precise_mbclen(left, head+
len, enc);
6816str_bit_offset_out_of_range(
long byte_len, uint64_t bit_offset)
6819 return bit_offset / CHAR_BIT >= (uint64_t)byte_len;
6835str_bit_offset_from_index(
VALUE index)
6847 offset.long_value =
FIX2LONG(integer);
6848 if (offset.long_value < 0) {
6851 offset.value = (uint64_t)offset.long_value;
6852 offset.fits_long =
true;
6857 if (rb_int_negative_p(integer)) {
6860 if (rb_cmpint(rb_int_cmp(integer,
ULL2NUM(UINT64_MAX)), integer,
ULL2NUM(UINT64_MAX)) > 0) {
6861 rb_raise(rb_eArgError,
"bit index out of representable range");
6864 offset.value = (uint64_t)
NUM2ULL(integer);
6865 if (offset.value <= (uint64_t)LONG_MAX) {
6866 offset.long_value = (long)offset.value;
6867 offset.fits_long =
true;
6870 offset.long_value = 0;
6871 offset.fits_long =
false;
6881str_bit_length_from_index(
VALUE index)
6888 rb_raise(rb_eArgError,
"negative bit length");
6890 return (uint64_t)value;
6894 if (rb_int_negative_p(integer)) {
6895 rb_raise(rb_eArgError,
"negative bit length");
6897 if (rb_cmpint(rb_int_cmp(integer,
ULL2NUM(UINT64_MAX)), integer,
ULL2NUM(UINT64_MAX)) > 0) {
6898 rb_raise(rb_eArgError,
"bit length out of representable range");
6900 return (uint64_t)
NUM2ULL(integer);
6903static inline uint64_t
6904str_bit_size(
long byte_len)
6910 if ((uint64_t)byte_len > UINT64_MAX / CHAR_BIT)
return UINT64_MAX;
6911 return (uint64_t)byte_len * CHAR_BIT;
6916 uint64_t end_exclusive;
6939 out->beg =
NIL_P(beg_v) ? 0 : str_bit_offset_from_index(beg_v).value;
6941 out->end_open =
true;
6942 out->end_exclusive = 0;
6945 uint64_t end = str_bit_offset_from_index(end_v).value;
6946 out->end_open =
false;
6951 out->end_exclusive = (excl || end == UINT64_MAX) ? end : end + 1;
6961str_bit_range_resolve(
const struct str_bit_range *range, uint64_t total_bits, uint64_t *begp, uint64_t *lenp)
6963 uint64_t beg = range->beg;
6964 if (beg > total_bits)
return false;
6966 uint64_t end_exclusive = range->end_open ? total_bits : range->end_exclusive;
6967 if (end_exclusive < beg) end_exclusive = beg;
6970 *lenp = end_exclusive - beg;
6975str_lsb_first_from_opts(
VALUE opts)
6977 static ID keywords[1];
6985 if (vlsb_first ==
Qundef || vlsb_first ==
Qtrue) {
6988 if (vlsb_first ==
Qfalse) {
6991 rb_raise(rb_eArgError,
"lsb_first must be true or false");
6996str_lsb_first(
int argc,
VALUE *argv,
VALUE *index)
7001 return str_lsb_first_from_opts(opts);
7004static inline uint64_t
7005str_logical_to_physical_bit64(uint64_t logical,
bool lsb_first)
7007 return lsb_first ? logical : ((logical & ~(uint64_t)7) | (7 - (logical & 7)));
7011str_logical_to_physical_bit(
long logical,
bool lsb_first)
7013 return lsb_first ? logical : ((logical & ~7L) | (7 - (logical & 7L)));
7018 unsigned int bit_offset;
7022str_bit_location_from_offset(uint64_t logical, bool lsb_first)
7028 uint64_t physical = str_logical_to_physical_bit64(logical, lsb_first);
7030 location.byte_index = (long)(physical / CHAR_BIT);
7031 location.bit_offset = (
unsigned int)(physical % CHAR_BIT);
7036str_get_bit(
const char *ptr,
long bit_index)
7038 return (((
unsigned char)ptr[bit_index / CHAR_BIT]) >> (bit_index % CHAR_BIT)) & 1;
7044 return (((
unsigned char)ptr[location.byte_index]) >> location.bit_offset) & 1;
7051 bool lsb_first = str_lsb_first(argc, argv, &index);
7054 if (str_bit_offset_out_of_range(RSTRING_LEN(str), offset.value)) {
7058 if (offset.fits_long) {
7059 return str_get_bit(RSTRING_PTR(str), str_logical_to_physical_bit(offset.long_value, lsb_first));
7062 return str_get_bit_location(RSTRING_PTR(str), str_bit_location_from_offset(offset.value, lsb_first));
7074rb_str_bit_get(
int argc,
VALUE *argv,
VALUE str)
7076 int bit = str_bit_get(argc, argv, str);
7088rb_str_bit_set_p(
int argc,
VALUE *argv,
VALUE str)
7090 int bit = str_bit_get(argc, argv, str);
7091 return bit < 0 ?
Qnil : RBOOL(bit);
7094enum str_bit_mutation {
7105static inline unsigned char
7106str_bit_region_byte_mask(
unsigned int lo,
unsigned int hi,
bool lsb_first)
7109 return (
unsigned char)((0xFFu >> (7 - hi)) & (0xFFu << lo));
7112 return (
unsigned char)((0xFFu >> lo) & (0xFFu << (7 - hi)));
7117str_apply_bit_mask(
unsigned char *
byte,
unsigned char mask,
enum str_bit_mutation mutation)
7124 *
byte &= (
unsigned char)~mask;
7134str_mutate_bit_region(
unsigned char *ptr, uint64_t beg, uint64_t
len,
bool lsb_first,
enum str_bit_mutation mutation)
7136 uint64_t first_bit = beg;
7137 uint64_t last_bit = beg +
len - 1;
7138 long first_byte = (long)(first_bit / CHAR_BIT);
7139 long last_byte = (long)(last_bit / CHAR_BIT);
7140 unsigned int first_off = (
unsigned int)(first_bit % CHAR_BIT);
7141 unsigned int last_off = (
unsigned int)(last_bit % CHAR_BIT);
7143 if (first_byte == last_byte) {
7144 str_apply_bit_mask(ptr + first_byte, str_bit_region_byte_mask(first_off, last_off, lsb_first), mutation);
7148 str_apply_bit_mask(ptr + first_byte, str_bit_region_byte_mask(first_off, 7, lsb_first), mutation);
7149 long middle_len = last_byte - first_byte - 1;
7150 if (middle_len > 0) {
7151 unsigned char *middle = ptr + first_byte + 1;
7154 memset(middle, 0xFF, middle_len);
7157 memset(middle, 0, middle_len);
7165 for (
long i = 0; i < middle_len; i++) {
7171 str_apply_bit_mask(ptr + last_byte, str_bit_region_byte_mask(0, last_off, lsb_first), mutation);
7175str_mutate_single_bit(
VALUE str,
VALUE index,
bool lsb_first,
enum str_bit_mutation mutation)
7183 rb_check_frozen(str);
7185 if (str_bit_offset_out_of_range(RSTRING_LEN(str), offset.value)) {
7190 ptr = (
unsigned char *)RSTRING_PTR(str);
7191 if (offset.fits_long) {
7192 bit_index = str_logical_to_physical_bit(offset.long_value, lsb_first);
7193 mask = (
unsigned char)(1u << (bit_index % CHAR_BIT));
7194 location.byte_index = bit_index / CHAR_BIT;
7197 location = str_bit_location_from_offset(offset.value, lsb_first);
7198 mask = (
unsigned char)(1u << location.bit_offset);
7201 str_apply_bit_mask(ptr + location.byte_index, mask, mutation);
7206str_mutate_bit(
int argc,
VALUE *argv,
VALUE str,
enum str_bit_mutation mutation)
7208 VALUE target, length_v, opts;
7209 uint64_t beg = 0,
len = 0;
7212 int nargs =
rb_scan_args(argc, argv,
"11:", &target, &length_v, &opts);
7213 bool lsb_first = str_lsb_first_from_opts(opts);
7216 if (nargs == 1 && !is_range) {
7217 return str_mutate_single_bit(str, target, lsb_first, mutation);
7224 rb_raise(rb_eArgError,
"bit length not allowed with a Range");
7226 str_bit_range_to_offsets(target, &range);
7229 offset = str_bit_offset_from_index(target);
7230 len = str_bit_length_from_index(length_v);
7234 rb_check_frozen(str);
7242 uint64_t total_bits = str_bit_size(RSTRING_LEN(str));
7244 if (!str_bit_range_resolve(&range, total_bits, &beg, &
len) ||
len > total_bits - beg) {
7250 if (beg > total_bits ||
len > total_bits - beg) {
7255 if (
len == 0)
return str;
7258 str_mutate_bit_region((
unsigned char *)RSTRING_PTR(str), beg,
len, lsb_first, mutation);
7272rb_str_bit_set(
int argc,
VALUE *argv,
VALUE str)
7274 return str_mutate_bit(argc, argv, str, STR_BIT_SET);
7287rb_str_bit_clear(
int argc,
VALUE *argv,
VALUE str)
7289 return str_mutate_bit(argc, argv, str, STR_BIT_CLEAR);
7302rb_str_bit_flip(
int argc,
VALUE *argv,
VALUE str)
7304 return str_mutate_bit(argc, argv, str, STR_BIT_FLIP);
7308str_count_bits(
const unsigned char *ptr,
long len)
7312 long unrolled_end =
len & ~31L;
7313 long aligned_end =
len & ~7L;
7316 for (;
off < unrolled_end;
off += 32) {
7317 uint64_t w0, w1, w2, w3;
7318 memcpy(&w0, ptr +
off, 8);
7319 memcpy(&w1, ptr +
off + 8, 8);
7320 memcpy(&w2, ptr +
off + 16, 8);
7321 memcpy(&w3, ptr +
off + 24, 8);
7322 count += rb_popcount64(w0);
7323 count += rb_popcount64(w1);
7324 count += rb_popcount64(w2);
7325 count += rb_popcount64(w3);
7329 for (;
off < aligned_end;
off += 8) {
7331 memcpy(&word, ptr +
off, 8);
7332 count += rb_popcount64(word);
7339 for (;
off <
len;
off++, shift += CHAR_BIT) {
7340 word |= (uint64_t)ptr[
off] << shift;
7342 count += rb_popcount64(word);
7349str_count_bits_region(
const unsigned char *ptr, uint64_t beg, uint64_t
len,
bool lsb_first)
7351 uint64_t first_bit = beg;
7352 uint64_t last_bit = beg +
len - 1;
7353 long first_byte = (long)(first_bit / CHAR_BIT);
7354 long last_byte = (long)(last_bit / CHAR_BIT);
7355 unsigned int first_off = (
unsigned int)(first_bit % CHAR_BIT);
7356 unsigned int last_off = (
unsigned int)(last_bit % CHAR_BIT);
7358 if (first_byte == last_byte) {
7359 return rb_popcount32((uint32_t)(ptr[first_byte] & str_bit_region_byte_mask(first_off, last_off, lsb_first)));
7362 uint64_t count = rb_popcount32((uint32_t)(ptr[first_byte] & str_bit_region_byte_mask(first_off, 7, lsb_first)));
7363 count += str_count_bits(ptr + first_byte + 1, last_byte - first_byte - 1);
7364 count += rb_popcount32((uint32_t)(ptr[last_byte] & str_bit_region_byte_mask(0, last_off, lsb_first)));
7378rb_str_bit_count(
int argc,
VALUE *argv,
VALUE str)
7381 uint64_t beg = 0,
len = 0;
7384 int nargs =
rb_scan_args(argc, argv,
"02:", &v0, &v1, &opts);
7389 bool lsb_first = str_lsb_first_from_opts(opts);
7392 return ULL2NUM(str_count_bits((
const unsigned char *)RSTRING_PTR(str), RSTRING_LEN(str)));
7399 rb_raise(rb_eArgError,
"bit length not allowed with a Range");
7401 str_bit_range_to_offsets(v0, &range);
7403 else if (nargs == 1) {
7404 rb_raise(rb_eArgError,
"no bit length given");
7407 beg = str_bit_offset_from_index(v0).value;
7408 len = str_bit_length_from_index(v1);
7411 const unsigned char *ptr = (
const unsigned char *)RSTRING_PTR(str);
7412 uint64_t total_bits = str_bit_size(RSTRING_LEN(str));
7414 if (!str_bit_range_resolve(&range, total_bits, &beg, &
len)) {
7418 else if (beg >= total_bits) {
7423 if (
len > total_bits - beg)
len = total_bits - beg;
7425 return ULL2NUM(str_count_bits_region(ptr, beg,
len, lsb_first));
7429str_check_bitwise_length(
VALUE str,
VALUE other)
7431 if (RSTRING_LEN(str) != RSTRING_LEN(other)) {
7432 rb_raise(rb_eArgError,
"operands must have the same length (%ld vs %ld)",
7433 RSTRING_LEN(str), RSTRING_LEN(other));
7438str_bitwise_result(
VALUE str)
7440 long len = RSTRING_LEN(str);
7442 rb_str_resize(result,
len);
7443 rb_enc_associate(result, rb_ascii8bit_encoding());
7448#define STR_DEFINE_UNARY_BITWISE_KERNEL(name, expr_word, expr_byte) \
7450 name(unsigned char *dst, const unsigned char *src, long len) \
7453 long unrolled_end = len & ~31L; \
7454 long aligned_end = len & ~7L; \
7455 for (; off < unrolled_end; off += 32) { \
7456 uint64_t s0, s1, s2, s3; \
7457 memcpy(&s0, src + off, 8); \
7458 memcpy(&s1, src + off + 8, 8); \
7459 memcpy(&s2, src + off + 16, 8); \
7460 memcpy(&s3, src + off + 24, 8); \
7461 s0 = (expr_word(s0)); \
7462 s1 = (expr_word(s1)); \
7463 s2 = (expr_word(s2)); \
7464 s3 = (expr_word(s3)); \
7465 memcpy(dst + off, &s0, 8); \
7466 memcpy(dst + off + 8, &s1, 8); \
7467 memcpy(dst + off + 16, &s2, 8); \
7468 memcpy(dst + off + 24, &s3, 8); \
7470 for (; off < aligned_end; off += 8) { \
7472 memcpy(&word, src + off, 8); \
7473 word = (expr_word(word)); \
7474 memcpy(dst + off, &word, 8); \
7476 for (; off < len; off++) dst[off] = (expr_byte(src[off])); \
7479#define STR_DEFINE_BINARY_BITWISE_KERNEL(name, expr_word, expr_byte) \
7481 name(unsigned char *dst, const unsigned char *lhs, \
7482 const unsigned char *rhs, long len) \
7485 long unrolled_end = len & ~31L; \
7486 long aligned_end = len & ~7L; \
7487 for (; off < unrolled_end; off += 32) { \
7488 uint64_t l0, l1, l2, l3, r0, r1, r2, r3; \
7489 memcpy(&l0, lhs + off, 8); memcpy(&r0, rhs + off, 8); \
7490 memcpy(&l1, lhs + off + 8, 8); memcpy(&r1, rhs + off + 8, 8); \
7491 memcpy(&l2, lhs + off + 16, 8); memcpy(&r2, rhs + off + 16, 8); \
7492 memcpy(&l3, lhs + off + 24, 8); memcpy(&r3, rhs + off + 24, 8); \
7493 l0 = expr_word(l0, r0); \
7494 l1 = expr_word(l1, r1); \
7495 l2 = expr_word(l2, r2); \
7496 l3 = expr_word(l3, r3); \
7497 memcpy(dst + off, &l0, 8); \
7498 memcpy(dst + off + 8, &l1, 8); \
7499 memcpy(dst + off + 16, &l2, 8); \
7500 memcpy(dst + off + 24, &l3, 8); \
7502 for (; off < aligned_end; off += 8) { \
7503 uint64_t lhs_word, rhs_word; \
7504 memcpy(&lhs_word, lhs + off, 8); \
7505 memcpy(&rhs_word, rhs + off, 8); \
7506 lhs_word = expr_word(lhs_word, rhs_word); \
7507 memcpy(dst + off, &lhs_word, 8); \
7509 for (; off < len; off++) dst[off] = expr_byte(lhs[off], rhs[off]); \
7512#define STR_BITWISE_NOT_WORD(x) (~(x))
7513#define STR_BITWISE_NOT_BYTE(x) ((unsigned char)~(x))
7514#define STR_BITWISE_AND_WORD(x, y) ((x) & (y))
7515#define STR_BITWISE_AND_BYTE(x, y) ((unsigned char)((x) & (y)))
7516#define STR_BITWISE_OR_WORD(x, y) ((x) | (y))
7517#define STR_BITWISE_OR_BYTE(x, y) ((unsigned char)((x) | (y)))
7518#define STR_BITWISE_XOR_WORD(x, y) ((x) ^ (y))
7519#define STR_BITWISE_XOR_BYTE(x, y) ((unsigned char)((x) ^ (y)))
7521STR_DEFINE_UNARY_BITWISE_KERNEL(str_bitwise_not, STR_BITWISE_NOT_WORD, STR_BITWISE_NOT_BYTE)
7522STR_DEFINE_BINARY_BITWISE_KERNEL(str_bitwise_and, STR_BITWISE_AND_WORD, STR_BITWISE_AND_BYTE)
7523STR_DEFINE_BINARY_BITWISE_KERNEL(str_bitwise_or, STR_BITWISE_OR_WORD, STR_BITWISE_OR_BYTE)
7524STR_DEFINE_BINARY_BITWISE_KERNEL(str_bitwise_xor, STR_BITWISE_XOR_WORD, STR_BITWISE_XOR_BYTE)
7534rb_str_bitwise_not(
VALUE str)
7536 long len = RSTRING_LEN(str);
7537 VALUE result = str_bitwise_result(str);
7538 str_bitwise_not((
unsigned char *)RSTRING_PTR(result),
7539 (
const unsigned char *)RSTRING_PTR(str),
len);
7551rb_str_bitwise_not_bang(
VALUE str)
7557 len = RSTRING_LEN(str);
7558 ptr = (
unsigned char *)RSTRING_PTR(str);
7559 str_bitwise_not(ptr, ptr,
len);
7563#define STR_DEFINE_BINARY_BITWISE_METHOD(name) \
7565 rb_str_bitwise_##name(VALUE str, VALUE other) \
7569 StringValue(other); \
7570 str_check_bitwise_length(str, other); \
7571 len = RSTRING_LEN(str); \
7572 result = str_bitwise_result(str); \
7573 str_bitwise_##name((unsigned char *)RSTRING_PTR(result), \
7574 (const unsigned char *)RSTRING_PTR(str), \
7575 (const unsigned char *)RSTRING_PTR(other), len); \
7579 rb_str_bitwise_##name##_bang(VALUE str, VALUE other) \
7582 unsigned char *ptr; \
7583 StringValue(other); \
7584 str_check_bitwise_length(str, other); \
7585 rb_str_modify(str); \
7586 len = RSTRING_LEN(str); \
7587 ptr = (unsigned char *)RSTRING_PTR(str); \
7588 str_bitwise_##name(ptr, ptr, \
7589 (const unsigned char *)RSTRING_PTR(other), len); \
7593STR_DEFINE_BINARY_BITWISE_METHOD(and)
7594STR_DEFINE_BINARY_BITWISE_METHOD(or)
7595STR_DEFINE_BINARY_BITWISE_METHOD(xor)
7598str_byte_substr(
VALUE str,
long beg,
long len,
int empty)
7600 long n = RSTRING_LEN(str);
7602 if (beg > n ||
len < 0)
return Qnil;
7605 if (beg < 0)
return Qnil;
7610 if (!empty)
return Qnil;
7614 VALUE str2 = str_subseq(str, beg,
len);
7616 str_enc_copy_direct(str2, str);
7618 if (RSTRING_LEN(str2) == 0) {
7619 if (!rb_enc_asciicompat(STR_ENC_GET(str)))
7653 long beg,
len = RSTRING_LEN(str);
7661 return str_byte_substr(str, beg,
len, TRUE);
7666 return str_byte_substr(str, idx, 1, FALSE);
7678rb_str_byteslice(
int argc,
VALUE *argv,
VALUE str)
7683 return str_byte_substr(str, beg,
len, TRUE);
7686 return str_byte_aref(str, argv[0]);
7690str_check_beg_len(
VALUE str,
long *beg,
long *
len)
7692 long end, slen = RSTRING_LEN(str);
7695 if ((slen < *beg) || ((*beg < 0) && (*beg + slen < 0))) {
7704 if (*
len > slen - *beg) {
7708 str_ensure_byte_pos(str, *beg);
7709 str_ensure_byte_pos(str, end);
7723rb_str_bytesplice(
int argc,
VALUE *argv,
VALUE str)
7725 long beg,
len, vbeg, vlen;
7730 if (!(argc == 2 || argc == 3 || argc == 5)) {
7731 rb_raise(rb_eArgError,
"wrong number of arguments (given %d, expected 2, 3, or 5)", argc);
7735 rb_raise(
rb_eTypeError,
"wrong argument type %s (expected Range)",
7736 rb_builtin_class_name(argv[0]));
7743 vlen = RSTRING_LEN(val);
7748 rb_raise(
rb_eTypeError,
"wrong argument type %s (expected Range)",
7749 rb_builtin_class_name(argv[2]));
7761 vlen = RSTRING_LEN(val);
7769 str_check_beg_len(str, &beg, &
len);
7770 str_check_beg_len(val, &vbeg, &vlen);
7771 str_modify_keep_cr(str);
7774 rb_enc_associate(str, rb_enc_check(str, val));
7777 rb_str_update_1(str, beg,
len, val, vbeg, vlen);
7799rb_str_reverse(
VALUE str)
7806 if (RSTRING_LEN(str) <= 1)
return str_duplicate(
rb_cString, str);
7807 enc = STR_ENC_GET(str);
7813 if (RSTRING_LEN(str) > 1) {
7814 if (single_byte_optimizable(str)) {
7821 int clen = rb_enc_fast_mbclen(s, e, enc);
7829 cr = rb_enc_asciicompat(enc) ?
7832 int clen = rb_enc_mbclen(s, e, enc);
7841 STR_SET_LEN(rev, RSTRING_LEN(str));
7842 str_enc_copy_direct(rev, str);
7864rb_str_reverse_bang(
VALUE str)
7866 if (RSTRING_LEN(str) > 1) {
7867 if (single_byte_optimizable(str)) {
7870 str_modify_keep_cr(str);
7871 s = RSTRING_PTR(str);
7880 str_shared_replace(str, rb_str_reverse(str));
7884 str_modify_keep_cr(str);
7913 i = rb_str_index(str, arg, 0);
7915 return RBOOL(i != -1);
7959 rb_raise(rb_eArgError,
"invalid radix %d", base);
7961 return rb_str_to_inum(str, base, FALSE);
7986rb_str_to_f(
VALUE str)
8003rb_str_to_s(
VALUE str)
8015 char s[RUBY_MAX_CHAR_LEN];
8016 int n = rb_enc_codelen(c, enc);
8018 rb_enc_mbcput(c, s, enc);
8023#define CHAR_ESC_LEN 13
8026rb_str_buf_cat_escaped_char(
VALUE result,
unsigned int c,
int unicode_p)
8028 char buf[CHAR_ESC_LEN + 1];
8036 snprintf(buf, CHAR_ESC_LEN,
"%c", c);
8038 else if (c < 0x10000) {
8039 snprintf(buf, CHAR_ESC_LEN,
"\\u%04X", c);
8042 snprintf(buf, CHAR_ESC_LEN,
"\\u{%X}", c);
8047 snprintf(buf, CHAR_ESC_LEN,
"\\x%02X", c);
8050 snprintf(buf, CHAR_ESC_LEN,
"\\x{%X}", c);
8053 l = (int)strlen(buf);
8059ruby_escaped_char(
int c)
8062 case '\0':
return "\\0";
8063 case '\n':
return "\\n";
8064 case '\r':
return "\\r";
8065 case '\t':
return "\\t";
8066 case '\f':
return "\\f";
8067 case '\013':
return "\\v";
8068 case '\010':
return "\\b";
8069 case '\007':
return "\\a";
8070 case '\033':
return "\\e";
8071 case '\x7f':
return "\\c?";
8077rb_str_escape(
VALUE str)
8081 const char *p = RSTRING_PTR(str);
8083 const char *prev = p;
8084 char buf[CHAR_ESC_LEN + 1];
8086 int unicode_p = rb_enc_unicode_p(enc);
8087 int asciicompat = rb_enc_asciicompat(enc);
8092 int n = rb_enc_precise_mbclen(p, pend, enc);
8094 if (p > prev) str_buf_cat(result, prev, p - prev);
8095 n = rb_enc_mbminlen(enc);
8097 n = (int)(pend - p);
8099 snprintf(buf, CHAR_ESC_LEN,
"\\x%02X", *p & 0377);
8100 str_buf_cat(result, buf, strlen(buf));
8106 c = rb_enc_mbc_to_codepoint(p, pend, enc);
8108 cc = ruby_escaped_char(c);
8110 if (p - n > prev) str_buf_cat(result, prev, p - n - prev);
8111 str_buf_cat(result, cc, strlen(cc));
8114 else if (asciicompat && rb_enc_isascii(c, enc) &&
ISPRINT(c)) {
8117 if (p - n > prev) str_buf_cat(result, prev, p - n - prev);
8118 rb_str_buf_cat_escaped_char(result, c, unicode_p);
8122 if (p > prev) str_buf_cat(result, prev, p - prev);
8132static const bool inspect_no_escape[256] = {
8133 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8134 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8135 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
8136 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
8137 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
8138 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1,
8139 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
8140 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,
8156 const char *p, *pend, *prev;
8157 char buf[CHAR_ESC_LEN + 1];
8159 rb_encoding *resenc = rb_default_internal_encoding();
8160 int unicode_p = rb_enc_unicode_p(enc);
8161 int asciicompat = rb_enc_asciicompat(enc);
8162 int cr = rb_enc_str_coderange(str);
8164 if (resenc == NULL) resenc = rb_default_external_encoding();
8165 if (!rb_enc_asciicompat(resenc)) resenc = rb_usascii_encoding();
8166 rb_enc_associate(result, resenc);
8167 str_buf_cat2(result,
"\"");
8180 while (p < pend && inspect_no_escape[(
unsigned char)*p]) p++;
8181 if (p >= pend)
break;
8184 n = rb_enc_precise_mbclen(p, pend, enc);
8186 if (p > prev) str_buf_cat(result, prev, p - prev);
8187 n = rb_enc_mbminlen(enc);
8189 n = (int)(pend - p);
8191 snprintf(buf, CHAR_ESC_LEN,
"\\x%02X", *p & 0377);
8192 str_buf_cat(result, buf, strlen(buf));
8198 c = rb_enc_mbc_to_codepoint(p, pend, enc);
8200 if ((asciicompat || unicode_p) &&
8201 (c ==
'"'|| c ==
'\\' ||
8206 (cc ==
'$' || cc ==
'@' || cc ==
'{'))))) {
8207 if (p - n > prev) str_buf_cat(result, prev, p - n - prev);
8208 str_buf_cat2(result,
"\\");
8209 if (asciicompat || enc == resenc) {
8215 case '\n': cc =
'n';
break;
8216 case '\r': cc =
'r';
break;
8217 case '\t': cc =
't';
break;
8218 case '\f': cc =
'f';
break;
8219 case '\013': cc =
'v';
break;
8220 case '\010': cc =
'b';
break;
8221 case '\007': cc =
'a';
break;
8222 case 033: cc =
'e';
break;
8223 default: cc = 0;
break;
8226 if (p - n > prev) str_buf_cat(result, prev, p - n - prev);
8229 str_buf_cat(result, buf, 2);
8242 (asciicompat && rb_enc_isascii(c, enc) &&
ISPRINT(c))) {
8246 if (p - n > prev) str_buf_cat(result, prev, p - n - prev);
8247 rb_str_buf_cat_escaped_char(result, c, unicode_p);
8252 if (p > prev) str_buf_cat(result, prev, p - prev);
8253 str_buf_cat2(result,
"\"");
8258#define IS_EVSTR(p,e) ((p) < (e) && (*(p) == '$' || *(p) == '@' || *(p) == '{'))
8271 int encidx = rb_enc_get_index(str);
8274 const char *p, *pend;
8277 int u8 = (encidx == rb_utf8_encindex());
8278 static const char nonascii_suffix[] =
".dup.force_encoding(\"%s\")";
8281 if (!rb_enc_asciicompat(enc)) {
8283 len += strlen(enc->name);
8286 p = RSTRING_PTR(str); pend = p + RSTRING_LEN(str);
8289 unsigned char c = *p++;
8292 case '"':
case '\\':
8293 case '\n':
case '\r':
8294 case '\t':
case '\f':
8295 case '\013':
case '\010':
case '\007':
case '\033':
8300 clen = IS_EVSTR(p, pend) ? 2 : 1;
8308 if (u8 && c > 0x7F) {
8309 int n = rb_enc_precise_mbclen(p-1, pend, enc);
8311 unsigned int cc = rb_enc_mbc_to_codepoint(p-1, pend, enc);
8314 else if (cc <= 0xFFFFF)
8327 if (clen > LONG_MAX -
len) {
8334 p = RSTRING_PTR(str); pend = p + RSTRING_LEN(str);
8335 q = RSTRING_PTR(result); qend = q +
len + 1;
8339 unsigned char c = *p++;
8341 if (c ==
'"' || c ==
'\\') {
8345 else if (c ==
'#') {
8346 if (IS_EVSTR(p, pend)) *q++ =
'\\';
8349 else if (c ==
'\n') {
8353 else if (c ==
'\r') {
8357 else if (c ==
'\t') {
8361 else if (c ==
'\f') {
8365 else if (c ==
'\013') {
8369 else if (c ==
'\010') {
8373 else if (c ==
'\007') {
8377 else if (c ==
'\033') {
8387 int n = rb_enc_precise_mbclen(p-1, pend, enc) - 1;
8389 int cc = rb_enc_mbc_to_codepoint(p-1, pend, enc);
8392 snprintf(q, qend-q,
"u%04X", cc);
8394 snprintf(q, qend-q,
"u{%X}", cc);
8399 snprintf(q, qend-q,
"x%02X", c);
8405 if (!rb_enc_asciicompat(enc)) {
8406 snprintf(q, qend-q, nonascii_suffix, enc->name);
8407 encidx = rb_ascii8bit_encindex();
8410 rb_enc_associate_index(result, encidx);
8416unescape_ascii(
unsigned int c)
8440undump_after_backslash(
VALUE undumped,
const char **ss,
const char *s_end,
rb_encoding **penc,
bool *utf8,
bool *binary)
8442 const char *s = *ss;
8446 unsigned char buf[6];
8464 *buf = unescape_ascii(*s);
8476 if (enc_utf8 == NULL) enc_utf8 = rb_utf8_encoding();
8477 if (*penc != enc_utf8) {
8479 rb_enc_associate(undumped, enc_utf8);
8496 if (hexlen == 0 || hexlen > 6) {
8502 if (0xd800 <= c && c <= 0xdfff) {
8505 codelen = rb_enc_mbcput(c, (
char *)buf, *penc);
8515 if (0xd800 <= c && c <= 0xdfff) {
8518 codelen = rb_enc_mbcput(c, (
char *)buf, *penc);
8548static VALUE rb_str_is_ascii_only_p(
VALUE str);
8560str_undump(
VALUE str)
8562 const char *s = RSTRING_PTR(str);
8565 VALUE undumped = rb_enc_str_new(s, 0L, enc);
8567 bool binary =
false;
8571 if (rb_str_is_ascii_only_p(str) ==
Qfalse) {
8574 if (!str_null_check(str, &w)) {
8577 if (RSTRING_LEN(str) < 2)
goto invalid_format;
8578 if (*s !=
'"')
goto invalid_format;
8596 static const char force_encoding_suffix[] =
".force_encoding(\"";
8597 static const char dup_suffix[] =
".dup";
8598 const char *encname;
8603 size =
sizeof(dup_suffix) - 1;
8604 if (s_end - s > size && memcmp(s, dup_suffix, size) == 0) s += size;
8606 size =
sizeof(force_encoding_suffix) - 1;
8607 if (s_end - s <= size)
goto invalid_format;
8608 if (memcmp(s, force_encoding_suffix, size) != 0)
goto invalid_format;
8612 rb_raise(
rb_eRuntimeError,
"dumped string contained Unicode escape but used force_encoding");
8616 s = memchr(s,
'"', s_end-s);
8618 if (!s)
goto invalid_format;
8619 if (s_end - s != 2)
goto invalid_format;
8620 if (s[0] !=
'"' || s[1] !=
')')
goto invalid_format;
8622 encidx = rb_enc_find_index2(encname, (
long)size);
8626 rb_enc_associate_index(undumped, encidx);
8636 undump_after_backslash(undumped, &s, s_end, &enc, &utf8, &binary);
8647 rb_raise(
rb_eRuntimeError,
"invalid dumped string; not wrapped with '\"' nor '\"...\".force_encoding(\"...\")' form");
8653 if (rb_enc_dummy_p(enc)) {
8660str_true_enc(
VALUE str)
8663 rb_str_check_dummy_enc(enc);
8667static OnigCaseFoldType
8668check_case_options(
int argc,
VALUE *argv, OnigCaseFoldType flags)
8673 rb_raise(rb_eArgError,
"too many options");
8674 if (argv[0]==sym_turkic) {
8675 flags |= ONIGENC_CASE_FOLD_TURKISH_AZERI;
8677 if (argv[1]==sym_lithuanian)
8678 flags |= ONIGENC_CASE_FOLD_LITHUANIAN;
8680 rb_raise(rb_eArgError,
"invalid second option");
8683 else if (argv[0]==sym_lithuanian) {
8684 flags |= ONIGENC_CASE_FOLD_LITHUANIAN;
8686 if (argv[1]==sym_turkic)
8687 flags |= ONIGENC_CASE_FOLD_TURKISH_AZERI;
8689 rb_raise(rb_eArgError,
"invalid second option");
8693 rb_raise(rb_eArgError,
"too many options");
8694 else if (argv[0]==sym_ascii)
8695 flags |= ONIGENC_CASE_ASCII_ONLY;
8696 else if (argv[0]==sym_fold) {
8697 if ((flags & (ONIGENC_CASE_UPCASE|ONIGENC_CASE_DOWNCASE)) == ONIGENC_CASE_DOWNCASE)
8698 flags ^= ONIGENC_CASE_FOLD|ONIGENC_CASE_DOWNCASE;
8700 rb_raise(rb_eArgError,
"option :fold only allowed for downcasing");
8703 rb_raise(rb_eArgError,
"invalid option");
8710 if ((flags & ONIGENC_CASE_ASCII_ONLY) && (enc==rb_utf8_encoding() ||
rb_enc_mbmaxlen(enc) == 1))
8712 return !(flags & ONIGENC_CASE_FOLD_TURKISH_AZERI) &&
8717#define CASE_MAPPING_ADDITIONAL_LENGTH 20
8718#ifndef CASEMAP_DEBUG
8719# define CASEMAP_DEBUG 0
8727 OnigUChar space[FLEX_ARY_LEN];
8731mapping_buffer_free(
void *p)
8735 while (current_buffer) {
8736 previous_buffer = current_buffer;
8737 current_buffer = current_buffer->next;
8738 ruby_xfree_sized(previous_buffer, offsetof(
mapping_buffer, space) + previous_buffer->capa);
8744 {0, mapping_buffer_free,},
8745 0, 0, RUBY_TYPED_THREAD_SAFE_FREE | RUBY_TYPED_WB_PROTECTED
8753 const OnigUChar *source_current, *source_end;
8754 int target_length = 0;
8755 VALUE buffer_anchor;
8758 size_t buffer_count = 0;
8759 int buffer_length_or_invalid;
8761 if (RSTRING_LEN(source) == 0)
return str_duplicate(
rb_cString, source);
8763 source_current = (OnigUChar*)RSTRING_PTR(source);
8768 while (source_current < source_end) {
8770 size_t capa = (size_t)(source_end-source_current)*++buffer_count + CASE_MAPPING_ADDITIONAL_LENGTH;
8771 if (CASEMAP_DEBUG) {
8772 fprintf(stderr,
"Buffer allocation, capa is %"PRIuSIZE
"\n",
capa);
8775 *pre_buffer = current_buffer;
8776 pre_buffer = ¤t_buffer->next;
8777 current_buffer->next = NULL;
8778 current_buffer->capa =
capa;
8779 buffer_length_or_invalid = enc->case_map(flags,
8780 &source_current, source_end,
8781 current_buffer->space,
8782 current_buffer->space+current_buffer->capa,
8784 if (buffer_length_or_invalid < 0) {
8785 current_buffer =
DATA_PTR(buffer_anchor);
8787 mapping_buffer_free(current_buffer);
8788 rb_raise(rb_eArgError,
"input string invalid");
8790 target_length += current_buffer->used = buffer_length_or_invalid;
8792 if (CASEMAP_DEBUG) {
8793 fprintf(stderr,
"Buffer count is %"PRIuSIZE
"\n", buffer_count);
8796 if (buffer_count==1) {
8797 target =
rb_str_new((
const char*)current_buffer->space, target_length);
8800 char *target_current;
8803 target_current = RSTRING_PTR(target);
8804 current_buffer =
DATA_PTR(buffer_anchor);
8805 while (current_buffer) {
8806 memcpy(target_current, current_buffer->space, current_buffer->used);
8807 target_current += current_buffer->used;
8808 current_buffer = current_buffer->next;
8811 current_buffer =
DATA_PTR(buffer_anchor);
8813 mapping_buffer_free(current_buffer);
8818 str_enc_copy_direct(target, source);
8827 const OnigUChar *source_current, *source_end;
8828 OnigUChar *target_current, *target_end;
8829 long old_length = RSTRING_LEN(source);
8830 int length_or_invalid;
8832 if (old_length == 0)
return Qnil;
8834 source_current = (OnigUChar*)RSTRING_PTR(source);
8836 if (source == target) {
8837 target_current = (OnigUChar*)source_current;
8838 target_end = (OnigUChar*)source_end;
8841 target_current = (OnigUChar*)RSTRING_PTR(target);
8845 length_or_invalid = onigenc_ascii_only_case_map(flags,
8846 &source_current, source_end,
8847 target_current, target_end, enc);
8848 if (length_or_invalid < 0)
8849 rb_raise(rb_eArgError,
"input string invalid");
8850 if (CASEMAP_DEBUG && length_or_invalid != old_length) {
8851 fprintf(stderr,
"problem with rb_str_ascii_casemap"
8852 "; old_length=%ld, new_length=%d\n", old_length, length_or_invalid);
8853 rb_raise(rb_eArgError,
"internal problem with rb_str_ascii_casemap"
8854 "; old_length=%ld, new_length=%d\n", old_length, length_or_invalid);
8857 str_enc_copy(target, source);
8863upcase_single(
VALUE str)
8865 char *s = RSTRING_PTR(str), *send =
RSTRING_END(str);
8866 bool modified =
false;
8869 unsigned int c = *(
unsigned char*)s;
8871 if (
'a' <= c && c <=
'z') {
8872 *s =
'A' + (c -
'a');
8893rb_str_upcase_bang(
int argc,
VALUE *argv,
VALUE str)
8896 OnigCaseFoldType flags = ONIGENC_CASE_UPCASE;
8898 flags = check_case_options(argc, argv, flags);
8899 str_modify_keep_cr(str);
8900 enc = str_true_enc(str);
8901 if (case_option_single_p(flags, enc, str)) {
8902 if (upcase_single(str))
8903 flags |= ONIGENC_CASE_MODIFIED;
8905 else if (flags&ONIGENC_CASE_ASCII_ONLY)
8906 rb_str_ascii_casemap(str, str, &flags, enc);
8908 str_shared_replace(str, rb_str_casemap(str, &flags, enc));
8910 if (ONIGENC_CASE_MODIFIED&flags)
return str;
8923rb_str_upcase(
int argc,
VALUE *argv,
VALUE str)
8926 OnigCaseFoldType flags = ONIGENC_CASE_UPCASE;
8929 flags = check_case_options(argc, argv, flags);
8930 enc = str_true_enc(str);
8931 if (case_option_single_p(flags, enc, str)) {
8932 ret =
rb_str_new(RSTRING_PTR(str), RSTRING_LEN(str));
8933 str_enc_copy_direct(ret, str);
8936 else if (flags&ONIGENC_CASE_ASCII_ONLY) {
8938 rb_str_ascii_casemap(str, ret, &flags, enc);
8941 ret = rb_str_casemap(str, &flags, enc);
8948downcase_single(
VALUE str)
8950 char *s = RSTRING_PTR(str), *send =
RSTRING_END(str);
8951 bool modified =
false;
8954 unsigned int c = *(
unsigned char*)s;
8956 if (
'A' <= c && c <=
'Z') {
8957 *s =
'a' + (c -
'A');
8979rb_str_downcase_bang(
int argc,
VALUE *argv,
VALUE str)
8982 OnigCaseFoldType flags = ONIGENC_CASE_DOWNCASE;
8984 flags = check_case_options(argc, argv, flags);
8985 str_modify_keep_cr(str);
8986 enc = str_true_enc(str);
8987 if (case_option_single_p(flags, enc, str)) {
8988 if (downcase_single(str))
8989 flags |= ONIGENC_CASE_MODIFIED;
8991 else if (flags&ONIGENC_CASE_ASCII_ONLY)
8992 rb_str_ascii_casemap(str, str, &flags, enc);
8994 str_shared_replace(str, rb_str_casemap(str, &flags, enc));
8996 if (ONIGENC_CASE_MODIFIED&flags)
return str;
9010rb_str_downcase(
int argc,
VALUE *argv,
VALUE str)
9013 OnigCaseFoldType flags = ONIGENC_CASE_DOWNCASE;
9016 flags = check_case_options(argc, argv, flags);
9017 enc = str_true_enc(str);
9018 if (case_option_single_p(flags, enc, str)) {
9019 ret =
rb_str_new(RSTRING_PTR(str), RSTRING_LEN(str));
9020 str_enc_copy_direct(ret, str);
9021 downcase_single(ret);
9023 else if (flags&ONIGENC_CASE_ASCII_ONLY) {
9025 rb_str_ascii_casemap(str, ret, &flags, enc);
9028 ret = rb_str_casemap(str, &flags, enc);
9035capitalize_single(
VALUE str)
9037 char *s = RSTRING_PTR(str), *send =
RSTRING_END(str);
9038 bool modified =
false;
9041 unsigned int c = (
unsigned char)*s;
9043 if (
'a' <= c && c <=
'z') {
9044 *s =
'A' + (c -
'a');
9050 unsigned int c = (
unsigned char)*s;
9052 if (
'A' <= c && c <=
'Z') {
9053 *s =
'a' + (c -
'A');
9075rb_str_capitalize_bang(
int argc,
VALUE *argv,
VALUE str)
9078 OnigCaseFoldType flags = ONIGENC_CASE_UPCASE | ONIGENC_CASE_TITLECASE;
9080 flags = check_case_options(argc, argv, flags);
9081 str_modify_keep_cr(str);
9082 enc = str_true_enc(str);
9083 if (RSTRING_LEN(str) == 0 || !RSTRING_PTR(str))
return Qnil;
9084 if (case_option_single_p(flags, enc, str)) {
9085 if (capitalize_single(str))
9086 flags |= ONIGENC_CASE_MODIFIED;
9088 else if (flags&ONIGENC_CASE_ASCII_ONLY)
9089 rb_str_ascii_casemap(str, str, &flags, enc);
9091 str_shared_replace(str, rb_str_casemap(str, &flags, enc));
9093 if (ONIGENC_CASE_MODIFIED&flags)
return str;
9107rb_str_capitalize(
int argc,
VALUE *argv,
VALUE str)
9110 OnigCaseFoldType flags = ONIGENC_CASE_UPCASE | ONIGENC_CASE_TITLECASE;
9113 flags = check_case_options(argc, argv, flags);
9114 enc = str_true_enc(str);
9115 if (RSTRING_LEN(str) == 0 || !RSTRING_PTR(str))
return str;
9116 if (case_option_single_p(flags, enc, str)) {
9117 ret =
rb_str_new(RSTRING_PTR(str), RSTRING_LEN(str));
9118 str_enc_copy_direct(ret, str);
9119 capitalize_single(ret);
9121 else if (flags&ONIGENC_CASE_ASCII_ONLY) {
9123 rb_str_ascii_casemap(str, ret, &flags, enc);
9126 ret = rb_str_casemap(str, &flags, enc);
9145rb_str_swapcase_bang(
int argc,
VALUE *argv,
VALUE str)
9148 OnigCaseFoldType flags = ONIGENC_CASE_UPCASE | ONIGENC_CASE_DOWNCASE;
9150 flags = check_case_options(argc, argv, flags);
9151 str_modify_keep_cr(str);
9152 enc = str_true_enc(str);
9153 if (flags&ONIGENC_CASE_ASCII_ONLY)
9154 rb_str_ascii_casemap(str, str, &flags, enc);
9156 str_shared_replace(str, rb_str_casemap(str, &flags, enc));
9158 if (ONIGENC_CASE_MODIFIED&flags)
return str;
9172rb_str_swapcase(
int argc,
VALUE *argv,
VALUE str)
9175 OnigCaseFoldType flags = ONIGENC_CASE_UPCASE | ONIGENC_CASE_DOWNCASE;
9178 flags = check_case_options(argc, argv, flags);
9179 enc = str_true_enc(str);
9180 if (RSTRING_LEN(str) == 0 || !RSTRING_PTR(str))
return str_duplicate(
rb_cString, str);
9181 if (flags&ONIGENC_CASE_ASCII_ONLY) {
9183 rb_str_ascii_casemap(str, ret, &flags, enc);
9186 ret = rb_str_casemap(str, &flags, enc);
9191typedef unsigned char *USTR;
9195 unsigned int now, max;
9196 const char *p, *pend;
9207 if (t->p == t->pend)
return -1;
9208 if (rb_enc_ascget(t->p, t->pend, &n, enc) ==
'\\' && t->p + n < t->pend) {
9211 t->now = rb_enc_codepoint_len(t->p, t->pend, &n, enc);
9213 if (rb_enc_ascget(t->p, t->pend, &n, enc) ==
'-' && t->p + n < t->pend) {
9215 if (t->p < t->pend) {
9216 unsigned int c = rb_enc_codepoint_len(t->p, t->pend, &n, enc);
9219 if (t->now < 0x80 && c < 0x80) {
9220 rb_raise(rb_eArgError,
9221 "invalid range \"%c-%c\" in string transliteration",
9225 rb_raise(rb_eArgError,
"invalid range in string transliteration");
9229 else if (t->now < c) {
9238 while (ONIGENC_CODE_TO_MBCLEN(enc, ++t->now) <= 0) {
9239 if (t->now == t->max) {
9244 if (t->now < t->max) {
9260 const unsigned int errc = -1;
9261 unsigned int trans[256];
9263 struct tr trsrc, trrepl;
9265 unsigned int c, c0, last = 0;
9266 int modify = 0, i, l;
9267 unsigned char *s, *send;
9269 int singlebyte = single_byte_optimizable(str);
9273#define CHECK_IF_ASCII(c) \
9274 (void)((cr == ENC_CODERANGE_7BIT && !rb_isascii(c)) ? \
9275 (cr = ENC_CODERANGE_VALID) : 0)
9279 if (RSTRING_LEN(str) == 0 || !RSTRING_PTR(str))
return Qnil;
9280 if (RSTRING_LEN(repl) == 0) {
9281 return rb_str_delete_bang(1, &src, str);
9285 e1 = rb_enc_check(str, src);
9286 e2 = rb_enc_check(str, repl);
9291 enc = rb_enc_check(src, repl);
9293 trsrc.p = RSTRING_PTR(src); trsrc.pend = trsrc.p + RSTRING_LEN(src);
9294 if (RSTRING_LEN(src) > 1 &&
9295 rb_enc_ascget(trsrc.p, trsrc.pend, &l, enc) ==
'^' &&
9296 trsrc.p + l < trsrc.pend) {
9300 trrepl.p = RSTRING_PTR(repl);
9301 trrepl.pend = trrepl.p + RSTRING_LEN(repl);
9302 trsrc.gen = trrepl.gen = 0;
9303 trsrc.now = trrepl.now = 0;
9304 trsrc.max = trrepl.max = 0;
9307 for (i=0; i<256; i++) {
9310 while ((c = trnext(&trsrc, enc)) != errc) {
9315 if (!hash) hash = rb_hash_new();
9319 while ((c = trnext(&trrepl, enc)) != errc)
9322 for (i=0; i<256; i++) {
9323 if (trans[i] != errc) {
9331 for (i=0; i<256; i++) {
9334 while ((c = trnext(&trsrc, enc)) != errc) {
9335 r = trnext(&trrepl, enc);
9336 if (r == errc) r = trrepl.now;
9339 if (rb_enc_codelen(r, enc) != 1) singlebyte = 0;
9342 if (!hash) hash = rb_hash_new();
9350 str_modify_keep_cr(str);
9351 s = (
unsigned char *)RSTRING_PTR(str); send = (
unsigned char *)
RSTRING_END(str);
9352 termlen = rb_enc_mbminlen(enc);
9355 long offset, max = RSTRING_LEN(str);
9356 unsigned int save = -1;
9357 unsigned char *buf =
ALLOC_N(
unsigned char, max + termlen), *t = buf;
9362 int r = rb_enc_precise_mbclen((
char *)s, (
char *)send, e1);
9364 SIZED_FREE_N(buf, max + termlen);
9365 rb_raise(rb_eArgError,
"invalid byte sequence in %s", rb_enc_name(e1));
9368 c0 = c = rb_enc_mbc_to_codepoint((
char *)s, (
char *)send, e1);
9370 tlen = enc == e1 ? clen : rb_enc_codelen(c, enc);
9379 if (cflag) c = last;
9382 else if (cflag) c = errc;
9388 if (c != (
unsigned int)-1) {
9394 tlen = rb_enc_codelen(c, enc);
9400 if (enc != e1) may_modify = 1;
9402 if ((offset = t - buf) + tlen > max) {
9403 size_t MAYBE_UNUSED(old) = max + termlen;
9404 max = offset + tlen + (send - s);
9405 SIZED_REALLOC_N(buf,
unsigned char, max + termlen, old);
9408 rb_enc_mbcput(c, t, enc);
9409 if (may_modify && memcmp(s, t, tlen) != 0) {
9415 if (!STR_EMBED_P(str)) {
9416 SIZED_FREE_N(STR_HEAP_PTR(str), STR_HEAP_SIZE(str));
9418 TERM_FILL((
char *)t, termlen);
9419 RSTRING(str)->as.heap.ptr = (
char *)buf;
9420 STR_SET_LEN(str, t - buf);
9421 STR_SET_NOEMBED(str);
9422 RSTRING(str)->as.heap.aux.capa = max;
9426 c = (
unsigned char)*s;
9427 if (trans[c] != errc) {
9444 long offset, max = (long)((send - s) * 1.2);
9445 unsigned char *buf =
ALLOC_N(
unsigned char, max + termlen), *t = buf;
9450 int r = rb_enc_precise_mbclen((
char *)s, (
char *)send, e1);
9452 SIZED_FREE_N(buf, max + termlen);
9453 rb_raise(rb_eArgError,
"invalid byte sequence in %s", rb_enc_name(e1));
9456 c0 = c = rb_enc_mbc_to_codepoint((
char *)s, (
char *)send, e1);
9458 tlen = enc == e1 ? clen : rb_enc_codelen(c, enc);
9466 if (cflag) c = last;
9469 else if (cflag) c = errc;
9473 c = cflag ? last : errc;
9476 tlen = rb_enc_codelen(c, enc);
9481 if (enc != e1) may_modify = 1;
9483 if ((offset = t - buf) + tlen > max) {
9484 size_t MAYBE_UNUSED(old) = max + termlen;
9485 max = offset + tlen + (long)((send - s) * 1.2);
9486 SIZED_REALLOC_N(buf,
unsigned char, max + termlen, old);
9490 rb_enc_mbcput(c, t, enc);
9491 if (may_modify && memcmp(s, t, tlen) != 0) {
9498 if (!STR_EMBED_P(str)) {
9499 SIZED_FREE_N(STR_HEAP_PTR(str), STR_HEAP_SIZE(str));
9501 TERM_FILL((
char *)t, termlen);
9502 RSTRING(str)->as.heap.ptr = (
char *)buf;
9503 STR_SET_LEN(str, t - buf);
9504 STR_SET_NOEMBED(str);
9505 RSTRING(str)->as.heap.aux.capa = max;
9511 rb_enc_associate(str, enc);
9521 size_t initial_capa;
9525tr_buffer_init(
struct tr_buffer *buffer,
size_t initial_capa)
9527 if (initial_capa < 32) {
9530 *buffer = (
struct tr_buffer){ .initial_capa = initial_capa };
9534tr_buffer_ensure_capa(
struct tr_buffer *buffer,
size_t extra_capa)
9536 size_t offset = buffer->ptr - buffer->buf;
9537 size_t required_capa = offset + extra_capa;
9538 if (UNLIKELY(buffer->capa < required_capa)) {
9539 size_t new_capa = buffer->capa ? buffer->capa : buffer->initial_capa;
9541 while (new_capa < required_capa) {
9542 new_capa = (size_t)(new_capa * 1.2);
9544 SIZED_REALLOC_N(buffer->buf,
unsigned char, new_capa, buffer->capa);
9545 buffer->ptr = buffer->buf + offset;
9546 buffer->capa = new_capa;
9551tr_buffer_append(
struct tr_buffer *buffer,
const unsigned char *ptr,
size_t len)
9554 tr_buffer_ensure_capa(buffer,
len);
9555 memcpy(buffer->ptr, ptr,
len);
9563 tr_buffer_append(buffer, (
unsigned char *)RSTRING_PTR(str), RSTRING_LEN(str));
9569 tr_buffer_ensure_capa(buffer, 4);
9570 buffer->ptr += rb_enc_mbcput(codepoint, buffer->ptr, enc);
9577 SIZED_FREE_N(buffer->buf, buffer->capa);
9594tr_trans_pairs_coerce_i(st_data_t key, st_data_t value, st_data_t _args)
9597 struct tr_pair *pair = &args->pairs[args->index];
9605 if (RSTRING_LEN(search) != 1 && str_strlen(search, NULL) != 1) {
9606 rb_raise(rb_eArgError,
"keys must be of size 1");
9609 args->enc = rb_enc_check_multi_str(args->enc, &args->cr, search);
9610 args->enc = rb_enc_check_multi_str(args->enc, &args->cr, replace);
9612 pair->search = search;
9613 pair->replace = replace;
9617#define TR_TRANS_PAIRS_SIMD_MAX_NEEDLES 16
9620 const unsigned char *s;
9621 const unsigned char *send;
9624 unsigned char needles[TR_TRANS_PAIRS_SIMD_MAX_NEEDLES];
9625 unsigned int needles_count;
9626#ifdef HAVE_SIMD_NEON
9627 uint64_t matches_bitmap;
9629#ifdef HAVE_SIMD_SSE2
9634 VALUE trans_table[256];
9640 while (search->s < search->send) {
9641 VALUE repl = search->trans_table[*search->s];
9642 if (UNLIKELY(repl)) {
9652#ifdef HAVE_SIMD_SSE2
9657 size_t trailing_zeros = (size_t)ntz_int32(search->matches_bitmap);
9659 RUBY_ASSERT(trailing_zeros < (
sizeof(search->matches_bitmap) * CHAR_BIT));
9660 search->matches_bitmap >>= trailing_zeros;
9661 search->s += trailing_zeros;
9664 return search->trans_table[*search->s];
9670 const unsigned int needles_count = search->needles_count;
9671 if (needles_count) {
9674 if (search->matches_bitmap) {
9675 return tr_trans_pairs_next_match_sse2(search);
9678 if ((
size_t)(search->send - search->s) >=
sizeof(__m128i)) {
9680 __m128i masks[TR_TRANS_PAIRS_SIMD_MAX_NEEDLES];
9681 for (i = 0; i < needles_count; i++) {
9682 masks[i] = _mm_set1_epi8(search->needles[i]);
9686 const __m128i bytes = _mm_loadu_si128((__m128i
const *)search->s);
9688 __m128i matches[TR_TRANS_PAIRS_SIMD_MAX_NEEDLES];
9689 for (i = 0; i < needles_count; i++) {
9690 matches[i] = _mm_cmpeq_epi8(bytes, masks[i]);
9693 for (i = 1; i < needles_count; i++) {
9694 matches[0] = _mm_or_si128(matches[0], matches[i]);
9697 const int bitmap = _mm_movemask_epi8(matches[0]);
9700 search->matches_bitmap = bitmap;
9701 return tr_trans_pairs_next_match_sse2(search);
9703 search->s +=
sizeof(__m128i);
9704 }
while ((
size_t)(search->send - search->s) >=
sizeof(__m128i));
9707 return tr_trans_pairs_search_basic(search);
9710#define tr_trans_pairs_search_impl tr_trans_pairs_search_sse2
9713#ifdef HAVE_SIMD_NEON
9718 size_t trailing_zeros = (size_t)ntz_int64(search->matches_bitmap);
9721 RUBY_ASSERT(trailing_zeros < (
sizeof(search->matches_bitmap) * CHAR_BIT));
9722 search->matches_bitmap >>= trailing_zeros;
9723 search->s += trailing_zeros / 4;
9726 return search->trans_table[*search->s];
9732 const unsigned int needles_count = search->needles_count;
9733 if (needles_count) {
9736 if (search->matches_bitmap) {
9737 return tr_trans_pairs_next_match_neon(search);
9740 if ((
size_t)(search->send - search->s) >=
sizeof(uint8x16_t)) {
9742 uint8x16_t masks[TR_TRANS_PAIRS_SIMD_MAX_NEEDLES];
9743 for (i = 0; i < needles_count; i++) {
9744 masks[i] = vdupq_n_u8(search->needles[i]);
9748 const uint8x16_t bytes = vld1q_u8(search->s);
9750 uint8x16_t matches[TR_TRANS_PAIRS_SIMD_MAX_NEEDLES];
9751 for (i = 0; i < needles_count; i++) {
9752 matches[i] = vceqq_u8(bytes, masks[i]);
9755 for (i = 1; i < needles_count; i++) {
9756 matches[0] = vorrq_u8(matches[0], matches[i]);
9759 const uint8x8_t res = vshrn_n_u16(vreinterpretq_u16_u8(matches[0]), 4);
9760 const uint64_t bitmap = vget_lane_u64(vreinterpret_u64_u8(res), 0);
9763 search->matches_bitmap = bitmap & 0x8888888888888888ull;
9764 return tr_trans_pairs_next_match_neon(search);
9766 search->s +=
sizeof(uint8x16_t);
9767 }
while ((
size_t)(search->send - search->s) >=
sizeof(uint8x16_t));
9770 return tr_trans_pairs_search_basic(search);
9773#define tr_trans_pairs_search_impl tr_trans_pairs_search_neon
9776#ifndef tr_trans_pairs_search_impl
9777#define tr_trans_pairs_search_impl tr_trans_pairs_search_basic
9785 search->matches_bitmap >>= 1;
9794 mustnot_broken(str);
9797 if (RSTRING_LEN(str) == 0 || !RSTRING_PTR(str) || pairs_count == 0)
return Qnil;
9802 int cr = rb_enc_str_coderange(str);
9816 pairs_count = coerce_args.index;
9820 const unsigned char *sstart = (
unsigned char *)RSTRING_PTR(str);
9821 long str_len = RSTRING_LEN(str);
9822 int termlen = rb_enc_mbminlen(e1);
9825 tr_buffer_init(&buffer, str_len);
9826 bool modify =
false;
9828 if (RB_LIKELY(rb_str_encindex_fastpath(rb_enc_to_index(e1)))) {
9832 .send = sstart + str_len,
9835 for (
size_t index = 0; index < pairs_count; index++) {
9836 struct tr_pair *pair = &pairs[index];
9838 char *ptr = RSTRING_PTR(pair->search);
9839 unsigned int codepoint = rb_enc_mbc_to_codepoint(ptr,
RSTRING_END(pair->search), e1);
9841 const unsigned char first_byte = (
unsigned char)*ptr;
9844 if (pairs_count <= TR_TRANS_PAIRS_SIMD_MAX_NEEDLES) {
9845 search.needles[index] = first_byte;
9846 search.needles_count++;
9850 if (rb_enc_codelen(codepoint, e1) == 1) {
9851 search.trans_table[first_byte] = pair->replace;
9854 search.trans_table[first_byte] =
Qundef;
9856 hash =
rb_obj_hide(rb_hash_new_capa(pairs_count));
9858 rb_hash_aset(hash,
UINT2NUM(codepoint), pair->replace);
9862 const unsigned char *checkpoint = search.s;
9864 while ((repl = tr_trans_pairs_search_impl(&search))) {
9867 if (UNLIKELY(repl ==
Qundef)) {
9868 unsigned int c = rb_enc_mbc_to_codepoint((
char *)search.s, (
char *)search.send, e1);
9869 clen = rb_enc_codelen(c, e1);
9870 repl = rb_hash_lookup2(hash,
UINT2NUM(c), 0);
9872 tr_trans_pairs_consume_match(&search);
9880 if (checkpoint < search.s) {
9881 tr_buffer_append(&buffer, checkpoint, search.s - checkpoint);
9883 tr_buffer_append_str(&buffer, repl);
9884 checkpoint = search.s + clen;
9885 tr_trans_pairs_consume_match(&search);
9892 if (modify && checkpoint < search.s) {
9893 tr_buffer_append(&buffer, checkpoint, search.s - checkpoint);
9897 const unsigned char *s = sstart;
9898 const unsigned char *send = sstart + str_len;
9900 hash =
rb_obj_hide(rb_hash_new_capa(pairs_count));
9902 for (
size_t index = 0; index < pairs_count; index++) {
9903 struct tr_pair *pair = &pairs[index];
9905 unsigned int codepoint = rb_enc_mbc_to_codepoint(RSTRING_PTR(pair->search),
RSTRING_END(pair->search), e1);
9906 rb_hash_aset(hash,
UINT2NUM(codepoint), pair->replace);
9910 bool may_modify =
false;
9912 int r = rb_enc_precise_mbclen((
char *)s, (
char *)send, e1);
9914 tr_buffer_free(&buffer);
9915 rb_raise(rb_eArgError,
"invalid byte sequence in %s", rb_enc_name(e1));
9918 unsigned int c = rb_enc_mbc_to_codepoint((
char *)s, (
char *)send, e1);
9919 unsigned int c0 = c;
9921 long tlen = enc == e1 ? clen : rb_enc_codelen(c, e1);
9924 if (
NIL_P(replacement)) {
9925 tlen = enc == e1 ? clen : rb_enc_codelen(c, enc);
9927 if (enc != e1) may_modify =
true;
9930 tlen = RSTRING_LEN(replacement);
9934 if (
NIL_P(replacement)) {
9935 tr_buffer_mbcput(&buffer, c, enc);
9938 tr_buffer_append_str(&buffer, replacement);
9941 if (may_modify && memcmp(s, buffer.ptr - tlen, tlen) != 0) {
9957 if (!STR_EMBED_P(str)) {
9958 SIZED_FREE_N(STR_HEAP_PTR(str), STR_HEAP_SIZE(str));
9960 tr_buffer_ensure_capa(&buffer, termlen);
9961 TERM_FILL((
char *)buffer.ptr, termlen);
9962 RSTRING(str)->as.heap.ptr = (
char *)buffer.buf;
9963 STR_SET_LEN(str, buffer.ptr - buffer.buf);
9964 STR_SET_NOEMBED(str);
9965 RSTRING(str)->as.heap.aux.capa = buffer.capa - termlen;
9971 rb_enc_associate(str, e1);
9989rb_str_tr_bang(
int argc,
VALUE *argv,
VALUE str)
9994 VALUE pairs = argv[0];
9995 return tr_trans_pairs(str, pairs);
9998 VALUE src = argv[0], repl = argv[1];
9999 return tr_trans(str, src, repl, 0);
10063 VALUE pairs = argv[0];
10064 VALUE result = tr_trans_pairs(str, pairs);
10065 if (
NIL_P(result)) result = str;
10069 VALUE src = argv[0], repl = argv[1];
10070 tr_trans(str, src, repl, 0);
10074#define TR_TABLE_MAX (UCHAR_MAX+1)
10075#define TR_TABLE_SIZE (TR_TABLE_MAX+1)
10077tr_setup_table(
VALUE str,
char stable[TR_TABLE_SIZE],
int first,
10080 const unsigned int errc = -1;
10081 char buf[TR_TABLE_MAX];
10084 VALUE table = 0, ptable = 0;
10085 int i, l, cflag = 0;
10087 tr.p = RSTRING_PTR(str);
tr.pend =
tr.p + RSTRING_LEN(str);
10088 tr.gen =
tr.now =
tr.max = 0;
10090 if (RSTRING_LEN(str) > 1 && rb_enc_ascget(
tr.p,
tr.pend, &l, enc) ==
'^') {
10095 for (i=0; i<TR_TABLE_MAX; i++) {
10098 stable[TR_TABLE_MAX] = cflag;
10100 else if (stable[TR_TABLE_MAX] && !cflag) {
10101 stable[TR_TABLE_MAX] = 0;
10103 for (i=0; i<TR_TABLE_MAX; i++) {
10107 while ((c = trnext(&
tr, enc)) != errc) {
10108 if (c < TR_TABLE_MAX) {
10109 buf[(
unsigned char)c] = !cflag;
10114 if (!table && (first || *tablep || stable[TR_TABLE_MAX])) {
10117 table = ptable ? ptable : rb_hash_new();
10121 table = rb_hash_new();
10126 if (table && (!ptable || (cflag ^ !
NIL_P(rb_hash_aref(ptable, key))))) {
10127 rb_hash_aset(table, key,
Qtrue);
10131 for (i=0; i<TR_TABLE_MAX; i++) {
10132 stable[i] = stable[i] && buf[i];
10134 if (!table && !cflag) {
10141tr_find(
unsigned int c,
const char table[TR_TABLE_SIZE],
VALUE del,
VALUE nodel)
10143 if (c < TR_TABLE_MAX) {
10144 return table[c] != 0;
10150 if (!
NIL_P(rb_hash_lookup(del, v)) &&
10151 (!nodel ||
NIL_P(rb_hash_lookup(nodel, v)))) {
10155 else if (nodel && !
NIL_P(rb_hash_lookup(nodel, v))) {
10158 return table[TR_TABLE_MAX] ? TRUE : FALSE;
10173rb_str_delete_bang(
int argc,
VALUE *argv,
VALUE str)
10175 char squeez[TR_TABLE_SIZE];
10177 char *s, *send, *t;
10178 VALUE del = 0, nodel = 0;
10180 int i, ascompat, cr;
10182 if (RSTRING_LEN(str) == 0 || !RSTRING_PTR(str))
return Qnil;
10184 for (i=0; i<argc; i++) {
10188 enc = rb_enc_check(str, s);
10189 tr_setup_table(s, squeez, i==0, &del, &nodel, enc);
10192 str_modify_keep_cr(str);
10193 ascompat = rb_enc_asciicompat(enc);
10194 s = t = RSTRING_PTR(str);
10201 if (ascompat && (c = *(
unsigned char*)s) < 0x80) {
10206 if (t != s) *t = c;
10212 c = rb_enc_codepoint_len(s, send, &clen, enc);
10214 if (tr_find(c, squeez, del, nodel)) {
10218 if (t != s) rb_enc_mbcput(c, t, enc);
10225 TERM_FILL(t, TERM_LEN(str));
10226 STR_SET_LEN(str, t - RSTRING_PTR(str));
10229 if (modify)
return str;
10243rb_str_delete(
int argc,
VALUE *argv,
VALUE str)
10246 rb_str_delete_bang(argc, argv, str);
10264rb_str_squeeze_bang(
int argc,
VALUE *argv,
VALUE str)
10266 char squeez[TR_TABLE_SIZE];
10268 VALUE del = 0, nodel = 0;
10269 unsigned char *s, *send, *t;
10271 int ascompat, singlebyte = single_byte_optimizable(str);
10275 enc = STR_ENC_GET(str);
10278 for (i=0; i<argc; i++) {
10282 enc = rb_enc_check(str, s);
10283 if (singlebyte && !single_byte_optimizable(s))
10285 tr_setup_table(s, squeez, i==0, &del, &nodel, enc);
10289 str_modify_keep_cr(str);
10290 s = t = (
unsigned char *)RSTRING_PTR(str);
10291 if (!s || RSTRING_LEN(str) == 0)
return Qnil;
10294 ascompat = rb_enc_asciicompat(enc);
10298 unsigned int c = *s++;
10299 if (c != save || (argc > 0 && !squeez[c])) {
10309 if (ascompat && (c = *s) < 0x80) {
10310 if (c != save || (argc > 0 && !squeez[c])) {
10316 c = rb_enc_codepoint_len((
char *)s, (
char *)send, &clen, enc);
10318 if (c != save || (argc > 0 && !tr_find(c, squeez, del, nodel))) {
10319 if (t != s) rb_enc_mbcput(c, t, enc);
10328 TERM_FILL((
char *)t, TERM_LEN(str));
10329 if ((
char *)t - RSTRING_PTR(str) != RSTRING_LEN(str)) {
10330 STR_SET_LEN(str, (
char *)t - RSTRING_PTR(str));
10334 if (modify)
return str;
10348rb_str_squeeze(
int argc,
VALUE *argv,
VALUE str)
10351 rb_str_squeeze_bang(argc, argv, str);
10371 return tr_trans(str, src, repl, 1);
10399 tr_trans(str, src, repl, 1);
10412rb_str_count(
int argc,
VALUE *argv,
VALUE str)
10414 char table[TR_TABLE_SIZE];
10416 VALUE del = 0, nodel = 0, tstr;
10417 const char *s, *send;
10426 enc = rb_enc_check(str, tstr);
10429 if (RSTRING_LEN(tstr) == 1 && rb_enc_asciicompat(enc) &&
10430 (ptstr = RSTRING_PTR(tstr),
10431 ONIGENC_IS_ALLOWED_REVERSE_MATCH(enc, (
const unsigned char *)ptstr, (
const unsigned char *)ptstr+1)) &&
10432 !is_broken_string(str)) {
10434 unsigned char c = rb_enc_codepoint_len(ptstr, ptstr+1, &clen, enc);
10436 s = RSTRING_PTR(str);
10437 if (!s || RSTRING_LEN(str) == 0)
return INT2FIX(0);
10440 if (*(
unsigned char*)s++ == c) n++;
10446 tr_setup_table(tstr, table, TRUE, &del, &nodel, enc);
10447 for (i=1; i<argc; i++) {
10450 enc = rb_enc_check(str, tstr);
10451 tr_setup_table(tstr, table, FALSE, &del, &nodel, enc);
10454 s = RSTRING_PTR(str);
10455 if (!s || RSTRING_LEN(str) == 0)
return INT2FIX(0);
10457 ascompat = rb_enc_asciicompat(enc);
10461 if (ascompat && (c = *(
unsigned char*)s) < 0x80) {
10469 c = rb_enc_codepoint_len(s, send, &clen, enc);
10470 if (tr_find(c, table, del, nodel)) {
10481rb_fs_check(
VALUE val)
10485 if (
NIL_P(val))
return 0;
10490static const char isspacetable[256] = {
10491 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0,
10492 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
10493 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
10494 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
10495 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
10496 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
10497 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
10498 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
10499 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
10500 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
10501 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
10502 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
10503 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
10504 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
10505 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
10506 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
10509#define ascii_isspace(c) isspacetable[(unsigned char)(c)]
10512split_string(
VALUE result,
VALUE str,
long beg,
long len,
long empty_count)
10514 if (empty_count >= 0 &&
len == 0) {
10515 return empty_count + 1;
10517 if (empty_count > 0) {
10522 }
while (--empty_count > 0);
10526 rb_yield(str_new_empty_String(str));
10527 }
while (--empty_count > 0);
10537 return empty_count;
10541 SPLIT_TYPE_AWK, SPLIT_TYPE_STRING, SPLIT_TYPE_REGEXP, SPLIT_TYPE_CHARS
10545literal_split_pattern(
VALUE spat, split_type_t default_type)
10553 return SPLIT_TYPE_CHARS;
10555 else if (rb_enc_asciicompat(enc)) {
10556 if (
len == 1 && ptr[0] ==
' ') {
10557 return SPLIT_TYPE_AWK;
10562 if (rb_enc_ascget(ptr, ptr +
len, &l, enc) ==
' ' &&
len == l) {
10563 return SPLIT_TYPE_AWK;
10566 return default_type;
10579rb_str_split_m(
int argc,
VALUE *argv,
VALUE str)
10584 split_type_t split_type;
10585 long beg, end, i = 0, empty_count = -1;
10590 if (
rb_scan_args(argc, argv,
"02", &spat, &limit) == 2) {
10592 if (lim <= 0) limit =
Qnil;
10593 else if (lim == 1) {
10594 if (RSTRING_LEN(str) == 0)
10605 if (
NIL_P(limit) && !lim) empty_count = 0;
10607 enc = STR_ENC_GET(str);
10608 split_type = SPLIT_TYPE_REGEXP;
10609 if (!
NIL_P(spat)) {
10610 spat = get_pat_quoted(spat, 0);
10612 else if (
NIL_P(spat = rb_fs)) {
10613 split_type = SPLIT_TYPE_AWK;
10615 else if (!(spat = rb_fs_check(spat))) {
10616 rb_raise(
rb_eTypeError,
"value of $; must be String or Regexp");
10621 if (split_type != SPLIT_TYPE_AWK) {
10626 split_type = literal_split_pattern(tmp, SPLIT_TYPE_REGEXP);
10627 if (split_type == SPLIT_TYPE_AWK) {
10629 split_type = SPLIT_TYPE_STRING;
10634 mustnot_broken(spat);
10635 split_type = literal_split_pattern(spat, SPLIT_TYPE_STRING);
10643#define SPLIT_STR(beg, len) ( \
10644 empty_count = split_string(result, str, beg, len, empty_count), \
10645 str_mod_check(str, str_start, str_len))
10648 const char *ptr = RSTRING_PTR(str);
10649 const char *
const str_start = ptr;
10650 const long str_len = RSTRING_LEN(str);
10651 const char *
const eptr = str_start + str_len;
10652 if (split_type == SPLIT_TYPE_AWK) {
10653 const char *bptr = ptr;
10659 if (is_ascii_string(str)) {
10660 while (ptr < eptr) {
10661 c = (
unsigned char)*ptr++;
10663 if (ascii_isspace(c)) {
10669 if (!
NIL_P(limit) && lim <= i)
break;
10672 else if (ascii_isspace(c)) {
10673 SPLIT_STR(beg, end-beg);
10676 if (!
NIL_P(limit)) ++i;
10684 while (ptr < eptr) {
10687 c = rb_enc_codepoint_len(ptr, eptr, &n, enc);
10696 if (!
NIL_P(limit) && lim <= i)
break;
10700 SPLIT_STR(beg, end-beg);
10703 if (!
NIL_P(limit)) ++i;
10711 else if (split_type == SPLIT_TYPE_STRING) {
10712 const char *substr_start = ptr;
10713 const char *sptr = RSTRING_PTR(spat);
10714 long slen = RSTRING_LEN(spat);
10717 mustnot_broken(str);
10718 enc = rb_enc_check(str, spat);
10719 while (ptr < eptr &&
10720 (end =
rb_memsearch(sptr, slen, ptr, eptr - ptr, enc)) >= 0) {
10723 if (t != ptr + end) {
10727 SPLIT_STR(substr_start - str_start, (ptr+end) - substr_start);
10728 str_mod_check(spat, sptr, slen);
10730 substr_start = ptr;
10731 if (!
NIL_P(limit) && lim <= ++i)
break;
10733 beg = ptr - str_start;
10735 else if (split_type == SPLIT_TYPE_CHARS) {
10739 mustnot_broken(str);
10740 enc = rb_enc_get(str);
10741 while (ptr < eptr &&
10742 (n = rb_enc_precise_mbclen(ptr, eptr, enc)) > 0) {
10743 SPLIT_STR(ptr - str_start, n);
10745 if (!
NIL_P(limit) && lim <= ++i)
break;
10747 beg = ptr - str_start;
10751 long len = RSTRING_LEN(str);
10758 (match ? (rb_match_unbusy(match),
rb_backref_set(match)) : (void)0)) {
10761 end = RMATCH_BEG(match, 0);
10762 if (start == end && RMATCH_BEG(match, 0) == RMATCH_END(match, 0)) {
10767 else if (last_null == 1) {
10768 SPLIT_STR(beg, rb_enc_fast_mbclen(ptr+beg, eptr, enc));
10775 start += rb_enc_fast_mbclen(ptr+start,eptr,enc);
10781 SPLIT_STR(beg, end-beg);
10782 beg = start = RMATCH_END(match, 0);
10786 for (idx = 1; idx < RMATCH_NREGS(match); idx++) {
10787 if (RMATCH_BEG(match, idx) == -1)
continue;
10788 SPLIT_STR(RMATCH_BEG(match, idx), RMATCH_END(match, idx) - RMATCH_BEG(match, idx));
10790 if (!
NIL_P(limit) && lim <= ++i)
break;
10792 if (match) rb_match_unbusy(match);
10794 if (RSTRING_LEN(str) > 0 && (!
NIL_P(limit) || RSTRING_LEN(str) > beg || lim < 0)) {
10795 SPLIT_STR(beg, RSTRING_LEN(str)-beg);
10798 return result ? result : str;
10808 return rb_str_split_m(1, &sep, str);
10811#define WANTARRAY(m, size) (!rb_block_given_p() ? rb_ary_new_capa(size) : 0)
10826#define ENUM_ELEM(ary, e) enumerator_element(ary, e)
10829chomp_newline(
const char *p,
const char *e,
rb_encoding *enc)
10831 const char *prev = rb_enc_prev_char(p, e, e, enc);
10834 prev = rb_enc_prev_char(p, e, e, enc);
10835 if (prev && rb_enc_ascget(prev, e, NULL, enc) ==
'\r')
10847 RSTRING_LEN(rs) != 1 ||
10848 RSTRING_PTR(rs)[0] !=
'\n')) {
10854#define rb_rs get_rs()
10861 const char *pend, *subptr, *subend, *rsptr, *hit, *adjusted;
10867 if (!
NIL_P(opts)) {
10868 static ID keywords[1];
10869 if (!keywords[0]) {
10873 chomp = (!UNDEF_P(chomp) &&
RTEST(chomp));
10877 if (!ENUM_ELEM(ary, str)) {
10885 if (!RSTRING_LEN(str))
goto end;
10887 const char *
const ptr = subptr = RSTRING_PTR(str);
10888 const long len = RSTRING_LEN(str);
10891 rslen = RSTRING_LEN(rs);
10894 enc = rb_enc_get(str);
10896 enc = rb_enc_check(str, rs);
10901 const char *eol = NULL;
10903 while (subend < pend) {
10904 long chomp_rslen = 0;
10906 if (rb_enc_ascget(subend, pend, &n, enc) !=
'\r')
10908 rslen = n + rb_enc_mbclen(subend + n, pend, enc);
10910 if (eol == subend)
break;
10914 chomp_rslen = -rslen;
10918 if (!subptr) subptr = subend;
10922 }
while (subend < pend);
10923 if (!subptr)
break;
10924 if (rslen == 0) chomp_rslen = 0;
10926 subend - subptr + (chomp ? chomp_rslen : rslen));
10927 if (ENUM_ELEM(ary, line)) {
10928 str_mod_check(str, ptr,
len);
10930 subptr = eol = NULL;
10935 rsptr = RSTRING_PTR(rs);
10936 if (RSTRING_LEN(rs) == rb_enc_mbminlen(enc) &&
10945 rsptr = RSTRING_PTR(rs);
10946 rslen = RSTRING_LEN(rs);
10949 while (subptr < pend) {
10950 pos =
rb_memsearch(rsptr, rslen, subptr, pend - subptr, enc);
10951 if (pos < 0)
break;
10952 hit = subptr + pos;
10954 if (hit != adjusted) {
10958 subend = hit += rslen;
10961 subend = chomp_newline(subptr, subend, enc);
10968 if (ENUM_ELEM(ary, line)) {
10969 str_mod_check(str, ptr,
len);
10970 str_mod_check(rs, rsptr, rslen);
10975 if (subptr < pend) {
10978 pend = chomp_newline(subptr, pend, enc);
10980 else if (pend - subptr >= rslen &&
10981 memcmp(pend - rslen, rsptr, rslen) == 0) {
10986 ENUM_ELEM(ary, line);
11007rb_str_each_line(
int argc,
VALUE *argv,
VALUE str)
11010 return rb_str_enumerate_lines(argc, argv, str, 0);
11065rb_str_lines(
int argc,
VALUE *argv,
VALUE str)
11067 VALUE ary = WANTARRAY(
"lines", 0);
11068 return rb_str_enumerate_lines(argc, argv, str, ary);
11074 return LONG2FIX(RSTRING_LEN(str));
11082 for (i=0; i<RSTRING_LEN(str); i++) {
11083 ENUM_ELEM(ary,
INT2FIX((
unsigned char)RSTRING_PTR(str)[i]));
11101rb_str_each_byte(
VALUE str)
11104 return rb_str_enumerate_bytes(str, 0);
11116rb_str_bytes(
VALUE str)
11118 VALUE ary = WANTARRAY(
"bytes", RSTRING_LEN(str));
11119 return rb_str_enumerate_bytes(str, ary);
11137 ptr = RSTRING_PTR(str);
11138 len = RSTRING_LEN(str);
11139 enc = rb_enc_get(str);
11142 for (i = 0; i <
len; i += n) {
11143 n = rb_enc_fast_mbclen(ptr + i, ptr +
len, enc);
11148 for (i = 0; i <
len; i += n) {
11149 n = rb_enc_mbclen(ptr + i, ptr +
len, enc);
11170rb_str_each_char(
VALUE str)
11173 return rb_str_enumerate_chars(str, 0);
11185rb_str_chars(
VALUE str)
11188 return rb_str_enumerate_chars(str, ary);
11192rb_str_enumerate_codepoints(
VALUE str,
VALUE ary)
11197 const char *ptr, *end;
11199 int enc_asciicompat;
11201 if (single_byte_optimizable(str))
11202 return rb_str_enumerate_bytes(str, ary);
11205 ptr = RSTRING_PTR(str);
11207 enc = STR_ENC_GET(str);
11208 enc_asciicompat = rb_enc_asciicompat(enc);
11210 while (ptr < end) {
11215 c = (enc_asciicompat &&
ISASCII(*ptr)) ?
11216 (
unsigned char)*ptr : rb_enc_codepoint_len(ptr, end, &n, enc);
11237rb_str_each_codepoint(
VALUE str)
11240 return rb_str_enumerate_codepoints(str, 0);
11252rb_str_codepoints(
VALUE str)
11255 return rb_str_enumerate_codepoints(str, ary);
11261 int encidx = rb_enc_to_index(enc);
11263 const OnigUChar source_ascii[] =
"\\X";
11264 const OnigUChar *source = source_ascii;
11265 size_t source_len =
sizeof(source_ascii) - 1;
11268#define CHARS_16BE(x) (OnigUChar)((x)>>8), (OnigUChar)(x)
11269#define CHARS_16LE(x) (OnigUChar)(x), (OnigUChar)((x)>>8)
11270#define CHARS_32BE(x) CHARS_16BE((x)>>16), CHARS_16BE(x)
11271#define CHARS_32LE(x) CHARS_16LE(x), CHARS_16LE((x)>>16)
11272#define CASE_UTF(e) \
11273 case ENCINDEX_UTF_##e: { \
11274 static const OnigUChar source_UTF_##e[] = {CHARS_##e('\\'), CHARS_##e('X')}; \
11275 source = source_UTF_##e; \
11276 source_len = sizeof(source_UTF_##e); \
11279 CASE_UTF(16BE); CASE_UTF(16LE); CASE_UTF(32BE); CASE_UTF(32LE);
11287 regex_t *reg_grapheme_cluster;
11289 int r = onig_new(®_grapheme_cluster, source, source + source_len,
11290 ONIG_OPTION_DEFAULT, enc, OnigDefaultSyntax, &einfo);
11292 UChar message[ONIG_MAX_ERROR_MESSAGE_LEN];
11293 onig_error_code_to_str(message, r, &einfo);
11294 rb_fatal(
"cannot compile grapheme cluster regexp: %s", (
char *)message);
11297 return reg_grapheme_cluster;
11303 int encidx = rb_enc_to_index(enc);
11304 static regex_t *reg_grapheme_cluster_utf8 = NULL;
11306 if (encidx == rb_utf8_encindex()) {
11307 if (!reg_grapheme_cluster_utf8) {
11308 reg_grapheme_cluster_utf8 = get_reg_grapheme_cluster(enc);
11311 return reg_grapheme_cluster_utf8;
11320 size_t grapheme_cluster_count = 0;
11322 const char *ptr, *end;
11324 if (!rb_enc_unicode_p(enc)) {
11328 bool cached_reg_grapheme_cluster =
true;
11329 regex_t *reg_grapheme_cluster = get_cached_reg_grapheme_cluster(enc);
11330 if (!reg_grapheme_cluster) {
11331 reg_grapheme_cluster = get_reg_grapheme_cluster(enc);
11332 cached_reg_grapheme_cluster =
false;
11335 ptr = RSTRING_PTR(str);
11338 while (ptr < end) {
11339 OnigPosition
len = onig_match(reg_grapheme_cluster,
11340 (
const OnigUChar *)ptr, (
const OnigUChar *)end,
11341 (
const OnigUChar *)ptr, NULL, 0);
11342 if (
len <= 0)
break;
11343 grapheme_cluster_count++;
11347 if (!cached_reg_grapheme_cluster) {
11348 onig_free(reg_grapheme_cluster);
11351 return SIZET2NUM(grapheme_cluster_count);
11355rb_str_enumerate_grapheme_clusters(
VALUE str,
VALUE ary)
11359 const char *ptr0, *ptr, *end;
11361 if (!rb_enc_unicode_p(enc)) {
11362 return rb_str_enumerate_chars(str, ary);
11367 bool cached_reg_grapheme_cluster =
true;
11368 regex_t *reg_grapheme_cluster = get_cached_reg_grapheme_cluster(enc);
11369 if (!reg_grapheme_cluster) {
11370 reg_grapheme_cluster = get_reg_grapheme_cluster(enc);
11371 cached_reg_grapheme_cluster =
false;
11374 ptr0 = ptr = RSTRING_PTR(str);
11377 while (ptr < end) {
11378 OnigPosition
len = onig_match(reg_grapheme_cluster,
11379 (
const OnigUChar *)ptr, (
const OnigUChar *)end,
11380 (
const OnigUChar *)ptr, NULL, 0);
11381 if (
len <= 0)
break;
11386 if (!cached_reg_grapheme_cluster) {
11387 onig_free(reg_grapheme_cluster);
11407rb_str_each_grapheme_cluster(
VALUE str)
11410 return rb_str_enumerate_grapheme_clusters(str, 0);
11422rb_str_grapheme_clusters(
VALUE str)
11425 return rb_str_enumerate_grapheme_clusters(str, ary);
11429chopped_length(
VALUE str)
11432 const char *p, *p2, *beg, *end;
11434 beg = RSTRING_PTR(str);
11435 end = beg + RSTRING_LEN(str);
11436 if (beg >= end)
return 0;
11437 p = rb_enc_prev_char(beg, end, end, enc);
11439 if (p > beg && rb_enc_ascget(p, end, 0, enc) ==
'\n') {
11440 p2 = rb_enc_prev_char(beg, p, end, enc);
11441 if (p2 && rb_enc_ascget(p2, end, 0, enc) ==
'\r') p = p2;
11459rb_str_chop_bang(
VALUE str)
11461 str_modify_keep_cr(str);
11462 if (RSTRING_LEN(str) > 0) {
11464 len = chopped_length(str);
11465 STR_SET_LEN(str,
len);
11466 TERM_FILL(&RSTRING_PTR(str)[
len], TERM_LEN(str));
11485rb_str_chop(
VALUE str)
11491smart_chomp(
VALUE str,
const char *e,
const char *p)
11494 if (rb_enc_mbminlen(enc) > 1) {
11496 if (e - p < rb_enc_mbminlen(enc))
return e - p;
11501 pp = e - rb_enc_mbminlen(enc);
11504 if (rb_enc_ascget(pp, e, 0, enc) ==
'\r') {
11512 if (--e > p && *(e-1) ==
'\r') {
11529 const char *pp, *e, *rsptr;
11531 const char *
const p = RSTRING_PTR(str);
11532 long len = RSTRING_LEN(str);
11534 if (
len == 0)
return 0;
11537 return smart_chomp(str, e, p);
11540 enc = rb_enc_get(str);
11543 if (rb_enc_mbminlen(enc) > 1) {
11544 while (e - p >= rb_enc_mbminlen(enc)) {
11548 pp -= rb_enc_mbminlen(enc);
11551 if (rb_enc_ascget(pp, e, 0, enc) ==
'\r') {
11558 while (e > p && *(e-1) ==
'\n') {
11560 if (e > p && *(e-1) ==
'\r')
11566 if (rslen >
len)
return len;
11568 enc = rb_enc_get(rs);
11569 newline = rsptr[rslen-1];
11570 if (rslen == rb_enc_mbminlen(enc)) {
11572 if (newline ==
'\n')
11573 return smart_chomp(str, e, p);
11577 return smart_chomp(str, e, p);
11581 enc = rb_enc_check(str, rs);
11582 if (is_broken_string(rs)) {
11586 if (p[
len-1] == newline &&
11588 memcmp(rsptr, pp, rslen) == 0)) {
11589 if (at_char_boundary(p, pp, e, enc))
11590 return len - rslen;
11602chomp_rs(
int argc,
const VALUE *argv)
11606 VALUE rs = argv[0];
11618 str_modify_keep_cr(str);
11619 STR_SET_LEN(str,
len);
11620 TERM_FILL(&RSTRING_PTR(str)[
len], TERM_LEN(str));
11630 long olen = RSTRING_LEN(str);
11631 long len = chompped_length(str, rs);
11632 if (
len >= olen)
return Qnil;
11633 return str_shrink(str,
len);
11649rb_str_chomp_bang(
int argc,
VALUE *argv,
VALUE str)
11652 str_modifiable(str);
11653 if (RSTRING_LEN(str) == 0 && argc < 2)
return Qnil;
11654 rs = chomp_rs(argc, argv);
11656 return rb_str_chomp_string(str, rs);
11669rb_str_chomp(
int argc,
VALUE *argv,
VALUE str)
11671 VALUE rs = chomp_rs(argc, argv);
11677tr_setup_table_multi(
char table[TR_TABLE_SIZE],
VALUE *tablep,
VALUE *ctablep,
11678 VALUE str,
int num_selectors,
VALUE *selectors)
11682 for (i=0; i<num_selectors; i++) {
11683 VALUE selector = selectors[i];
11687 enc = rb_enc_check(str, selector);
11688 tr_setup_table(selector, table, i==0, tablep, ctablep, enc);
11695 const char *
const start = s;
11697 if (!s || s >= e)
return 0;
11700 if (single_byte_optimizable(str)) {
11701 while (s < e && (*s ==
'\0' || ascii_isspace(*s))) s++;
11706 unsigned int cc = rb_enc_codepoint_len(s, e, &n, enc);
11716lstrip_offset_table(
VALUE str,
const char *s,
const char *e,
rb_encoding *enc,
11717 char table[TR_TABLE_SIZE],
VALUE del,
VALUE nodel)
11719 const char *
const start = s;
11721 if (!s || s >= e)
return 0;
11726 unsigned int cc = rb_enc_codepoint_len(s, e, &n, enc);
11728 if (!tr_find(cc, table, del, nodel))
break;
11747rb_str_lstrip_bang(
int argc,
VALUE *argv,
VALUE str)
11751 long olen, loffset;
11753 str_modify_keep_cr(str);
11754 enc = STR_ENC_GET(str);
11757 char table[TR_TABLE_SIZE];
11758 VALUE del = 0, nodel = 0;
11760 tr_setup_table_multi(table, &del, &nodel, str, argc, argv);
11763 str_modify_keep_cr(str);
11764 enc = STR_ENC_GET(str);
11767 loffset = lstrip_offset_table(str, start, start+olen, enc, table, del, nodel);
11770 loffset = lstrip_offset(str, start, start+olen, enc);
11774 long len = olen-loffset;
11775 memmove(start, start + loffset,
len);
11776 STR_SET_LEN(str,
len);
11777 TERM_FILL(start+
len, rb_enc_mbminlen(enc));
11812rb_str_lstrip(
int argc,
VALUE *argv,
VALUE str)
11819 char table[TR_TABLE_SIZE];
11820 VALUE del = 0, nodel = 0;
11822 tr_setup_table_multi(table, &del, &nodel, str, argc, argv);
11827 loffset = lstrip_offset_table(str, start, start+
len, STR_ENC_GET(str), table, del, nodel);
11830 loffset = lstrip_offset(str, start, start+
len, STR_ENC_GET(str));
11832 if (loffset <= 0)
return str_duplicate(
rb_cString, str);
11841 rb_str_check_dummy_enc(enc);
11845 if (!s || s >= e)
return 0;
11849 if (single_byte_optimizable(str)) {
11851 while (s < t && ((c = *(t-1)) ==
'\0' || ascii_isspace(c))) t--;
11856 while ((tp = rb_enc_prev_char(s, t, e, enc)) != NULL) {
11866rstrip_offset_table(
VALUE str,
const char *s,
const char *e,
rb_encoding *enc,
11867 char table[TR_TABLE_SIZE],
VALUE del,
VALUE nodel)
11869 const char *t, *tp;
11871 rb_str_check_dummy_enc(enc);
11875 if (!s || s >= e)
return 0;
11879 while ((tp = rb_enc_prev_char(s, t, e, enc)) != NULL) {
11881 if (!tr_find(c, table, del, nodel))
break;
11901rb_str_rstrip_bang(
int argc,
VALUE *argv,
VALUE str)
11905 long olen, roffset;
11907 str_modify_keep_cr(str);
11908 enc = STR_ENC_GET(str);
11911 char table[TR_TABLE_SIZE];
11912 VALUE del = 0, nodel = 0;
11914 tr_setup_table_multi(table, &del, &nodel, str, argc, argv);
11917 str_modify_keep_cr(str);
11918 enc = STR_ENC_GET(str);
11921 roffset = rstrip_offset_table(str, start, start+olen, enc, table, del, nodel);
11924 roffset = rstrip_offset(str, start, start+olen, enc);
11927 long len = olen - roffset;
11929 STR_SET_LEN(str,
len);
11930 TERM_FILL(start+
len, rb_enc_mbminlen(enc));
11964rb_str_rstrip(
int argc,
VALUE *argv,
VALUE str)
11968 long olen, roffset;
11970 enc = STR_ENC_GET(str);
11973 char table[TR_TABLE_SIZE];
11974 VALUE del = 0, nodel = 0;
11976 tr_setup_table_multi(table, &del, &nodel, str, argc, argv);
11979 enc = STR_ENC_GET(str);
11982 roffset = rstrip_offset_table(str, start, start+olen, enc, table, del, nodel);
11985 roffset = rstrip_offset(str, start, start+olen, enc);
11987 if (roffset <= 0)
return str_duplicate(
rb_cString, str);
12005rb_str_strip_bang(
int argc,
VALUE *argv,
VALUE str)
12008 long olen, loffset, roffset;
12011 str_modify_keep_cr(str);
12012 enc = STR_ENC_GET(str);
12016 char table[TR_TABLE_SIZE];
12017 VALUE del = 0, nodel = 0;
12019 tr_setup_table_multi(table, &del, &nodel, str, argc, argv);
12022 str_modify_keep_cr(str);
12023 enc = STR_ENC_GET(str);
12026 loffset = lstrip_offset_table(str, start, start+olen, enc, table, del, nodel);
12027 roffset = rstrip_offset_table(str, start+loffset, start+olen, enc, table, del, nodel);
12030 loffset = lstrip_offset(str, start, start+olen, enc);
12031 roffset = rstrip_offset(str, start+loffset, start+olen, enc);
12034 if (loffset > 0 || roffset > 0) {
12035 long len = olen-roffset;
12038 memmove(start, start + loffset,
len);
12040 STR_SET_LEN(str,
len);
12041 TERM_FILL(start+
len, rb_enc_mbminlen(enc));
12076rb_str_strip(
int argc,
VALUE *argv,
VALUE str)
12079 long olen, loffset, roffset;
12085 char table[TR_TABLE_SIZE];
12086 VALUE del = 0, nodel = 0;
12088 tr_setup_table_multi(table, &del, &nodel, str, argc, argv);
12091 enc = STR_ENC_GET(str);
12094 loffset = lstrip_offset_table(str, start, start+olen, enc, table, del, nodel);
12095 roffset = rstrip_offset_table(str, start+loffset, start+olen, enc, table, del, nodel);
12098 loffset = lstrip_offset(str, start, start+olen, enc);
12099 roffset = rstrip_offset(str, start+loffset, start+olen, enc);
12102 if (loffset <= 0 && roffset <= 0)
return str_duplicate(
rb_cString, str);
12107scan_once(
VALUE str,
VALUE pat,
long *start,
int set_backref_str)
12110 long end, pos = rb_pat_search(pat, str, *start, set_backref_str);
12114 end = pos + RSTRING_LEN(pat);
12118 pos = RMATCH_BEG(match, 0);
12119 end = RMATCH_END(match, 0);
12127 if (RSTRING_LEN(str) > end)
12128 *start = end + rb_enc_fast_mbclen(RSTRING_PTR(str) + end,
12137 if (
NIL_P(match) || RMATCH_NREGS(match) == 1) {
12142 int num_regs = RMATCH_NREGS(match);
12144 for (
int i = 1; i < num_regs; i++) {
12146 if (RMATCH_BEG(match, i) >= 0) {
12147 s =
rb_str_subseq(str, RMATCH_BEG(match, i), RMATCH_END(match, i) - RMATCH_BEG(match, i));
12175 long last = -1, prev = 0;
12176 const char *p = RSTRING_PTR(str);
12177 long len = RSTRING_LEN(str);
12179 pat = get_pat_quoted(pat, 1);
12180 mustnot_broken(str);
12184 while (!
NIL_P(result = scan_once(str, pat, &start, 0))) {
12189 if (last >= 0) rb_pat_search(pat, str, last, 1);
12194 while (!
NIL_P(result = scan_once(str, pat, &start, 1))) {
12198 str_mod_check(str, p,
len);
12200 if (last >= 0) rb_pat_search(pat, str, last, 1);
12252rb_str_hex(
VALUE str)
12254 return rb_str_to_inum(str, 16, FALSE);
12338rb_str_oct(
VALUE str)
12340 return rb_str_to_inum(str, -8, FALSE);
12343#ifndef HAVE_CRYPT_R
12348 rb_nativethread_lock_t lock;
12349} crypt_mutex = {PTHREAD_MUTEX_INITIALIZER};
12418# define CRYPT_END() ALLOCV_END(databuf)
12421 extern char *crypt(
const char *,
const char *);
12422# define CRYPT_END() rb_nativethread_lock_unlock(&crypt_mutex.lock)
12425 const char *s, *saltp, *res;
12427 char salt_8bit_clean[3];
12431 mustnot_wchar(str);
12432 mustnot_wchar(salt);
12434 saltp = RSTRING_PTR(salt);
12435 if (RSTRING_LEN(salt) < 2 || !saltp[0] || !saltp[1]) {
12436 rb_raise(rb_eArgError,
"salt too short (need >=2 bytes)");
12440 if (!
ISASCII((
unsigned char)saltp[0]) || !
ISASCII((
unsigned char)saltp[1])) {
12441 salt_8bit_clean[0] = saltp[0] & 0x7f;
12442 salt_8bit_clean[1] = saltp[1] & 0x7f;
12443 salt_8bit_clean[2] =
'\0';
12444 saltp = salt_8bit_clean;
12449# ifdef HAVE_STRUCT_CRYPT_DATA_INITIALIZED
12450 data->initialized = 0;
12452 res = crypt_r(s, saltp, data);
12455 res = crypt(s, saltp);
12470 size_t res_size = strlen(res);
12471 tmp_buf =
ALLOCA_N(
char, res_size);
12472 memcpy(tmp_buf, res, res_size);
12508 char *ptr, *p, *pend;
12511 unsigned long sum0 = 0;
12516 ptr = p = RSTRING_PTR(str);
12517 len = RSTRING_LEN(str);
12523 str_mod_check(str, ptr,
len);
12526 sum0 += (
unsigned char)*p;
12537 if (bits < (
int)
sizeof(
long)*CHAR_BIT) {
12538 sum0 &= (((
unsigned long)1)<<bits)-1;
12558rb_str_justify(
int argc,
VALUE *argv,
VALUE str,
char jflag)
12562 long width,
len, flen = 1, fclen = 1;
12565 const char *f =
" ";
12566 long n, size, llen, rlen, llen2 = 0, rlen2 = 0;
12568 int singlebyte = 1, cr;
12572 enc = STR_ENC_GET(str);
12576 enc = rb_enc_check(str, pad);
12577 f = RSTRING_PTR(pad);
12578 flen = RSTRING_LEN(pad);
12579 fclen = str_strlen(pad, enc);
12580 singlebyte = single_byte_optimizable(pad);
12581 if (flen == 0 || fclen == 0) {
12582 rb_raise(rb_eArgError,
"zero width padding");
12585 termlen = rb_enc_mbminlen(enc);
12586 len = str_strlen(str, enc);
12587 if (width < 0 || len >= width)
return str_duplicate(
rb_cString, str);
12589 llen = (jflag ==
'l') ? 0 : ((jflag ==
'r') ? n : n/2);
12593 llen2 = str_offset(f, f + flen, llen % fclen, enc, singlebyte);
12594 rlen2 = str_offset(f, f + flen, rlen % fclen, enc, singlebyte);
12596 size = RSTRING_LEN(str);
12597 if ((
len = llen / fclen + rlen / fclen) >= LONG_MAX / flen ||
12598 (
len *= flen) >= LONG_MAX - llen2 - rlen2 ||
12599 (
len += llen2 + rlen2) >= LONG_MAX - size) {
12600 rb_raise(rb_eArgError,
"argument too big");
12604 p = RSTRING_PTR(res);
12606 memset(p, *f, llen);
12610 while (llen >= fclen) {
12616 memcpy(p, f, llen2);
12620 memcpy(p, RSTRING_PTR(str), size);
12623 memset(p, *f, rlen);
12627 while (rlen >= fclen) {
12633 memcpy(p, f, rlen2);
12637 TERM_FILL(p, termlen);
12638 STR_SET_LEN(res, p-RSTRING_PTR(res));
12659rb_str_ljust(
int argc,
VALUE *argv,
VALUE str)
12661 return rb_str_justify(argc, argv, str,
'l');
12673rb_str_rjust(
int argc,
VALUE *argv,
VALUE str)
12675 return rb_str_justify(argc, argv, str,
'r');
12688rb_str_center(
int argc,
VALUE *argv,
VALUE str)
12690 return rb_str_justify(argc, argv, str,
'c');
12706 sep = get_pat_quoted(sep, 0);
12713 pos = RMATCH_BEG(match, 0);
12717 pos = rb_str_index(str, sep, 0);
12718 if (pos < 0)
goto failed;
12721 long rpos = pos + RSTRING_LEN(sep);
12722 if (rpos > RSTRING_LEN(str))
goto failed;
12728 return rb_ary_new3(3, str_duplicate(
rb_cString, str), str_new_empty_String(str), str_new_empty_String(str));
12744 sep = get_pat_quoted(sep, 0);
12746 pos = RSTRING_LEN(str);
12752 pos = RMATCH_BEG(match, 0);
12758 pos = rb_str_rindex(str, sep, pos);
12764 long rpos = pos + RSTRING_LEN(sep);
12765 if (rpos > RSTRING_LEN(str))
goto failed;
12770 return rb_ary_new3(3, str_new_empty_String(str), str_new_empty_String(str), str_duplicate(
rb_cString, str));
12782rb_str_start_with(
int argc,
VALUE *argv,
VALUE str)
12786 for (i=0; i<argc; i++) {
12787 VALUE tmp = argv[i];
12789 if (rb_reg_start_with_p(tmp, str))
12793 const char *p, *s, *e;
12798 enc = rb_enc_check(str, tmp);
12799 if ((tlen = RSTRING_LEN(tmp)) == 0)
return Qtrue;
12800 if ((slen = RSTRING_LEN(str)) < tlen)
continue;
12801 p = RSTRING_PTR(str);
12804 if (!at_char_right_boundary(p, s, e, enc))
12806 if (memcmp(p, RSTRING_PTR(tmp), tlen) == 0)
12822rb_str_end_with(
int argc,
VALUE *argv,
VALUE str)
12826 for (i=0; i<argc; i++) {
12827 VALUE tmp = argv[i];
12828 const char *p, *s, *e;
12833 enc = rb_enc_check(str, tmp);
12834 if ((tlen = RSTRING_LEN(tmp)) == 0)
return Qtrue;
12835 if ((slen = RSTRING_LEN(str)) < tlen)
continue;
12836 p = RSTRING_PTR(str);
12839 if (!at_char_boundary(p, s, e, enc))
12841 if (memcmp(s, RSTRING_PTR(tmp), tlen) == 0)
12857deleted_prefix_length(
VALUE str,
VALUE prefix)
12859 const char *strptr, *prefixptr;
12860 long olen, prefixlen;
12865 if (!is_broken_string(prefix) ||
12866 !rb_enc_asciicompat(enc) ||
12867 !rb_enc_asciicompat(rb_enc_get(prefix))) {
12868 enc = rb_enc_check(str, prefix);
12872 prefixlen = RSTRING_LEN(prefix);
12873 if (prefixlen <= 0)
return 0;
12874 olen = RSTRING_LEN(str);
12875 if (olen < prefixlen)
return 0;
12876 strptr = RSTRING_PTR(str);
12877 prefixptr = RSTRING_PTR(prefix);
12878 if (memcmp(strptr, prefixptr, prefixlen) != 0)
return 0;
12879 if (is_broken_string(prefix)) {
12880 if (!is_broken_string(str)) {
12884 const char *strend = strptr + olen;
12885 const char *after_prefix = strptr + prefixlen;
12886 if (!at_char_right_boundary(strptr, after_prefix, strend, enc)) {
12907rb_str_delete_prefix_bang(
VALUE str,
VALUE prefix)
12910 str_modify_keep_cr(str);
12912 prefixlen = deleted_prefix_length(str, prefix);
12913 if (prefixlen <= 0)
return Qnil;
12927rb_str_delete_prefix(
VALUE str,
VALUE prefix)
12931 prefixlen = deleted_prefix_length(str, prefix);
12932 if (prefixlen <= 0)
return str_duplicate(
rb_cString, str);
12934 return rb_str_subseq(str, prefixlen, RSTRING_LEN(str) - prefixlen);
12947deleted_suffix_length(
VALUE str,
VALUE suffix)
12949 const char *strptr, *suffixptr;
12950 long olen, suffixlen;
12954 if (is_broken_string(suffix))
return 0;
12955 enc = rb_enc_check(str, suffix);
12958 suffixlen = RSTRING_LEN(suffix);
12959 if (suffixlen <= 0)
return 0;
12960 olen = RSTRING_LEN(str);
12961 if (olen < suffixlen)
return 0;
12962 strptr = RSTRING_PTR(str);
12963 suffixptr = RSTRING_PTR(suffix);
12964 const char *strend = strptr + olen;
12965 const char *before_suffix = strend - suffixlen;
12966 if (memcmp(before_suffix, suffixptr, suffixlen) != 0)
return 0;
12967 if (!at_char_boundary(strptr, before_suffix, strend, enc))
return 0;
12983rb_str_delete_suffix_bang(
VALUE str,
VALUE suffix)
12986 str_modifiable(str);
12988 suffixlen = deleted_suffix_length(str, suffix);
12989 if (suffixlen <= 0)
return Qnil;
12991 return str_shrink(str, RSTRING_LEN(str) - suffixlen);
13003rb_str_delete_suffix(
VALUE str,
VALUE suffix)
13007 suffixlen = deleted_suffix_length(str, suffix);
13008 if (suffixlen <= 0)
return str_duplicate(
rb_cString, str);
13010 return rb_str_subseq(str, 0, RSTRING_LEN(str) - suffixlen);
13017 rb_raise(
rb_eTypeError,
"value of %"PRIsVALUE
" must be String", rb_id2str(
id));
13023nil_setter_warning(
ID id)
13025 rb_warn_deprecated(
"non-nil '%"PRIsVALUE
"'", NULL, rb_id2str(
id));
13032 if (!
NIL_P(*var)) {
13033 nil_setter_warning(
id);
13040 val = rb_fs_check(val);
13043 "value of %"PRIsVALUE
" must be String or Regexp",
13047 nil_setter_warning(
id);
13064 str_modifiable(str);
13067 int idx = rb_enc_to_index(encoding);
13074 rb_enc_associate_index(str, idx);
13098 if (STR_EMBED_P(str)) {
13099 str2 = str_alloc_embed(
rb_cString, RSTRING_LEN(str) + TERM_LEN(str));
13104 str_replace_shared_without_enc(str2, str);
13106 if (rb_enc_asciicompat(STR_ENC_GET(str))) {
13129rb_str_valid_encoding_p(
VALUE str)
13131 int cr = rb_enc_str_coderange(str);
13138rb_str_is_ascii_only_p(
VALUE str)
13140 int cr = rb_enc_str_coderange(str);
13148 static const char ellipsis[] =
"...";
13149 const long ellipsislen =
sizeof(ellipsis) - 1;
13151 const long blen = RSTRING_LEN(str);
13152 const char *
const p = RSTRING_PTR(str), *e = p + blen;
13153 VALUE estr, ret = 0;
13156 if (
len * rb_enc_mbminlen(enc) >= blen ||
13160 else if (
len <= ellipsislen ||
13162 if (rb_enc_asciicompat(enc)) {
13164 rb_enc_associate(ret, enc);
13171 else if (ret =
rb_str_subseq(str, 0, e - p), rb_enc_asciicompat(enc)) {
13176 rb_enc_from_encoding(enc), 0,
Qnil);
13187 cr = rb_enc_str_coderange(str);
13189 rb_raise(rb_eArgError,
"replacement must be valid byte sequence '%+"PRIsVALUE
"'", str);
13195 rb_enc_inspect_name(enc), rb_enc_inspect_name(e));
13214 if (enc == STR_ENC_GET(str)) {
13219 return enc_str_scrub(enc, str, repl, cr);
13227 const char *rep, *p, *e, *p1, *sp;
13233 rb_raise(rb_eArgError,
"both of block and replacement given");
13240 if (!
NIL_P(repl)) {
13241 repl = str_compat_and_valid(repl, enc);
13244 if (rb_enc_dummy_p(enc)) {
13247 encidx = rb_enc_to_index(enc);
13249#define DEFAULT_REPLACE_CHAR(str) do { \
13250 RBIMPL_ATTR_NONSTRING() static const char replace[sizeof(str)-1] = str; \
13251 rep = replace; replen = (int)sizeof(replace); \
13254 slen = RSTRING_LEN(str);
13255 p = RSTRING_PTR(str);
13260 if (rb_enc_asciicompat(enc)) {
13266 else if (!
NIL_P(repl)) {
13267 rep = RSTRING_PTR(repl);
13268 replen = RSTRING_LEN(repl);
13271 else if (encidx == rb_utf8_encindex()) {
13272 DEFAULT_REPLACE_CHAR(
"\xEF\xBF\xBD");
13276 DEFAULT_REPLACE_CHAR(
"?");
13281 p = search_nonascii(p, e);
13286 int ret = rb_enc_precise_mbclen(p, e, enc);
13294 p = search_nonascii(p, e);
13311 if (e - p < clen) clen = e - p;
13318 for (; clen > 1; clen--) {
13319 ret = rb_enc_precise_mbclen(q, q + clen, enc);
13330 repl =
rb_yield(rb_enc_str_new(p, clen, enc));
13331 str_mod_check(str, sp, slen);
13332 repl = str_compat_and_valid(repl, enc);
13339 p = search_nonascii(p, e);
13365 repl =
rb_yield(rb_enc_str_new(p, e-p, enc));
13366 str_mod_check(str, sp, slen);
13367 repl = str_compat_and_valid(repl, enc);
13376 long mbminlen = rb_enc_mbminlen(enc);
13380 else if (!
NIL_P(repl)) {
13381 rep = RSTRING_PTR(repl);
13382 replen = RSTRING_LEN(repl);
13384 else if (encidx == ENCINDEX_UTF_16BE) {
13385 DEFAULT_REPLACE_CHAR(
"\xFF\xFD");
13387 else if (encidx == ENCINDEX_UTF_16LE) {
13388 DEFAULT_REPLACE_CHAR(
"\xFD\xFF");
13390 else if (encidx == ENCINDEX_UTF_32BE) {
13391 DEFAULT_REPLACE_CHAR(
"\x00\x00\xFF\xFD");
13393 else if (encidx == ENCINDEX_UTF_32LE) {
13394 DEFAULT_REPLACE_CHAR(
"\xFD\xFF\x00\x00");
13397 DEFAULT_REPLACE_CHAR(
"?");
13401 int ret = rb_enc_precise_mbclen(p, e, enc);
13414 if (e - p < clen) clen = e - p;
13415 if (clen <= mbminlen * 2) {
13420 for (; clen > mbminlen; clen-=mbminlen) {
13421 ret = rb_enc_precise_mbclen(q, q + clen, enc);
13431 repl =
rb_yield(rb_enc_str_new(p, clen, enc));
13432 str_mod_check(str, sp, slen);
13433 repl = str_compat_and_valid(repl, enc);
13458 repl =
rb_yield(rb_enc_str_new(p, e-p, enc));
13459 str_mod_check(str, sp, slen);
13460 repl = str_compat_and_valid(repl, enc);
13500str_scrub_bang(
int argc,
VALUE *argv,
VALUE str)
13508static ID id_normalize;
13509static ID id_normalized_p;
13510static VALUE mUnicodeNormalize;
13513unicode_normalize_common(
int argc,
VALUE *argv,
VALUE str,
ID id)
13515 static int UnicodeNormalizeRequired = 0;
13518 if (!UnicodeNormalizeRequired) {
13519 rb_require(
"unicode_normalize/normalize.rb");
13520 UnicodeNormalizeRequired = 1;
13524 return rb_funcallv(mUnicodeNormalize,
id, argc+1, argv2);
13535rb_str_unicode_normalize(
int argc,
VALUE *argv,
VALUE str)
13537 return unicode_normalize_common(argc, argv, str, id_normalize);
13551rb_str_unicode_normalize_bang(
int argc,
VALUE *argv,
VALUE str)
13553 return rb_str_replace(str, unicode_normalize_common(argc, argv, str, id_normalize));
13580rb_str_unicode_normalized_p(
int argc,
VALUE *argv,
VALUE str)
13582 return unicode_normalize_common(argc, argv, str, id_normalized_p);
13714#define sym_equal rb_obj_equal
13717sym_printable(
const char *s,
const char *send,
rb_encoding *enc)
13721 int c = rb_enc_precise_mbclen(s, send, enc);
13725 c = rb_enc_mbc_to_codepoint(s, send, enc);
13733rb_str_symname_p(
VALUE sym)
13738 rb_encoding *resenc = rb_default_internal_encoding();
13740 if (resenc == NULL) resenc = rb_default_external_encoding();
13741 enc = STR_ENC_GET(sym);
13742 ptr = RSTRING_PTR(sym);
13743 len = RSTRING_LEN(sym);
13744 if ((resenc != enc && !rb_str_is_ascii_only_p(sym)) ||
len != (
long)strlen(ptr) ||
13752rb_str_quote_unprintable(
VALUE str)
13760 resenc = rb_default_internal_encoding();
13761 if (resenc == NULL) resenc = rb_default_external_encoding();
13762 enc = STR_ENC_GET(str);
13763 ptr = RSTRING_PTR(str);
13764 len = RSTRING_LEN(str);
13765 if ((resenc != enc && !rb_str_is_ascii_only_p(str)) ||
13766 !sym_printable(ptr, ptr +
len, enc)) {
13767 return rb_str_escape(str);
13773rb_id_quote_unprintable(
ID id)
13775 VALUE str = rb_id2str(
id);
13776 if (!rb_str_symname_p(str)) {
13777 return rb_str_escape(str);
13795sym_inspect(
VALUE sym)
13802 if (!rb_str_symname_p(str)) {
13804 len = RSTRING_LEN(str);
13805 rb_str_resize(str,
len + 1);
13806 dest = RSTRING_PTR(str);
13807 memmove(dest + 1, dest,
len);
13811 VALUE orig_str = str;
13813 len = RSTRING_LEN(orig_str);
13814 str = rb_enc_str_new(0,
len + 1, enc);
13817 ptr = RSTRING_PTR(orig_str);
13818 dest = RSTRING_PTR(str);
13819 memcpy(dest + 1, ptr,
len);
13837rb_sym_proc_call(
ID mid,
int argc,
const VALUE *argv,
int kw_splat,
VALUE passed_proc)
13842 rb_raise(rb_eArgError,
"no receiver given");
13945 return rb_str_match(
rb_sym2str(sym), other);
13960sym_match_m(
int argc,
VALUE *argv,
VALUE sym)
13962 return rb_str_match_m(argc, argv,
rb_sym2str(sym));
13975sym_match_m_p(
int argc,
VALUE *argv,
VALUE sym)
13977 return rb_str_match_m_p(argc, argv, sym);
13995 return rb_str_aref_m(argc, argv,
rb_sym2str(sym));
14006sym_length(
VALUE sym)
14040sym_downcase(
int argc,
VALUE *argv,
VALUE sym)
14056sym_capitalize(
int argc,
VALUE *argv,
VALUE sym)
14072sym_swapcase(
int argc,
VALUE *argv,
VALUE sym)
14086sym_start_with(
int argc,
VALUE *argv,
VALUE sym)
14088 return rb_str_start_with(argc, argv,
rb_sym2str(sym));
14101sym_end_with(
int argc,
VALUE *argv,
VALUE sym)
14103 return rb_str_end_with(argc, argv,
rb_sym2str(sym));
14115sym_encoding(
VALUE sym)
14121string_for_symbol(
VALUE name)
14126 rb_raise(
rb_eTypeError,
"%+"PRIsVALUE
" is not a symbol nor a string",
14140 name = string_for_symbol(name);
14141 return rb_intern_str(name);
14150 name = string_for_symbol(name);
14174 return rb_fstring(str);
14180 struct RString fake_str = {RBASIC_INIT};
14181 int encidx = ENCINDEX_US_ASCII;
14184 encidx = ENCINDEX_ASCII_8BIT;
14187 VALUE str = setup_fake_str(&fake_str,
ptr,
len, encidx);
14189 return register_fstring(str,
true,
false);
14201 if (enc != NULL && UNLIKELY(rb_enc_autoload_p(enc))) {
14202 rb_enc_autoload(enc);
14205 struct RString fake_str = {RBASIC_INIT};
14206 return register_fstring(rb_setup_fake_str(&fake_str,
ptr,
len, enc),
true,
false);
14212 if (enc != NULL && UNLIKELY(rb_enc_autoload_p(enc))) {
14213 rb_enc_autoload(enc);
14216 struct RString fake_str = {RBASIC_INIT};
14217 VALUE str = register_fstring(rb_setup_fake_str(&fake_str,
ptr,
len, enc),
true,
true);
14228#if USE_YJIT || USE_ZJIT
14230rb_jit_str_concat_codepoint(
VALUE str,
VALUE codepoint)
14235 if (RB_LIKELY(code >= 0 && code < 0xff)) {
14236 rb_str_buf_cat_byte(str, (
char) code);
14246fstring_set_class_i(
VALUE *str,
void *data)
14250 return ST_CONTINUE;
14258 rb_concurrent_set_foreach_with_replace(fstring_table_obj, fstring_set_class_i, NULL);
14426 mUnicodeNormalize = rb_define_module(
"UnicodeNormalize");
14437 rb_gc_register_address(&
rb_fs);
14475#include "string.rbinc"
#define RUBY_ASSERT_ALWAYS(expr,...)
A variant of RUBY_ASSERT that does not interface with RUBY_DEBUG.
#define RBIMPL_ASSERT_OR_ASSUME(...)
This is either RUBY_ASSERT or RBIMPL_ASSUME, depending on RUBY_DEBUG.
#define RUBY_ASSERT_BUILTIN_TYPE(obj, type)
A variant of RUBY_ASSERT that asserts when either RUBY_DEBUG or built-in type of obj is type.
#define RUBY_ASSERT(...)
Asserts that the given expression is truthy if and only if RUBY_DEBUG is truthy.
@ RUBY_ENC_CODERANGE_7BIT
The object holds 0 to 127 inclusive and nothing else.
static enum ruby_coderange_type RB_ENC_CODERANGE_AND(enum ruby_coderange_type a, enum ruby_coderange_type b)
"Mix" two code ranges into one.
static int rb_isspace(int c)
Our own locale-insensitive version of isspace(3).
static int rb_isascii(int c)
Our own locale-insensitive version of isascii(3).
#define rb_define_method(klass, mid, func, arity)
Defines klass#mid.
#define rb_define_singleton_method(klass, mid, func, arity)
Defines klass.mid.
static bool rb_enc_is_newline(const char *p, const char *e, rb_encoding *enc)
Queries if the passed pointer points to a newline character.
static bool rb_enc_isprint(OnigCodePoint c, rb_encoding *enc)
Identical to rb_isprint(), except it additionally takes an encoding.
static bool rb_enc_isctype(OnigCodePoint c, OnigCtype t, rb_encoding *enc)
Queries if the passed code point is of passed character type in the passed encoding.
VALUE rb_enc_sprintf(rb_encoding *enc, const char *fmt,...)
Identical to rb_sprintf(), except it additionally takes an encoding.
static VALUE RB_OBJ_FROZEN_RAW(VALUE obj)
This is an implementation detail of RB_OBJ_FROZEN().
static VALUE RB_FL_TEST_RAW(VALUE obj, VALUE flags)
This is an implementation detail of RB_FL_TEST().
void rb_include_module(VALUE klass, VALUE module)
Includes a module to a class.
void rb_define_alias(VALUE klass, const char *name1, const char *name2)
Defines an alias of a method.
void rb_undef_method(VALUE klass, const char *name)
Defines an undef of a method.
int rb_scan_args(int argc, const VALUE *argv, const char *fmt,...)
Retrieves argument from argc and argv to given VALUE references according to the format string.
int rb_block_given_p(void)
Determines if the current method is given a block.
int rb_get_kwargs(VALUE keyword_hash, const ID *table, int required, int optional, VALUE *values)
Keyword argument deconstructor.
#define TYPE(_)
Old name of rb_type.
#define ENCODING_SET_INLINED(obj, i)
Old name of RB_ENCODING_SET_INLINED.
#define RB_INTEGER_TYPE_P
Old name of rb_integer_type_p.
#define ENC_CODERANGE_7BIT
Old name of RUBY_ENC_CODERANGE_7BIT.
#define ENC_CODERANGE_VALID
Old name of RUBY_ENC_CODERANGE_VALID.
#define FL_UNSET_RAW
Old name of RB_FL_UNSET_RAW.
#define rb_str_buf_cat2
Old name of rb_usascii_str_new_cstr.
#define ALLOCV
Old name of RB_ALLOCV.
#define ISSPACE
Old name of rb_isspace.
#define T_STRING
Old name of RUBY_T_STRING.
#define ENC_CODERANGE_CLEAN_P(cr)
Old name of RB_ENC_CODERANGE_CLEAN_P.
#define ENC_CODERANGE_AND(a, b)
Old name of RB_ENC_CODERANGE_AND.
#define Qundef
Old name of RUBY_Qundef.
#define INT2FIX
Old name of RB_INT2FIX.
#define OBJ_FROZEN
Old name of RB_OBJ_FROZEN.
#define rb_str_cat2
Old name of rb_str_cat_cstr.
#define UNREACHABLE
Old name of RBIMPL_UNREACHABLE.
#define ID2SYM
Old name of RB_ID2SYM.
#define T_BIGNUM
Old name of RUBY_T_BIGNUM.
#define OBJ_FREEZE
Old name of RB_OBJ_FREEZE.
#define T_FIXNUM
Old name of RUBY_T_FIXNUM.
#define UNREACHABLE_RETURN
Old name of RBIMPL_UNREACHABLE_RETURN.
#define SYM2ID
Old name of RB_SYM2ID.
#define ENC_CODERANGE(obj)
Old name of RB_ENC_CODERANGE.
#define CLASS_OF
Old name of rb_class_of.
#define ENC_CODERANGE_UNKNOWN
Old name of RUBY_ENC_CODERANGE_UNKNOWN.
#define SIZET2NUM
Old name of RB_SIZE2NUM.
#define FIXABLE
Old name of RB_FIXABLE.
#define xmalloc
Old name of ruby_xmalloc.
#define ENCODING_GET(obj)
Old name of RB_ENCODING_GET.
#define LONG2FIX
Old name of RB_INT2FIX.
#define ISDIGIT
Old name of rb_isdigit.
#define ENC_CODERANGE_MASK
Old name of RUBY_ENC_CODERANGE_MASK.
#define ZALLOC_N
Old name of RB_ZALLOC_N.
#define T_HASH
Old name of RUBY_T_HASH.
#define ALLOC_N
Old name of RB_ALLOC_N.
#define MBCLEN_CHARFOUND_LEN(ret)
Old name of ONIGENC_MBCLEN_CHARFOUND_LEN.
#define FL_TEST_RAW
Old name of RB_FL_TEST_RAW.
#define FL_SET
Old name of RB_FL_SET.
#define rb_ary_new3
Old name of rb_ary_new_from_args.
#define ENCODING_INLINE_MAX
Old name of RUBY_ENCODING_INLINE_MAX.
#define LONG2NUM
Old name of RB_LONG2NUM.
#define FL_ANY_RAW
Old name of RB_FL_ANY_RAW.
#define ISALPHA
Old name of rb_isalpha.
#define MBCLEN_INVALID_P(ret)
Old name of ONIGENC_MBCLEN_INVALID_P.
#define ISASCII
Old name of rb_isascii.
#define ULL2NUM
Old name of RB_ULL2NUM.
#define TOLOWER
Old name of rb_tolower.
#define Qtrue
Old name of RUBY_Qtrue.
#define ST2FIX
Old name of RB_ST2FIX.
#define MBCLEN_NEEDMORE_P(ret)
Old name of ONIGENC_MBCLEN_NEEDMORE_P.
#define FIXNUM_MAX
Old name of RUBY_FIXNUM_MAX.
#define NUM2INT
Old name of RB_NUM2INT.
#define Qnil
Old name of RUBY_Qnil.
#define Qfalse
Old name of RUBY_Qfalse.
#define FIX2LONG
Old name of RB_FIX2LONG.
#define ENC_CODERANGE_BROKEN
Old name of RUBY_ENC_CODERANGE_BROKEN.
#define scan_hex(s, l, e)
Old name of ruby_scan_hex.
#define NIL_P
Old name of RB_NIL_P.
#define ALLOCV_N
Old name of RB_ALLOCV_N.
#define MBCLEN_CHARFOUND_P(ret)
Old name of ONIGENC_MBCLEN_CHARFOUND_P.
#define NUM2ULL
Old name of RB_NUM2ULL.
#define DBL2NUM
Old name of rb_float_new.
#define ISPRINT
Old name of rb_isprint.
#define BUILTIN_TYPE
Old name of RB_BUILTIN_TYPE.
#define ENCODING_SHIFT
Old name of RUBY_ENCODING_SHIFT.
#define FL_TEST
Old name of RB_FL_TEST.
#define FL_FREEZE
Old name of RUBY_FL_FREEZE.
#define NUM2LONG
Old name of RB_NUM2LONG.
#define ENCODING_GET_INLINED(obj)
Old name of RB_ENCODING_GET_INLINED.
#define ENC_CODERANGE_CLEAR(obj)
Old name of RB_ENC_CODERANGE_CLEAR.
#define FL_UNSET
Old name of RB_FL_UNSET.
#define UINT2NUM
Old name of RB_UINT2NUM.
#define ENCODING_IS_ASCII8BIT(obj)
Old name of RB_ENCODING_IS_ASCII8BIT.
#define FIXNUM_P
Old name of RB_FIXNUM_P.
#define CONST_ID
Old name of RUBY_CONST_ID.
#define rb_ary_new2
Old name of rb_ary_new_capa.
#define ENC_CODERANGE_SET(obj, cr)
Old name of RB_ENC_CODERANGE_SET.
#define ENCODING_CODERANGE_SET(obj, encindex, cr)
Old name of RB_ENCODING_CODERANGE_SET.
#define FL_SET_RAW
Old name of RB_FL_SET_RAW.
#define SYMBOL_P
Old name of RB_SYMBOL_P.
#define OBJ_FROZEN_RAW
Old name of RB_OBJ_FROZEN_RAW.
#define T_REGEXP
Old name of RUBY_T_REGEXP.
#define ENCODING_MASK
Old name of RUBY_ENCODING_MASK.
void rb_category_warn(rb_warning_category_t category, const char *fmt,...)
Identical to rb_category_warning(), except it reports unless $VERBOSE is nil.
void rb_exc_raise(VALUE mesg)
Raises an exception in the current thread.
void rb_syserr_fail(int e, const char *mesg)
Raises appropriate exception that represents a C errno.
VALUE rb_eRangeError
RangeError exception.
VALUE rb_eTypeError
TypeError exception.
VALUE rb_eEncCompatError
Encoding::CompatibilityError exception.
VALUE rb_eRuntimeError
RuntimeError exception.
VALUE rb_eIndexError
IndexError exception.
@ RB_WARN_CATEGORY_DEPRECATED
Warning is for deprecated features.
VALUE rb_cObject
Object class.
VALUE rb_any_to_s(VALUE obj)
Generates a textual representation of the given object.
VALUE rb_obj_alloc(VALUE klass)
Allocates an instance of the given class.
VALUE rb_obj_hide(VALUE obj)
Make the object invisible from Ruby code.
VALUE rb_class_new_instance_pass_kw(int argc, const VALUE *argv, VALUE klass)
Identical to rb_class_new_instance(), except it passes the passed keywords if any to the #initialize ...
VALUE rb_obj_frozen_p(VALUE obj)
Same as RB_OBJ_FROZEN(), but returns Qtrue/Qfalse instead of #bool.
double rb_str_to_dbl(VALUE str, int mode)
Identical to rb_cstr_to_dbl(), except it accepts a Ruby's string instead of C's.
VALUE rb_obj_class(VALUE obj)
Queries the class of an object.
VALUE rb_obj_dup(VALUE obj)
Duplicates the given object.
VALUE rb_cSymbol
Symbol class.
VALUE rb_cRange
Range class.
VALUE rb_equal(VALUE lhs, VALUE rhs)
This function is an optimised version of calling #==.
VALUE rb_obj_is_kind_of(VALUE obj, VALUE klass)
Queries if the given object is an instance (of possibly descendants) of the given class.
VALUE rb_obj_freeze(VALUE obj)
Same as RB_OBJ_FREEZE(), but returns the given object.
VALUE rb_mComparable
Comparable module.
VALUE rb_cString
String class.
VALUE rb_to_int(VALUE val)
Identical to rb_check_to_int(), except it raises in case of conversion mismatch.
static char * rb_enc_left_char_head(const char *s, const char *p, const char *e, rb_encoding *enc)
Queries the left boundary of a character.
static char * rb_enc_right_char_head(const char *s, const char *p, const char *e, rb_encoding *enc)
Queries the right boundary of a character.
static unsigned int rb_enc_codepoint(const char *p, const char *e, rb_encoding *enc)
Queries the code point of character pointed by the passed pointer.
static int rb_enc_mbmaxlen(rb_encoding *enc)
Queries the maximum number of bytes that the passed encoding needs to represent a character.
static int RB_ENCODING_GET_INLINED(VALUE obj)
Queries the encoding of the passed object.
static int rb_enc_code_to_mbclen(int c, rb_encoding *enc)
Identical to rb_enc_codelen(), except it returns 0 for invalid code points.
static char * rb_enc_step_back(const char *s, const char *p, const char *e, int n, rb_encoding *enc)
Scans the string backwards for n characters.
VALUE rb_str_conv_enc(VALUE str, rb_encoding *from, rb_encoding *to)
Encoding conversion main routine.
VALUE rb_enc_str_new_static(const char *ptr, long len, rb_encoding *enc)
Identical to rb_enc_str_new(), except it takes a C string literal.
char * rb_enc_nth(const char *head, const char *tail, long nth, rb_encoding *enc)
Queries the n-th character.
VALUE rb_str_conv_enc_opts(VALUE str, rb_encoding *from, rb_encoding *to, int ecflags, VALUE ecopts)
Identical to rb_str_conv_enc(), except it additionally takes IO encoder options.
VALUE rb_enc_interned_str(const char *ptr, long len, rb_encoding *enc)
Identical to rb_enc_str_new(), except it returns a "f"string.
long rb_memsearch(const void *x, long m, const void *y, long n, rb_encoding *enc)
Looks for the passed string in the passed buffer.
long rb_enc_strlen(const char *head, const char *tail, rb_encoding *enc)
Counts the number of characters of the passed string, according to the passed encoding.
VALUE rb_enc_str_buf_cat(VALUE str, const char *ptr, long len, rb_encoding *enc)
Identical to rb_str_cat(), except it additionally takes an encoding.
VALUE rb_enc_str_new_cstr(const char *ptr, rb_encoding *enc)
Identical to rb_enc_str_new(), except it assumes the passed pointer is a pointer to a C string.
VALUE rb_str_export_to_enc(VALUE obj, rb_encoding *enc)
Identical to rb_str_export(), except it additionally takes an encoding.
VALUE rb_external_str_new_with_enc(const char *ptr, long len, rb_encoding *enc)
Identical to rb_external_str_new(), except it additionally takes an encoding.
int rb_enc_str_asciionly_p(VALUE str)
Queries if the passed string is "ASCII only".
VALUE rb_enc_interned_str_cstr(const char *ptr, rb_encoding *enc)
Identical to rb_enc_str_new_cstr(), except it returns a "f"string.
long rb_str_coderange_scan_restartable(const char *str, const char *end, rb_encoding *enc, int *cr)
Scans the passed string until it finds something odd.
int rb_enc_symname2_p(const char *name, long len, rb_encoding *enc)
Identical to rb_enc_symname_p(), except it additionally takes the passed string's length.
rb_econv_result_t rb_econv_convert(rb_econv_t *ec, const unsigned char **source_buffer_ptr, const unsigned char *source_buffer_end, unsigned char **destination_buffer_ptr, unsigned char *destination_buffer_end, int flags)
Converts a string from an encoding to another.
rb_econv_result_t
return value of rb_econv_convert()
@ econv_finished
The conversion stopped after converting everything.
@ econv_destination_buffer_full
The conversion stopped because there is no destination.
rb_econv_t * rb_econv_open_opts(const char *source_encoding, const char *destination_encoding, int ecflags, VALUE ecopts)
Identical to rb_econv_open(), except it additionally takes a hash of optional strings.
VALUE rb_str_encode(VALUE str, VALUE to, int ecflags, VALUE ecopts)
Converts the contents of the passed string from its encoding to the passed one.
void rb_econv_close(rb_econv_t *ec)
Destructs a converter.
VALUE rb_funcall(VALUE recv, ID mid, int n,...)
Calls a method.
VALUE rb_funcallv(VALUE recv, ID mid, int argc, const VALUE *argv)
Identical to rb_funcall(), except it takes the method arguments as a C array.
VALUE rb_funcall_with_block_kw(VALUE recv, ID mid, int argc, const VALUE *argv, VALUE procval, int kw_splat)
Identical to rb_funcallv_with_block(), except you can specify how to handle the last element of the g...
VALUE rb_check_array_type(VALUE obj)
Try converting an object to its array representation using its to_ary method, if any.
VALUE rb_ary_new(void)
Allocates a new, empty array.
VALUE rb_ary_new_capa(long capa)
Identical to rb_ary_new(), except it additionally specifies how many rooms of objects it should alloc...
VALUE rb_ary_push(VALUE ary, VALUE elem)
Special case of rb_ary_cat() that it adds only one element.
VALUE rb_ary_freeze(VALUE obj)
Freeze an array, preventing further modifications.
#define RETURN_SIZED_ENUMERATOR(obj, argc, argv, size_fn)
This roughly resembles return enum_for(__callee__) unless block_given?.
#define RETURN_ENUMERATOR(obj, argc, argv)
Identical to RETURN_SIZED_ENUMERATOR(), except its size is unknown.
#define UNLIMITED_ARGUMENTS
This macro is used in conjunction with rb_check_arity().
static int rb_check_arity(int argc, int min, int max)
Ensures that the passed integer is in the passed range.
VALUE rb_fs
The field separator character for inputs, or the $;.
VALUE rb_default_rs
This is the default value of rb_rs, i.e.
VALUE rb_backref_get(void)
Queries the last match, or Regexp.last_match, or the $~.
VALUE rb_sym_all_symbols(void)
Collects every single bits of symbols that have ever interned in the entire history of the current pr...
void rb_backref_set(VALUE md)
Updates $~.
int rb_range_values(VALUE range, VALUE *begp, VALUE *endp, int *exclp)
Deconstructs a range into its components.
VALUE rb_range_beg_len(VALUE range, long *begp, long *lenp, long len, int err)
Deconstructs a numerical range.
int rb_reg_backref_number(VALUE match, VALUE backref)
Queries the index of the given named capture.
int rb_reg_options(VALUE re)
Queries the options of the passed regular expression.
VALUE rb_reg_match(VALUE re, VALUE str)
This is the match operator.
void rb_match_busy(VALUE md)
Asserts that the given MatchData is "occupied".
VALUE rb_reg_nth_match(int n, VALUE md)
Queries the nth captured substring.
void rb_str_free(VALUE str)
Destroys the given string for no reason.
VALUE rb_str_new_shared(VALUE str)
Identical to rb_str_new_cstr(), except it takes a Ruby's string instead of C's.
VALUE rb_str_plus(VALUE lhs, VALUE rhs)
Generates a new string, concatenating the former to the latter.
#define rb_utf8_str_new_cstr(str)
Identical to rb_str_new_cstr, except it generates a string of "UTF-8" encoding.
#define rb_hash_end(h)
Just another name of st_hash_end.
#define rb_hash_uint32(h, i)
Just another name of st_hash_uint32.
VALUE rb_str_append(VALUE dst, VALUE src)
Identical to rb_str_buf_append(), except it converts the right hand side before concatenating.
VALUE rb_filesystem_str_new(const char *ptr, long len)
Identical to rb_str_new(), except it generates a string of "filesystem" encoding.
VALUE rb_sym_to_s(VALUE sym)
This is an rb_sym2str() + rb_str_dup() combo.
VALUE rb_str_times(VALUE str, VALUE num)
Repetition of a string.
VALUE rb_external_str_new(const char *ptr, long len)
Identical to rb_str_new(), except it generates a string of "default external" encoding.
VALUE rb_str_tmp_new(long len)
Allocates a "temporary" string.
long rb_str_offset(VALUE str, long pos)
"Inverse" of rb_str_sublen().
VALUE rb_str_succ(VALUE orig)
Searches for the "successor" of a string.
int rb_str_hash_cmp(VALUE str1, VALUE str2)
Compares two strings.
VALUE rb_str_subseq(VALUE str, long beg, long len)
Identical to rb_str_substr(), except the numbers are interpreted as byte offsets instead of character...
VALUE rb_str_ellipsize(VALUE str, long len)
Shortens str and adds three dots, an ellipsis, if it is longer than len characters.
st_index_t rb_memhash(const void *ptr, long len)
This is a universal hash function.
#define rb_str_new(str, len)
Allocates an instance of rb_cString.
void rb_str_shared_replace(VALUE dst, VALUE src)
Replaces the contents of the former with the latter.
#define rb_str_buf_cat
Just another name of rb_str_cat.
VALUE rb_str_new_static(const char *ptr, long len)
Identical to rb_str_new(), except it takes a C string literal.
#define rb_usascii_str_new(str, len)
Identical to rb_str_new, except it generates a string of "US ASCII" encoding.
size_t rb_str_capacity(VALUE str)
Queries the capacity of the given string.
VALUE rb_str_new_frozen(VALUE str)
Creates a frozen copy of the string, if necessary.
VALUE rb_str_dup(VALUE str)
Duplicates a string.
st_index_t rb_str_hash(VALUE str)
Calculates a hash value of a string.
VALUE rb_str_cat(VALUE dst, const char *src, long srclen)
Destructively appends the passed contents to the string.
VALUE rb_str_locktmp(VALUE str)
Obtains a "temporary lock" of the string.
long rb_str_strlen(VALUE str)
Counts the number of characters (not bytes) that are stored inside of the given string.
VALUE rb_str_resurrect(VALUE str)
Like rb_str_dup(), but always create an instance of rb_cString regardless of the given object's class...
#define rb_str_buf_new_cstr(str)
Identical to rb_str_new_cstr, except done differently.
#define rb_usascii_str_new_cstr(str)
Identical to rb_str_new_cstr, except it generates a string of "US ASCII" encoding.
VALUE rb_str_replace(VALUE dst, VALUE src)
Replaces the contents of the former object with the stringised contents of the latter.
VALUE rb_str_no_gvl_safe_acquire(VALUE orig)
Creates a frozen copy of orig that guarantees the RSTRING_PTR is safe to use in operations that relea...
char * rb_str_subpos(VALUE str, long beg, long *len)
Identical to rb_str_substr(), except it returns a C's string instead of Ruby's.
rb_gvar_setter_t rb_str_setter
This is a rb_gvar_setter_t that refutes non-string assignments.
VALUE rb_interned_str_cstr(const char *ptr)
Identical to rb_interned_str(), except it assumes the passed pointer is a pointer to a C's string.
VALUE rb_filesystem_str_new_cstr(const char *ptr)
Identical to rb_filesystem_str_new(), except it assumes the passed pointer is a pointer to a C string...
#define rb_external_str_new_cstr(str)
Identical to rb_str_new_cstr, except it generates a string of "default external" encoding.
VALUE rb_str_buf_append(VALUE dst, VALUE src)
Identical to rb_str_cat_cstr(), except it takes Ruby's string instead of C's.
long rb_str_sublen(VALUE str, long pos)
Byte offset to character offset conversion.
VALUE rb_str_equal(VALUE str1, VALUE str2)
Equality of two strings.
void rb_str_no_gvl_safe_release(VALUE orig, VALUE tmp)
Releases a string created from rb_str_no_gvl_safe_acquire.
void rb_str_set_len(VALUE str, long len)
Overwrites the length of the string.
VALUE rb_str_inspect(VALUE str)
Generates a "readable" version of the receiver.
void rb_must_asciicompat(VALUE obj)
Asserts that the given string's encoding is (Ruby's definition of) ASCII compatible.
VALUE rb_interned_str(const char *ptr, long len)
Identical to rb_str_new(), except it returns an infamous "f"string.
int rb_str_cmp(VALUE lhs, VALUE rhs)
Compares two strings, as in strcmp(3).
VALUE rb_str_concat(VALUE dst, VALUE src)
Identical to rb_str_append(), except it also accepts an integer as a codepoint.
int rb_str_comparable(VALUE str1, VALUE str2)
Checks if two strings are comparable each other or not.
#define rb_strlen_lit(str)
Length of a string literal.
VALUE rb_str_buf_cat_ascii(VALUE dst, const char *src)
Identical to rb_str_cat_cstr(), except it additionally assumes the source string be a NUL terminated ...
VALUE rb_str_freeze(VALUE str)
This is the implementation of String#freeze.
void rb_str_update(VALUE dst, long beg, long len, VALUE src)
Replaces some (or all) of the contents of the given string.
VALUE rb_str_scrub(VALUE str, VALUE repl)
"Cleanses" the string.
#define rb_locale_str_new_cstr(str)
Identical to rb_external_str_new_cstr, except it generates a string of "locale" encoding instead of "...
VALUE rb_str_new_with_class(VALUE obj, const char *ptr, long len)
Identical to rb_str_new(), except it takes the class of the allocating object.
#define rb_str_dup_frozen
Just another name of rb_str_new_frozen.
VALUE rb_check_string_type(VALUE obj)
Try converting an object to its stringised representation using its to_str method,...
VALUE rb_str_substr(VALUE str, long beg, long len)
This is the implementation of two-argumented String#slice.
#define rb_str_cat_cstr(buf, str)
Identical to rb_str_cat(), except it assumes the passed pointer is a pointer to a C string.
VALUE rb_str_unlocktmp(VALUE str)
Releases a lock formerly obtained by rb_str_locktmp().
VALUE rb_utf8_str_new_static(const char *ptr, long len)
Identical to rb_str_new_static(), except it generates a string of "UTF-8" encoding instead of "binary...
#define rb_utf8_str_new(str, len)
Identical to rb_str_new, except it generates a string of "UTF-8" encoding.
void rb_str_modify_expand(VALUE str, long capa)
Identical to rb_str_modify(), except it additionally expands the capacity of the receiver.
VALUE rb_str_dump(VALUE str)
"Inverse" of rb_eval_string().
VALUE rb_locale_str_new(const char *ptr, long len)
Identical to rb_str_new(), except it generates a string of "locale" encoding.
VALUE rb_str_buf_new(long capa)
Allocates a "string buffer".
VALUE rb_str_length(VALUE)
Identical to rb_str_strlen(), except it returns the value in rb_cInteger.
#define rb_str_new_cstr(str)
Identical to rb_str_new, except it assumes the passed pointer is a pointer to a C string.
VALUE rb_str_drop_bytes(VALUE str, long len)
Shrinks the given string for the given number of bytes.
VALUE rb_str_split(VALUE str, const char *delim)
Divides the given string based on the given delimiter.
VALUE rb_usascii_str_new_static(const char *ptr, long len)
Identical to rb_str_new_static(), except it generates a string of "US ASCII" encoding instead of "bin...
VALUE rb_str_intern(VALUE str)
Identical to rb_to_symbol(), except it assumes the receiver being an instance of RString.
VALUE rb_obj_as_string(VALUE obj)
Try converting an object to its stringised representation using its to_s method, if any.
VALUE rb_ivar_set(VALUE obj, ID name, VALUE val)
Identical to rb_iv_set(), except it accepts the name as an ID instead of a C string.
VALUE rb_ivar_defined(VALUE obj, ID name)
Queries if the instance variable is defined at the object.
int rb_respond_to(VALUE obj, ID mid)
Queries if the object responds to the method.
void rb_undef_alloc_func(VALUE klass)
Deletes the allocator function of a class.
void rb_define_alloc_func(VALUE klass, rb_alloc_func_t func)
Sets the allocator function of a class.
static ID rb_intern_const(const char *str)
This is a "tiny optimisation" over rb_intern().
VALUE rb_sym2str(VALUE symbol)
Obtain a frozen string representation of a symbol (not including the leading colon).
VALUE rb_to_symbol(VALUE name)
Identical to rb_intern_str(), except it generates a dynamic symbol if necessary.
ID rb_to_id(VALUE str)
Identical to rb_intern_str(), except it tries to convert the parameter object to an instance of rb_cS...
int capa
Designed capacity of the buffer.
int off
Offset inside of ptr.
int len
Length of the buffer.
#define RB_OBJ_SET_SHAREABLE(obj)
Wrapper of rb_obj_set_shareable().
#define RB_OBJ_SHAREABLE_P(obj)
Queries if the passed object has previously classified as shareable or not.
long rb_reg_search(VALUE re, VALUE str, long pos, int dir)
Runs the passed regular expression over the passed string.
VALUE rb_reg_regcomp(VALUE str)
Creates a new instance of rb_cRegexp.
VALUE rb_str_format(int argc, const VALUE *argv, VALUE fmt)
Formats a string.
VALUE rb_yield(VALUE val)
Yields the block.
#define MEMCPY(p1, p2, type, n)
Handy macro to call memcpy.
#define ALLOCA_N(type, n)
#define MEMZERO(p, type, n)
Handy macro to erase a region of memory.
#define RB_GC_GUARD(v)
Prevents premature destruction of local objects.
void rb_define_hooked_variable(const char *q, VALUE *w, type *e, void_type *r)
Define a function-backended global variable.
VALUE type(ANYARGS)
ANYARGS-ed function type.
void rb_hash_foreach(VALUE q, int_type *w, VALUE e)
Iteration over the given hash.
VALUE rb_ensure(type *q, VALUE w, type *e, VALUE r)
An equivalent of ensure clause.
Defines RBIMPL_ATTR_NONSTRING.
static int RARRAY_LENINT(VALUE ary)
Identical to rb_array_len(), except it differs for the return type.
#define RARRAY_CONST_PTR
Just another name of rb_array_const_ptr.
static VALUE RBASIC_CLASS(VALUE obj)
Queries the class of an object.
#define RBASIC(obj)
Convenient casting macro.
#define RHASH_SIZE(h)
Queries the size of the hash.
static VALUE RREGEXP_SRC(VALUE rexp)
Convenient getter function.
#define StringValue(v)
Ensures that the parameter object is a String.
VALUE rb_str_export_locale(VALUE obj)
Identical to rb_str_export(), except it converts into the locale encoding instead.
char * rb_string_value_cstr(volatile VALUE *ptr)
Identical to rb_string_value_ptr(), except it additionally checks for the contents for viability as a...
static int RSTRING_LENINT(VALUE str)
Identical to RSTRING_LEN(), except it differs for the return type.
static char * RSTRING_END(VALUE str)
Queries the end of the contents pointer of the string.
#define RSTRING_GETMEM(str, ptrvar, lenvar)
Convenient macro to obtain the contents and length at once.
VALUE rb_string_value(volatile VALUE *ptr)
Identical to rb_str_to_str(), except it fills the passed pointer with the converted object.
#define RSTRING(obj)
Convenient casting macro.
VALUE rb_str_export(VALUE obj)
Identical to rb_str_to_str(), except it additionally converts the string into default external encodi...
char * rb_string_value_ptr(volatile VALUE *ptr)
Identical to rb_str_to_str(), except it returns the converted string's backend memory region.
VALUE rb_str_to_str(VALUE obj)
Identical to rb_check_string_type(), except it raises exceptions in case of conversion failures.
#define StringValueCStr(v)
Identical to StringValuePtr, except it additionally checks for the contents for viability as a C stri...
#define DATA_PTR(obj)
Convenient casting macro for backward compatibility.
#define TypedData_Wrap_Struct(klass, data_type, sval)
Converts sval, a pointer to your struct, into a Ruby object.
VALUE rb_require(const char *feature)
Identical to rb_require_string(), except it takes C's string instead of Ruby's.
#define errno
Ractor-aware version of errno.
#define RB_NUM2SSIZE
Converts an instance of rb_cInteger into C's ssize_t.
#define RTEST
This is an old name of RB_TEST.
#define _(args)
This was a transition path from K&R to ANSI.
VALUE flags
Per-object flags.
struct RBasic basic
Basic part, including flags and class.
union RString::@60::@61::@63 aux
Auxiliary info.
long capa
Capacity of *ptr.
long len
Length of the string, not including terminating NUL character.
struct RString::@60::@61 heap
Strings that use separated memory region for contents use this pattern.
struct RString::@60::@62 embed
Embedded contents.
VALUE shared
Parent of the string.
char * ptr
Pointer to the contents of the string.
union RString::@60 as
String's specific fields.
This is the struct that holds necessary info for a struct.
void rb_nativethread_lock_lock(rb_nativethread_lock_t *lock)
Blocks until the current thread obtains a lock.
uintptr_t ID
Type that represents a Ruby identifier such as a variable name.
uintptr_t VALUE
Type that represents a Ruby object.
static enum ruby_value_type rb_type(VALUE obj)
Identical to RB_BUILTIN_TYPE(), except it can also accept special constants.
static void Check_Type(VALUE v, enum ruby_value_type t)
Identical to RB_TYPE_P(), except it raises exceptions on predication failure.
static bool RB_TYPE_P(VALUE obj, enum ruby_value_type t)
Queries if the given object is of given type.
ruby_value_type
C-level type of an object.