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");
4156 if (rb_num_to_uint(str2, &code) == 0) {
4169 encidx = rb_ascii8bit_appendable_encoding_index(enc, code);
4172 rb_str_buf_cat_byte(str1, (
unsigned char)code);
4175 long pos = RSTRING_LEN(str1);
4180 switch (
len = rb_enc_codelen(code, enc)) {
4181 case ONIGERR_INVALID_CODE_POINT_VALUE:
4182 rb_raise(
rb_eRangeError,
"invalid codepoint 0x%X in %s", code, rb_enc_name(enc));
4184 case ONIGERR_TOO_BIG_WIDE_CHAR_VALUE:
4190 rb_enc_mbcput(code, buf, enc);
4191 if (rb_enc_precise_mbclen(buf, buf +
len + 1, enc) !=
len) {
4192 rb_raise(
rb_eRangeError,
"invalid codepoint 0x%X in %s", code, rb_enc_name(enc));
4194 rb_str_resize(str1, pos+
len);
4195 memcpy(RSTRING_PTR(str1) + pos, buf,
len);
4208rb_ascii8bit_appendable_encoding_index(
rb_encoding *enc,
unsigned int code)
4210 int encidx = rb_enc_to_index(enc);
4212 if (encidx == ENCINDEX_ASCII_8BIT || encidx == ENCINDEX_US_ASCII) {
4217 if (encidx == ENCINDEX_US_ASCII && code > 127) {
4218 return ENCINDEX_ASCII_8BIT;
4240rb_str_prepend_multi(
int argc,
VALUE *argv,
VALUE str)
4242 str_modifiable(str);
4247 else if (argc > 1) {
4250 rb_enc_copy(arg_str, str);
4251 for (i = 0; i < argc; i++) {
4264 st_index_t precomputed_hash;
4265 memcpy(&precomputed_hash,
RSTRING_END(str) + TERM_LEN(str),
sizeof(precomputed_hash));
4267 RUBY_ASSERT(precomputed_hash == str_do_hash(str));
4268 return precomputed_hash;
4271 return str_do_hash(str);
4278 const char *ptr1, *ptr2;
4281 return (len1 != len2 ||
4283 memcmp(ptr1, ptr2, len1) != 0);
4295rb_str_hash_m(
VALUE str)
4301#define lesser(a,b) (((a)>(b))?(b):(a))
4309 if (RSTRING_LEN(str1) == 0)
return TRUE;
4310 if (RSTRING_LEN(str2) == 0)
return TRUE;
4313 if (idx1 == idx2)
return TRUE;
4314 rc1 = rb_enc_str_coderange(str1);
4315 rc2 = rb_enc_str_coderange(str2);
4318 if (rb_enc_asciicompat(rb_enc_from_index(idx2)))
4322 if (rb_enc_asciicompat(rb_enc_from_index(idx1)))
4332 const char *ptr1, *ptr2;
4335 if (str1 == str2)
return 0;
4338 if (ptr1 == ptr2 || (retval = memcmp(ptr1, ptr2, lesser(len1, len2))) == 0) {
4347 if (len1 > len2)
return 1;
4350 if (retval > 0)
return 1;
4384 if (str1 == str2)
return Qtrue;
4391 return rb_str_eql_internal(str1, str2);
4405 if (str1 == str2)
return Qtrue;
4407 return rb_str_eql_internal(str1, str2);
4445 return rb_invcmp(str1, str2);
4487 return str_casecmp(str1, s);
4495 const char *p1, *p1end, *p2, *p2end;
4497 enc = rb_enc_compatible(str1, str2);
4502 p1 = RSTRING_PTR(str1); p1end =
RSTRING_END(str1);
4503 p2 = RSTRING_PTR(str2); p2end =
RSTRING_END(str2);
4504 if (single_byte_optimizable(str1) && single_byte_optimizable(str2)) {
4505 while (p1 < p1end && p2 < p2end) {
4507 unsigned int c1 =
TOLOWER(*p1 & 0xff);
4508 unsigned int c2 =
TOLOWER(*p2 & 0xff);
4510 return INT2FIX(c1 < c2 ? -1 : 1);
4517 while (p1 < p1end && p2 < p2end) {
4518 int l1, c1 = rb_enc_ascget(p1, p1end, &l1, enc);
4519 int l2, c2 = rb_enc_ascget(p2, p2end, &l2, enc);
4521 if (0 <= c1 && 0 <= c2) {
4525 return INT2FIX(c1 < c2 ? -1 : 1);
4529 l1 = rb_enc_mbclen(p1, p1end, enc);
4530 l2 = rb_enc_mbclen(p2, p2end, enc);
4531 len = l1 < l2 ? l1 : l2;
4532 r = memcmp(p1, p2,
len);
4534 return INT2FIX(r < 0 ? -1 : 1);
4536 return INT2FIX(l1 < l2 ? -1 : 1);
4542 if (p1 == p1end && p2 == p2end)
return INT2FIX(0);
4543 if (p1 == p1end)
return INT2FIX(-1);
4576 return str_casecmp_p(str1, s);
4583 VALUE folded_str1, folded_str2;
4584 VALUE fold_opt = sym_fold;
4586 enc = rb_enc_compatible(str1, str2);
4591 if (is_ascii_string(str1) && is_ascii_string(str2)) {
4592 if (RSTRING_LEN(str1) != RSTRING_LEN(str2))
return Qfalse;
4593 const char *p1 = RSTRING_PTR(str1), *p1end =
RSTRING_END(str1);
4594 const char *p2 = RSTRING_PTR(str2);
4595 while (p1 < p1end) {
4596 if (*p1 != *p2 &&
TOLOWER((
unsigned char)*p1) !=
TOLOWER((
unsigned char)*p2)) {
4605 folded_str1 = rb_str_downcase(1, &fold_opt, str1);
4606 folded_str2 = rb_str_downcase(1, &fold_opt, str2);
4608 return rb_str_eql(folded_str1, folded_str2);
4612strseq_core(
const char *str_ptr,
const char *str_ptr_end,
long str_len,
4613 const char *sub_ptr,
long sub_len,
long offset,
rb_encoding *enc)
4615 const char *search_start = str_ptr;
4616 long pos, search_len = str_len - offset;
4620 pos =
rb_memsearch(sub_ptr, sub_len, search_start, search_len, enc);
4621 if (pos < 0)
return pos;
4623 if (t == search_start + pos)
break;
4624 search_len -= t - search_start;
4625 if (search_len <= 0)
return -1;
4626 offset += t - search_start;
4629 return pos + offset;
4633#define rb_str_index(str, sub, offset) rb_strseq_index(str, sub, offset, 0)
4634#define rb_str_byteindex(str, sub, offset) rb_strseq_index(str, sub, offset, 1)
4637rb_strseq_index(
VALUE str,
VALUE sub,
long offset,
int in_byte)
4639 const char *str_ptr, *str_ptr_end, *sub_ptr;
4640 long str_len, sub_len;
4643 enc = rb_enc_check(str, sub);
4644 if (is_broken_string(sub))
return -1;
4646 str_ptr = RSTRING_PTR(str);
4648 str_len = RSTRING_LEN(str);
4649 sub_ptr = RSTRING_PTR(sub);
4650 sub_len = RSTRING_LEN(sub);
4652 if (str_len < sub_len)
return -1;
4655 long str_len_char, sub_len_char;
4656 int single_byte = single_byte_optimizable(str);
4657 str_len_char = (in_byte || single_byte) ? str_len : str_strlen(str, enc);
4658 sub_len_char = in_byte ? sub_len : str_strlen(sub, enc);
4660 offset += str_len_char;
4661 if (offset < 0)
return -1;
4663 if (str_len_char - offset < sub_len_char)
return -1;
4664 if (!in_byte) offset = str_offset(str_ptr, str_ptr_end, offset, enc, single_byte);
4667 if (sub_len == 0)
return offset;
4670 return strseq_core(str_ptr, str_ptr_end, str_len, sub_ptr, sub_len, offset, enc);
4683rb_str_index_m(
int argc,
VALUE *argv,
VALUE str)
4690 if (
rb_scan_args(argc, argv,
"11", &sub, &initpos) == 2) {
4691 long slen = str_strlen(str, enc);
4693 if (pos < 0 ? (pos += slen) < 0 : pos > slen) {
4705 pos = str_offset(RSTRING_PTR(str),
RSTRING_END(str), pos,
4706 enc, single_byte_optimizable(str));
4716 pos = rb_str_index(str, sub, pos);
4730str_ensure_byte_pos(
VALUE str,
long pos)
4732 if (!single_byte_optimizable(str)) {
4733 const char *s = RSTRING_PTR(str);
4735 const char *p = s + pos;
4736 if (!at_char_boundary(s, p, e, rb_enc_get(str))) {
4738 "offset %ld does not land on character boundary", pos);
4811rb_str_byteindex_m(
int argc,
VALUE *argv,
VALUE str)
4817 if (
rb_scan_args(argc, argv,
"11", &sub, &initpos) == 2) {
4819 long slen = RSTRING_LEN(str);
4820 if (pos < 0 ? (pos += slen) < 0 : pos > slen) {
4831 str_ensure_byte_pos(str, pos);
4836 pos = RMATCH_BEG(match, 0);
4842 pos = rb_str_byteindex(str, sub, pos);
4843 if (pos >= 0)
return LONG2NUM(pos);
4851 const char *hit, *adjusted, *sbeg, *e, *t;
4853 long slen, searchlen;
4855 sbeg = RSTRING_PTR(str);
4856 slen = RSTRING_LEN(sub);
4857 if (slen == 0)
return s - sbeg;
4859 t = RSTRING_PTR(sub);
4861 searchlen = s - sbeg + 1;
4863 if (s + slen <= e && memcmp(s, t, slen) == 0) {
4868 hit = memrchr(sbeg, c, searchlen);
4871 if (hit != adjusted) {
4872 searchlen = adjusted - sbeg;
4875 if (hit + slen <= e && memcmp(hit, t, slen) == 0)
4877 searchlen = adjusted - sbeg;
4878 }
while (searchlen > 0);
4888 const char *sbeg, *s;
4892 enc = rb_enc_check(str, sub);
4893 if (is_broken_string(sub))
return -1;
4894 singlebyte = single_byte_optimizable(str);
4895 len = singlebyte ? RSTRING_LEN(str) : str_strlen(str, enc);
4896 slen = str_strlen(sub, enc);
4899 if (
len < slen)
return -1;
4901 if (
len - pos < slen) pos =
len - slen;
4902 if (
len == 0)
return pos;
4904 sbeg = RSTRING_PTR(str);
4907 if (RSTRING_LEN(sub) <= RSTRING_LEN(str) &&
4908 memcmp(sbeg, RSTRING_PTR(sub), RSTRING_LEN(sub)) == 0) {
4916 s = str_nth(sbeg,
RSTRING_END(str), pos, enc, singlebyte);
4917 return str_rindex(str, sub, s, enc);
4929rb_str_rindex_m(
int argc,
VALUE *argv,
VALUE str)
4934 long pos,
len = str_strlen(str, enc);
4936 if (
rb_scan_args(argc, argv,
"11", &sub, &initpos) == 2) {
4938 if (pos < 0 && (pos +=
len) < 0) {
4944 if (pos >
len) pos =
len;
4952 pos = str_offset(RSTRING_PTR(str),
RSTRING_END(str), pos,
4953 enc, single_byte_optimizable(str));
4963 pos = rb_str_rindex(str, sub, pos);
4973rb_str_byterindex(
VALUE str,
VALUE sub,
long pos)
4976 const char *sbeg, *s;
4979 enc = rb_enc_check(str, sub);
4980 if (is_broken_string(sub))
return -1;
4981 len = RSTRING_LEN(str);
4982 slen = RSTRING_LEN(sub);
4985 if (
len < slen)
return -1;
4986 if (
len - pos < slen) pos =
len - slen;
4987 if (
len == 0)
return pos;
4989 sbeg = RSTRING_PTR(str);
4992 if (memcmp(sbeg, RSTRING_PTR(sub), RSTRING_LEN(sub)) == 0)
4999 return str_rindex(str, sub, s, enc);
5089rb_str_byterindex_m(
int argc,
VALUE *argv,
VALUE str)
5095 if (
rb_scan_args(argc, argv,
"11", &sub, &initpos) == 2) {
5097 long len = RSTRING_LEN(str);
5098 if (pos < 0 && (pos +=
len) < 0) {
5104 if (pos >
len) pos =
len;
5107 pos = RSTRING_LEN(str);
5110 str_ensure_byte_pos(str, pos);
5115 pos = RMATCH_BEG(match, 0);
5121 pos = rb_str_byterindex(str, sub, pos);
5122 if (pos >= 0)
return LONG2NUM(pos);
5164 switch (OBJ_BUILTIN_TYPE(y)) {
5216rb_str_match_m(
int argc,
VALUE *argv,
VALUE str)
5223 result =
rb_funcallv(get_pat(re), rb_intern(
"match"), argc, argv);
5254rb_str_match_m_p(
int argc,
VALUE *argv,
VALUE str)
5258 re = get_pat(argv[0]);
5259 return rb_reg_match_p(re, str, argc > 1 ?
NUM2LONG(argv[1]) : 0);
5268static enum neighbor_char
5274 if (rb_enc_mbminlen(enc) > 1) {
5276 int r = rb_enc_precise_mbclen(p, p +
len, enc), c;
5278 return NEIGHBOR_NOT_CHAR;
5280 c = rb_enc_mbc_to_codepoint(p, p +
len, enc) + 1;
5282 if (!l)
return NEIGHBOR_NOT_CHAR;
5283 if (l !=
len)
return NEIGHBOR_WRAPPED;
5284 rb_enc_mbcput(c, p, enc);
5285 r = rb_enc_precise_mbclen(p, p +
len, enc);
5287 return NEIGHBOR_NOT_CHAR;
5289 return NEIGHBOR_FOUND;
5292 for (i =
len-1; 0 <= i && (
unsigned char)p[i] == 0xff; i--)
5295 return NEIGHBOR_WRAPPED;
5296 ++((
unsigned char*)p)[i];
5297 l = rb_enc_precise_mbclen(p, p+
len, enc);
5301 return NEIGHBOR_FOUND;
5304 memset(p+l, 0xff,
len-l);
5310 for (len2 =
len-1; 0 < len2; len2--) {
5311 l2 = rb_enc_precise_mbclen(p, p+len2, enc);
5315 memset(p+len2+1, 0xff,
len-(len2+1));
5320static enum neighbor_char
5325 if (rb_enc_mbminlen(enc) > 1) {
5327 int r = rb_enc_precise_mbclen(p, p +
len, enc), c;
5329 return NEIGHBOR_NOT_CHAR;
5331 c = rb_enc_mbc_to_codepoint(p, p +
len, enc);
5332 if (!c)
return NEIGHBOR_NOT_CHAR;
5335 if (!l)
return NEIGHBOR_NOT_CHAR;
5336 if (l !=
len)
return NEIGHBOR_WRAPPED;
5337 rb_enc_mbcput(c, p, enc);
5338 r = rb_enc_precise_mbclen(p, p +
len, enc);
5340 return NEIGHBOR_NOT_CHAR;
5342 return NEIGHBOR_FOUND;
5345 for (i =
len-1; 0 <= i && (
unsigned char)p[i] == 0; i--)
5348 return NEIGHBOR_WRAPPED;
5349 --((
unsigned char*)p)[i];
5350 l = rb_enc_precise_mbclen(p, p+
len, enc);
5354 return NEIGHBOR_FOUND;
5357 memset(p+l, 0,
len-l);
5363 for (len2 =
len-1; 0 < len2; len2--) {
5364 l2 = rb_enc_precise_mbclen(p, p+len2, enc);
5368 memset(p+len2+1, 0,
len-(len2+1));
5382static enum neighbor_char
5383enc_succ_alnum_char(
char *p,
long len,
rb_encoding *enc,
char *carry)
5385 enum neighbor_char ret;
5389 char save[ONIGENC_CODE_TO_MBC_MAXLEN];
5393 const int max_gaps = 1;
5395 c = rb_enc_mbc_to_codepoint(p, p+
len, enc);
5397 ctype = ONIGENC_CTYPE_DIGIT;
5399 ctype = ONIGENC_CTYPE_ALPHA;
5401 return NEIGHBOR_NOT_CHAR;
5404 for (
try = 0;
try <= max_gaps; ++
try) {
5405 ret = enc_succ_char(p,
len, enc);
5406 if (ret == NEIGHBOR_FOUND) {
5407 c = rb_enc_mbc_to_codepoint(p, p+
len, enc);
5409 return NEIGHBOR_FOUND;
5416 ret = enc_pred_char(p,
len, enc);
5417 if (ret == NEIGHBOR_FOUND) {
5418 c = rb_enc_mbc_to_codepoint(p, p+
len, enc);
5431 return NEIGHBOR_NOT_CHAR;
5434 if (ctype != ONIGENC_CTYPE_DIGIT) {
5436 return NEIGHBOR_WRAPPED;
5440 enc_succ_char(carry,
len, enc);
5441 return NEIGHBOR_WRAPPED;
5459 str =
rb_str_new(RSTRING_PTR(orig), RSTRING_LEN(orig));
5460 rb_enc_cr_str_copy_for_substr(str, orig);
5461 return str_succ(str);
5468 char *sbeg, *s, *e, *last_alnum = 0;
5469 int found_alnum = 0;
5471 char carry[ONIGENC_CODE_TO_MBC_MAXLEN] =
"\1";
5472 long carry_pos = 0, carry_len = 1;
5473 enum neighbor_char neighbor = NEIGHBOR_FOUND;
5475 slen = RSTRING_LEN(str);
5476 if (slen == 0)
return str;
5478 enc = STR_ENC_GET(str);
5479 sbeg = RSTRING_PTR(str);
5480 s = e = sbeg + slen;
5482 while ((s = rb_enc_prev_char(sbeg, s, e, enc)) != 0) {
5483 if (neighbor == NEIGHBOR_NOT_CHAR && last_alnum) {
5489 l = rb_enc_precise_mbclen(s, e, enc);
5490 if (!ONIGENC_MBCLEN_CHARFOUND_P(l))
continue;
5491 l = ONIGENC_MBCLEN_CHARFOUND_LEN(l);
5492 neighbor = enc_succ_alnum_char(s, l, enc, carry);
5494 case NEIGHBOR_NOT_CHAR:
5496 case NEIGHBOR_FOUND:
5498 case NEIGHBOR_WRAPPED:
5503 carry_pos = s - sbeg;
5508 while ((s = rb_enc_prev_char(sbeg, s, e, enc)) != 0) {
5509 enum neighbor_char neighbor;
5510 char tmp[ONIGENC_CODE_TO_MBC_MAXLEN];
5511 l = rb_enc_precise_mbclen(s, e, enc);
5512 if (!ONIGENC_MBCLEN_CHARFOUND_P(l))
continue;
5513 l = ONIGENC_MBCLEN_CHARFOUND_LEN(l);
5515 neighbor = enc_succ_char(tmp, l, enc);
5517 case NEIGHBOR_FOUND:
5521 case NEIGHBOR_WRAPPED:
5524 case NEIGHBOR_NOT_CHAR:
5527 if (rb_enc_precise_mbclen(s, s+l, enc) != l) {
5529 enc_succ_char(s, l, enc);
5531 if (!rb_enc_asciicompat(enc)) {
5532 MEMCPY(carry, s,
char, l);
5535 carry_pos = s - sbeg;
5539 RESIZE_CAPA(str, slen + carry_len);
5540 sbeg = RSTRING_PTR(str);
5541 s = sbeg + carry_pos;
5542 memmove(s + carry_len, s, slen - carry_pos);
5543 memmove(s, carry, carry_len);
5545 STR_SET_LEN(str, slen);
5546 TERM_FILL(&sbeg[slen], rb_enc_mbminlen(enc));
5547 rb_enc_str_coderange(str);
5562rb_str_succ_bang(
VALUE str)
5570all_digits_p(
const char *s,
long len)
5598 VALUE end, exclusive;
5602 return rb_str_upto_each(beg, end,
RTEST(exclusive), str_upto_i,
Qnil);
5608 VALUE current, after_end;
5615 enc = rb_enc_check(beg, end);
5616 ascii = (is_ascii_string(beg) && is_ascii_string(end));
5618 if (RSTRING_LEN(beg) == 1 && RSTRING_LEN(end) == 1 && ascii) {
5619 char c = RSTRING_PTR(beg)[0];
5620 char e = RSTRING_PTR(end)[0];
5622 if (c > e || (excl && c == e))
return beg;
5624 VALUE str = rb_enc_str_new(&c, 1, enc);
5626 if ((*each)(str, arg))
break;
5627 if (!excl && c == e)
break;
5629 if (excl && c == e)
break;
5634 if (ascii &&
ISDIGIT(RSTRING_PTR(beg)[0]) &&
ISDIGIT(RSTRING_PTR(end)[0]) &&
5635 all_digits_p(RSTRING_PTR(beg), RSTRING_LEN(beg)) &&
5636 all_digits_p(RSTRING_PTR(end), RSTRING_LEN(end))) {
5641 b = rb_str_to_inum(beg, 10, FALSE);
5642 e = rb_str_to_inum(end, 10, FALSE);
5649 if (excl && bi == ei)
break;
5650 if ((*each)(
rb_enc_sprintf(usascii,
"%.*ld", width, bi), arg))
break;
5655 ID op = excl ?
'<' : idLE;
5656 VALUE args[2], fmt = rb_fstring_lit(
"%.*d");
5661 if ((*each)(
rb_str_format(numberof(args), args, fmt), arg))
break;
5669 if (n > 0 || (excl && n == 0))
return beg;
5677 if ((*each)(current, arg))
break;
5678 if (
NIL_P(next))
break;
5682 if (RSTRING_LEN(current) > RSTRING_LEN(end) || RSTRING_LEN(current) == 0)
5697 if (is_ascii_string(beg) &&
ISDIGIT(RSTRING_PTR(beg)[0]) &&
5698 all_digits_p(RSTRING_PTR(beg), RSTRING_LEN(beg))) {
5699 VALUE b, args[2], fmt = rb_fstring_lit(
"%.*d");
5701 b = rb_str_to_inum(beg, 10, FALSE);
5707 if ((*each)(
rb_enc_sprintf(usascii,
"%.*ld", width, bi), arg))
break;
5715 if ((*each)(
rb_str_format(numberof(args), args, fmt), arg))
break;
5723 if ((*each)(current, arg))
break;
5726 if (RSTRING_LEN(current) == 0)
5737 if (!
rb_equal(str, *argp))
return 0;
5751 if (rb_enc_asciicompat(STR_ENC_GET(beg)) &&
5752 rb_enc_asciicompat(STR_ENC_GET(end)) &&
5753 rb_enc_asciicompat(STR_ENC_GET(val))) {
5754 const char *bp = RSTRING_PTR(beg);
5755 const char *ep = RSTRING_PTR(end);
5756 const char *vp = RSTRING_PTR(val);
5757 if (RSTRING_LEN(beg) == 1 && RSTRING_LEN(end) == 1) {
5758 if (RSTRING_LEN(val) == 0 || RSTRING_LEN(val) > 1)
5766 if (b <= v && v < e)
return Qtrue;
5767 return RBOOL(!
RTEST(exclusive) && v == e);
5774 all_digits_p(bp, RSTRING_LEN(beg)) &&
5775 all_digits_p(ep, RSTRING_LEN(end))) {
5780 rb_str_upto_each(beg, end,
RTEST(exclusive), include_range_i, (
VALUE)&val);
5782 return RBOOL(
NIL_P(val));
5805 return rb_str_subpat(str, indx,
INT2FIX(0));
5808 if (rb_str_index(str, indx, 0) != -1)
5814 long beg,
len = str_strlen(str, NULL);
5826 return str_substr(str, idx, 1, FALSE);
5843rb_str_aref_m(
int argc,
VALUE *argv,
VALUE str)
5847 return rb_str_subpat(str, argv[0], argv[1]);
5850 return rb_str_substr_two_fixnums(str, argv[0], argv[1], TRUE);
5854 return rb_str_aref(str, argv[0]);
5860 char *
ptr = RSTRING_PTR(str);
5861 long olen = RSTRING_LEN(str), nlen;
5863 str_modifiable(str);
5864 if (
len > olen)
len = olen;
5866 if (str_embed_capa(str) >= nlen + TERM_LEN(str)) {
5868 size_t old_capa =
RSTRING(str)->as.heap.aux.capa + TERM_LEN(str);
5869 int fl = (int)(
RBASIC(str)->flags & (STR_NOEMBED|STR_SHARED|STR_NOFREE));
5872 memmove(
ptr, oldptr +
len, nlen);
5873 if (fl == STR_NOEMBED) {
5874 SIZED_FREE_N(oldptr, old_capa);
5878 if (!STR_SHARED_P(str)) {
5880 rb_enc_cr_str_exact_copy(
shared, str);
5885 STR_SET_LEN(str, nlen);
5887 if (!SHARABLE_MIDDLE_SUBSTRING) {
5888 TERM_FILL(
ptr + nlen, TERM_LEN(str));
5895rb_str_update_1(
VALUE str,
long beg,
long len,
VALUE val,
long vbeg,
long vlen)
5901 if (beg == 0 && vlen == 0) {
5906 str_modify_keep_cr(str);
5910 RESIZE_CAPA(str, slen + vlen -
len);
5911 sptr = RSTRING_PTR(str);
5915 cr = rb_enc_str_coderange(val);
5920 memmove(sptr + beg + vlen,
5922 slen - (beg +
len));
5924 if (vlen < beg &&
len < 0) {
5928 memmove(sptr + beg, RSTRING_PTR(val) + vbeg, vlen);
5931 STR_SET_LEN(str, slen);
5932 TERM_FILL(&sptr[slen], TERM_LEN(str));
5939 rb_str_update_1(str, beg,
len, val, 0, RSTRING_LEN(val));
5948 int singlebyte = single_byte_optimizable(str);
5954 enc = rb_enc_check(str, val);
5955 slen = str_strlen(str, enc);
5957 if ((slen < beg) || ((beg < 0) && (beg + slen < 0))) {
5966 if (
len > slen - beg) {
5969 p = str_nth(RSTRING_PTR(str),
RSTRING_END(str), beg, enc, singlebyte);
5974 beg = p - RSTRING_PTR(str);
5976 rb_str_update_0(str, beg,
len, val);
5977 rb_enc_associate(str, enc);
5988 long start, end,
len;
5996 int num_regs = RMATCH_NREGS(match);
5997 if ((nth >= num_regs) || ((nth < 0) && (-nth >= num_regs))) {
6004 start = RMATCH_BEG(match, nth);
6008 end = RMATCH_END(match, nth);
6012 if (start +
len > RSTRING_LEN(str)) {
6016 enc = rb_enc_check_str(str, val);
6017 rb_str_update_0(str, start,
len, val);
6018 rb_enc_associate(str, enc);
6026 switch (
TYPE(indx)) {
6028 rb_str_subpat_set(str, indx,
INT2FIX(0), val);
6032 beg = rb_str_index(str, indx, 0);
6071rb_str_aset_m(
int argc,
VALUE *argv,
VALUE str)
6075 rb_str_subpat_set(str, argv[0], argv[1], argv[2]);
6083 return rb_str_aset(str, argv[0], argv[1]);
6135rb_str_slice_bang(
int argc,
VALUE *argv,
VALUE str)
6143 str_modify_keep_cr(str);
6148 int num_regs = RMATCH_NREGS(match);
6151 if ((nth += num_regs) <= 0)
return Qnil;
6153 else if (nth >= num_regs)
return Qnil;
6154 beg = RMATCH_BEG(match, nth);
6155 len = RMATCH_END(match, nth) - beg;
6157 if (beg > RSTRING_LEN(str))
return Qnil;
6158 if (
len > RSTRING_LEN(str) - beg)
len = RSTRING_LEN(str) - beg;
6161 else if (argc == 2) {
6170 beg = p - RSTRING_PTR(str);
6174 beg = rb_str_index(str, indx, 0);
6175 if (beg == -1)
return Qnil;
6176 len = RSTRING_LEN(indx);
6188 beg = p - RSTRING_PTR(str);
6197 beg = p - RSTRING_PTR(str);
6201 rb_enc_cr_str_copy_for_substr(result, str);
6209 char *sptr = RSTRING_PTR(str);
6210 long slen = RSTRING_LEN(str);
6211 if (beg +
len > slen)
6215 slen - (beg +
len));
6217 STR_SET_LEN(str, slen);
6218 TERM_FILL(&sptr[slen], TERM_LEN(str));
6229 switch (OBJ_BUILTIN_TYPE(pat)) {
6248get_pat_quoted(
VALUE pat,
int check)
6252 switch (OBJ_BUILTIN_TYPE(pat)) {
6266 if (check && is_broken_string(pat)) {
6273rb_pat_search0(
VALUE pat,
VALUE str,
long pos,
int set_backref_str,
VALUE *match)
6276 pos = rb_str_byteindex(str, pat, pos);
6277 if (set_backref_str) {
6279 str = rb_str_new_frozen_String(str);
6280 VALUE match_data = rb_backref_set_string(str, pos, RSTRING_LEN(pat));
6282 *match = match_data;
6292 return rb_reg_search0(pat, str, pos, 0, set_backref_str, match);
6297rb_pat_search(
VALUE pat,
VALUE str,
long pos,
int set_backref_str)
6299 return rb_pat_search0(pat, str, pos, set_backref_str, NULL);
6317rb_str_sub_bang(
int argc,
VALUE *argv,
VALUE str)
6332 hash = rb_check_hash_type(repl);
6339 pat = get_pat_quoted(argv[0], 1);
6341 str_modifiable(str);
6342 beg = rb_pat_search(pat, str, 0, 1);
6354 end0 = beg0 + RSTRING_LEN(pat);
6358 beg0 = RMATCH_BEG(match, 0);
6359 end0 = RMATCH_END(match, 0);
6363 if (iter || !
NIL_P(hash)) {
6364 p = RSTRING_PTR(str);
len = RSTRING_LEN(str);
6370 repl = rb_hash_aref(hash,
rb_str_subseq(str, beg0, end0 - beg0));
6373 str_mod_check(str, p,
len);
6374 rb_check_frozen(str);
6377 repl = rb_reg_regsub_match(repl, str, match);
6380 enc = rb_enc_compatible(str, repl);
6383 p = RSTRING_PTR(str);
len = RSTRING_LEN(str);
6387 rb_enc_inspect_name(str_enc),
6388 rb_enc_inspect_name(STR_ENC_GET(repl)));
6390 enc = STR_ENC_GET(repl);
6393 rb_enc_associate(str, enc);
6403 rlen = RSTRING_LEN(repl);
6404 len = RSTRING_LEN(str);
6406 RESIZE_CAPA(str,
len + rlen - plen);
6408 p = RSTRING_PTR(str);
6410 memmove(p + beg0 + rlen, p + beg0 + plen,
len - beg0 - plen);
6412 rp = RSTRING_PTR(repl);
6413 memmove(p + beg0, rp, rlen);
6415 STR_SET_LEN(str,
len);
6416 TERM_FILL(&RSTRING_PTR(str)[
len], TERM_LEN(str));
6439 rb_str_sub_bang(argc, argv, str);
6444str_gsub(
int argc,
VALUE *argv,
VALUE str,
int bang)
6447 long beg, beg0, end0;
6448 long offset, blen, slen,
len, last;
6449 enum {STR, ITER, FAST_MAP, MAP} mode = STR;
6451 int need_backref_str = -1;
6462 hash = rb_check_hash_type(repl);
6466 else if (rb_hash_default_unredefined(hash) && !
FL_TEST_RAW(hash, RHASH_PROC_DEFAULT)) {
6475 rb_error_arity(argc, 1, 2);
6478 pat = get_pat_quoted(argv[0], 1);
6479 beg = rb_pat_search0(pat, str, 0, need_backref_str, &match);
6482 if (bang)
return Qnil;
6485 if (bang) str_modify_keep_cr(str);
6488 blen = RSTRING_LEN(str) + 30;
6490 sp = RSTRING_PTR(str);
6491 slen = RSTRING_LEN(str);
6493 str_enc = STR_ENC_GET(str);
6494 rb_enc_associate(dest, str_enc);
6500 end0 = beg0 + RSTRING_LEN(pat);
6504 beg0 = RMATCH_BEG(match, 0);
6505 end0 = RMATCH_END(match, 0);
6514 struct RString fake_str = {RBASIC_INIT};
6516 if (mode == FAST_MAP) {
6525 val = rb_hash_aref(hash, key);
6528 str_mod_check(str, sp, slen);
6533 else if (need_backref_str) {
6534 val = rb_reg_regsub_match(repl, str, match);
6535 if (need_backref_str < 0) {
6536 need_backref_str = val != repl;
6543 len = beg0 - offset;
6557 if (RSTRING_LEN(str) <= end0)
break;
6558 len = rb_enc_fast_mbclen(RSTRING_PTR(str)+end0,
RSTRING_END(str), str_enc);
6560 offset = end0 +
len;
6562 cp = RSTRING_PTR(str) + offset;
6563 if (offset > RSTRING_LEN(str))
break;
6566 if (mode != FAST_MAP && mode != STR) {
6569 beg = rb_pat_search0(pat, str, offset, need_backref_str, &match);
6574 if (RSTRING_LEN(str) > offset) {
6577 rb_pat_search0(pat, str, last, 1, &match);
6579 str_shared_replace(str, dest);
6604rb_str_gsub_bang(
int argc,
VALUE *argv,
VALUE str)
6606 str_modifiable(str);
6607 return str_gsub(argc, argv, str, 1);
6657 return str_gsub(argc, argv, str, 0);
6677 str_modifiable(str);
6678 if (str == str2)
return str;
6682 return str_replace(str, str2);
6699rb_str_clear(
VALUE str)
6703 STR_SET_LEN(str, 0);
6704 RSTRING_PTR(str)[0] = 0;
6705 if (rb_enc_asciicompat(STR_ENC_GET(str)))
6721rb_str_chr(
VALUE str)
6739 pos += RSTRING_LEN(str);
6740 if (pos < 0 || RSTRING_LEN(str) <= pos)
6743 return INT2FIX((
unsigned char)RSTRING_PTR(str)[pos]);
6763 char *
ptr, *head, *left = 0;
6769 char byte = (char)(
NUM2INT(w) & 0xFF);
6771 long len = RSTRING_LEN(str);
6772 if (pos < -
len ||
len <= pos)
6777 if (!str_independent(str))
6778 str_make_independent(str);
6779 enc = STR_ENC_GET(str);
6780 head = RSTRING_PTR(str);
6782 if (!STR_EMBED_P(str)) {
6789 nlen = rb_enc_precise_mbclen(left, head+
len, enc);
6797 width = rb_enc_precise_mbclen(left, head+
len, enc);
6799 nlen = rb_enc_precise_mbclen(left, head+
len, enc);
6815str_bit_offset_out_of_range(
long byte_len, uint64_t bit_offset)
6818 return bit_offset / CHAR_BIT >= (uint64_t)byte_len;
6834str_bit_offset_from_index(
VALUE index)
6846 offset.long_value =
FIX2LONG(integer);
6847 if (offset.long_value < 0) {
6850 offset.value = (uint64_t)offset.long_value;
6851 offset.fits_long =
true;
6856 if (rb_int_negative_p(integer)) {
6859 if (rb_cmpint(rb_int_cmp(integer,
ULL2NUM(UINT64_MAX)), integer,
ULL2NUM(UINT64_MAX)) > 0) {
6860 rb_raise(rb_eArgError,
"bit index out of representable range");
6863 offset.value = (uint64_t)
NUM2ULL(integer);
6864 if (offset.value <= (uint64_t)LONG_MAX) {
6865 offset.long_value = (long)offset.value;
6866 offset.fits_long =
true;
6869 offset.long_value = 0;
6870 offset.fits_long =
false;
6880str_bit_length_from_index(
VALUE index)
6887 rb_raise(rb_eArgError,
"negative bit length");
6889 return (uint64_t)value;
6893 if (rb_int_negative_p(integer)) {
6894 rb_raise(rb_eArgError,
"negative bit length");
6896 if (rb_cmpint(rb_int_cmp(integer,
ULL2NUM(UINT64_MAX)), integer,
ULL2NUM(UINT64_MAX)) > 0) {
6897 rb_raise(rb_eArgError,
"bit length out of representable range");
6899 return (uint64_t)
NUM2ULL(integer);
6902static inline uint64_t
6903str_bit_size(
long byte_len)
6909 if ((uint64_t)byte_len > UINT64_MAX / CHAR_BIT)
return UINT64_MAX;
6910 return (uint64_t)byte_len * CHAR_BIT;
6915 uint64_t end_exclusive;
6938 out->beg =
NIL_P(beg_v) ? 0 : str_bit_offset_from_index(beg_v).value;
6940 out->end_open =
true;
6941 out->end_exclusive = 0;
6944 uint64_t end = str_bit_offset_from_index(end_v).value;
6945 out->end_open =
false;
6950 out->end_exclusive = (excl || end == UINT64_MAX) ? end : end + 1;
6960str_bit_range_resolve(
const struct str_bit_range *range, uint64_t total_bits, uint64_t *begp, uint64_t *lenp)
6962 uint64_t beg = range->beg;
6963 if (beg > total_bits)
return false;
6965 uint64_t end_exclusive = range->end_open ? total_bits : range->end_exclusive;
6966 if (end_exclusive < beg) end_exclusive = beg;
6969 *lenp = end_exclusive - beg;
6974str_lsb_first_from_opts(
VALUE opts)
6976 static ID keywords[1];
6984 if (vlsb_first ==
Qundef || vlsb_first ==
Qtrue) {
6987 if (vlsb_first ==
Qfalse) {
6990 rb_raise(rb_eArgError,
"lsb_first must be true or false");
6995str_lsb_first(
int argc,
VALUE *argv,
VALUE *index)
7000 return str_lsb_first_from_opts(opts);
7003static inline uint64_t
7004str_logical_to_physical_bit64(uint64_t logical,
bool lsb_first)
7006 return lsb_first ? logical : ((logical & ~(uint64_t)7) | (7 - (logical & 7)));
7010str_logical_to_physical_bit(
long logical,
bool lsb_first)
7012 return lsb_first ? logical : ((logical & ~7L) | (7 - (logical & 7L)));
7017 unsigned int bit_offset;
7021str_bit_location_from_offset(uint64_t logical, bool lsb_first)
7027 uint64_t physical = str_logical_to_physical_bit64(logical, lsb_first);
7029 location.byte_index = (long)(physical / CHAR_BIT);
7030 location.bit_offset = (
unsigned int)(physical % CHAR_BIT);
7035str_get_bit(
const char *ptr,
long bit_index)
7037 return (((
unsigned char)ptr[bit_index / CHAR_BIT]) >> (bit_index % CHAR_BIT)) & 1;
7043 return (((
unsigned char)ptr[location.byte_index]) >> location.bit_offset) & 1;
7050 bool lsb_first = str_lsb_first(argc, argv, &index);
7053 if (str_bit_offset_out_of_range(RSTRING_LEN(str), offset.value)) {
7057 if (offset.fits_long) {
7058 return str_get_bit(RSTRING_PTR(str), str_logical_to_physical_bit(offset.long_value, lsb_first));
7061 return str_get_bit_location(RSTRING_PTR(str), str_bit_location_from_offset(offset.value, lsb_first));
7073rb_str_bit_get(
int argc,
VALUE *argv,
VALUE str)
7075 int bit = str_bit_get(argc, argv, str);
7087rb_str_bit_set_p(
int argc,
VALUE *argv,
VALUE str)
7089 int bit = str_bit_get(argc, argv, str);
7090 return bit < 0 ?
Qnil : RBOOL(bit);
7093enum str_bit_mutation {
7104static inline unsigned char
7105str_bit_region_byte_mask(
unsigned int lo,
unsigned int hi,
bool lsb_first)
7108 return (
unsigned char)((0xFFu >> (7 - hi)) & (0xFFu << lo));
7111 return (
unsigned char)((0xFFu >> lo) & (0xFFu << (7 - hi)));
7116str_apply_bit_mask(
unsigned char *
byte,
unsigned char mask,
enum str_bit_mutation mutation)
7123 *
byte &= (
unsigned char)~mask;
7133str_mutate_bit_region(
unsigned char *ptr, uint64_t beg, uint64_t
len,
bool lsb_first,
enum str_bit_mutation mutation)
7135 uint64_t first_bit = beg;
7136 uint64_t last_bit = beg +
len - 1;
7137 long first_byte = (long)(first_bit / CHAR_BIT);
7138 long last_byte = (long)(last_bit / CHAR_BIT);
7139 unsigned int first_off = (
unsigned int)(first_bit % CHAR_BIT);
7140 unsigned int last_off = (
unsigned int)(last_bit % CHAR_BIT);
7142 if (first_byte == last_byte) {
7143 str_apply_bit_mask(ptr + first_byte, str_bit_region_byte_mask(first_off, last_off, lsb_first), mutation);
7147 str_apply_bit_mask(ptr + first_byte, str_bit_region_byte_mask(first_off, 7, lsb_first), mutation);
7148 long middle_len = last_byte - first_byte - 1;
7149 if (middle_len > 0) {
7150 unsigned char *middle = ptr + first_byte + 1;
7153 memset(middle, 0xFF, middle_len);
7156 memset(middle, 0, middle_len);
7164 for (
long i = 0; i < middle_len; i++) {
7170 str_apply_bit_mask(ptr + last_byte, str_bit_region_byte_mask(0, last_off, lsb_first), mutation);
7174str_mutate_single_bit(
VALUE str,
VALUE index,
bool lsb_first,
enum str_bit_mutation mutation)
7182 rb_check_frozen(str);
7184 if (str_bit_offset_out_of_range(RSTRING_LEN(str), offset.value)) {
7189 ptr = (
unsigned char *)RSTRING_PTR(str);
7190 if (offset.fits_long) {
7191 bit_index = str_logical_to_physical_bit(offset.long_value, lsb_first);
7192 mask = (
unsigned char)(1u << (bit_index % CHAR_BIT));
7193 location.byte_index = bit_index / CHAR_BIT;
7196 location = str_bit_location_from_offset(offset.value, lsb_first);
7197 mask = (
unsigned char)(1u << location.bit_offset);
7200 str_apply_bit_mask(ptr + location.byte_index, mask, mutation);
7205str_mutate_bit(
int argc,
VALUE *argv,
VALUE str,
enum str_bit_mutation mutation)
7207 VALUE target, length_v, opts;
7208 uint64_t beg = 0,
len = 0;
7211 int nargs =
rb_scan_args(argc, argv,
"11:", &target, &length_v, &opts);
7212 bool lsb_first = str_lsb_first_from_opts(opts);
7215 if (nargs == 1 && !is_range) {
7216 return str_mutate_single_bit(str, target, lsb_first, mutation);
7223 rb_raise(rb_eArgError,
"bit length not allowed with a Range");
7225 str_bit_range_to_offsets(target, &range);
7228 offset = str_bit_offset_from_index(target);
7229 len = str_bit_length_from_index(length_v);
7233 rb_check_frozen(str);
7241 uint64_t total_bits = str_bit_size(RSTRING_LEN(str));
7243 if (!str_bit_range_resolve(&range, total_bits, &beg, &
len) ||
len > total_bits - beg) {
7249 if (beg > total_bits ||
len > total_bits - beg) {
7254 if (
len == 0)
return str;
7257 str_mutate_bit_region((
unsigned char *)RSTRING_PTR(str), beg,
len, lsb_first, mutation);
7271rb_str_bit_set(
int argc,
VALUE *argv,
VALUE str)
7273 return str_mutate_bit(argc, argv, str, STR_BIT_SET);
7286rb_str_bit_clear(
int argc,
VALUE *argv,
VALUE str)
7288 return str_mutate_bit(argc, argv, str, STR_BIT_CLEAR);
7301rb_str_bit_flip(
int argc,
VALUE *argv,
VALUE str)
7303 return str_mutate_bit(argc, argv, str, STR_BIT_FLIP);
7307str_count_bits(
const unsigned char *ptr,
long len)
7311 long unrolled_end =
len & ~31L;
7312 long aligned_end =
len & ~7L;
7315 for (;
off < unrolled_end;
off += 32) {
7316 uint64_t w0, w1, w2, w3;
7317 memcpy(&w0, ptr +
off, 8);
7318 memcpy(&w1, ptr +
off + 8, 8);
7319 memcpy(&w2, ptr +
off + 16, 8);
7320 memcpy(&w3, ptr +
off + 24, 8);
7321 count += rb_popcount64(w0);
7322 count += rb_popcount64(w1);
7323 count += rb_popcount64(w2);
7324 count += rb_popcount64(w3);
7328 for (;
off < aligned_end;
off += 8) {
7330 memcpy(&word, ptr +
off, 8);
7331 count += rb_popcount64(word);
7338 for (;
off <
len;
off++, shift += CHAR_BIT) {
7339 word |= (uint64_t)ptr[
off] << shift;
7341 count += rb_popcount64(word);
7348str_count_bits_region(
const unsigned char *ptr, uint64_t beg, uint64_t
len,
bool lsb_first)
7350 uint64_t first_bit = beg;
7351 uint64_t last_bit = beg +
len - 1;
7352 long first_byte = (long)(first_bit / CHAR_BIT);
7353 long last_byte = (long)(last_bit / CHAR_BIT);
7354 unsigned int first_off = (
unsigned int)(first_bit % CHAR_BIT);
7355 unsigned int last_off = (
unsigned int)(last_bit % CHAR_BIT);
7357 if (first_byte == last_byte) {
7358 return rb_popcount32((uint32_t)(ptr[first_byte] & str_bit_region_byte_mask(first_off, last_off, lsb_first)));
7361 uint64_t count = rb_popcount32((uint32_t)(ptr[first_byte] & str_bit_region_byte_mask(first_off, 7, lsb_first)));
7362 count += str_count_bits(ptr + first_byte + 1, last_byte - first_byte - 1);
7363 count += rb_popcount32((uint32_t)(ptr[last_byte] & str_bit_region_byte_mask(0, last_off, lsb_first)));
7377rb_str_bit_count(
int argc,
VALUE *argv,
VALUE str)
7380 uint64_t beg = 0,
len = 0;
7383 int nargs =
rb_scan_args(argc, argv,
"02:", &v0, &v1, &opts);
7388 bool lsb_first = str_lsb_first_from_opts(opts);
7391 return ULL2NUM(str_count_bits((
const unsigned char *)RSTRING_PTR(str), RSTRING_LEN(str)));
7398 rb_raise(rb_eArgError,
"bit length not allowed with a Range");
7400 str_bit_range_to_offsets(v0, &range);
7402 else if (nargs == 1) {
7403 rb_raise(rb_eArgError,
"no bit length given");
7406 beg = str_bit_offset_from_index(v0).value;
7407 len = str_bit_length_from_index(v1);
7410 const unsigned char *ptr = (
const unsigned char *)RSTRING_PTR(str);
7411 uint64_t total_bits = str_bit_size(RSTRING_LEN(str));
7413 if (!str_bit_range_resolve(&range, total_bits, &beg, &
len)) {
7417 else if (beg >= total_bits) {
7422 if (
len > total_bits - beg)
len = total_bits - beg;
7424 return ULL2NUM(str_count_bits_region(ptr, beg,
len, lsb_first));
7428str_check_bitwise_length(
VALUE str,
VALUE other)
7430 if (RSTRING_LEN(str) != RSTRING_LEN(other)) {
7431 rb_raise(rb_eArgError,
"operands must have the same length (%ld vs %ld)",
7432 RSTRING_LEN(str), RSTRING_LEN(other));
7437str_bitwise_result(
VALUE str)
7439 long len = RSTRING_LEN(str);
7441 rb_str_resize(result,
len);
7442 rb_enc_associate(result, rb_ascii8bit_encoding());
7447#define STR_DEFINE_UNARY_BITWISE_KERNEL(name, expr_word, expr_byte) \
7449 name(unsigned char *dst, const unsigned char *src, long len) \
7452 long unrolled_end = len & ~31L; \
7453 long aligned_end = len & ~7L; \
7454 for (; off < unrolled_end; off += 32) { \
7455 uint64_t s0, s1, s2, s3; \
7456 memcpy(&s0, src + off, 8); \
7457 memcpy(&s1, src + off + 8, 8); \
7458 memcpy(&s2, src + off + 16, 8); \
7459 memcpy(&s3, src + off + 24, 8); \
7460 s0 = (expr_word(s0)); \
7461 s1 = (expr_word(s1)); \
7462 s2 = (expr_word(s2)); \
7463 s3 = (expr_word(s3)); \
7464 memcpy(dst + off, &s0, 8); \
7465 memcpy(dst + off + 8, &s1, 8); \
7466 memcpy(dst + off + 16, &s2, 8); \
7467 memcpy(dst + off + 24, &s3, 8); \
7469 for (; off < aligned_end; off += 8) { \
7471 memcpy(&word, src + off, 8); \
7472 word = (expr_word(word)); \
7473 memcpy(dst + off, &word, 8); \
7475 for (; off < len; off++) dst[off] = (expr_byte(src[off])); \
7478#define STR_DEFINE_BINARY_BITWISE_KERNEL(name, expr_word, expr_byte) \
7480 name(unsigned char *dst, const unsigned char *lhs, \
7481 const unsigned char *rhs, long len) \
7484 long unrolled_end = len & ~31L; \
7485 long aligned_end = len & ~7L; \
7486 for (; off < unrolled_end; off += 32) { \
7487 uint64_t l0, l1, l2, l3, r0, r1, r2, r3; \
7488 memcpy(&l0, lhs + off, 8); memcpy(&r0, rhs + off, 8); \
7489 memcpy(&l1, lhs + off + 8, 8); memcpy(&r1, rhs + off + 8, 8); \
7490 memcpy(&l2, lhs + off + 16, 8); memcpy(&r2, rhs + off + 16, 8); \
7491 memcpy(&l3, lhs + off + 24, 8); memcpy(&r3, rhs + off + 24, 8); \
7492 l0 = expr_word(l0, r0); \
7493 l1 = expr_word(l1, r1); \
7494 l2 = expr_word(l2, r2); \
7495 l3 = expr_word(l3, r3); \
7496 memcpy(dst + off, &l0, 8); \
7497 memcpy(dst + off + 8, &l1, 8); \
7498 memcpy(dst + off + 16, &l2, 8); \
7499 memcpy(dst + off + 24, &l3, 8); \
7501 for (; off < aligned_end; off += 8) { \
7502 uint64_t lhs_word, rhs_word; \
7503 memcpy(&lhs_word, lhs + off, 8); \
7504 memcpy(&rhs_word, rhs + off, 8); \
7505 lhs_word = expr_word(lhs_word, rhs_word); \
7506 memcpy(dst + off, &lhs_word, 8); \
7508 for (; off < len; off++) dst[off] = expr_byte(lhs[off], rhs[off]); \
7511#define STR_BITWISE_NOT_WORD(x) (~(x))
7512#define STR_BITWISE_NOT_BYTE(x) ((unsigned char)~(x))
7513#define STR_BITWISE_AND_WORD(x, y) ((x) & (y))
7514#define STR_BITWISE_AND_BYTE(x, y) ((unsigned char)((x) & (y)))
7515#define STR_BITWISE_OR_WORD(x, y) ((x) | (y))
7516#define STR_BITWISE_OR_BYTE(x, y) ((unsigned char)((x) | (y)))
7517#define STR_BITWISE_XOR_WORD(x, y) ((x) ^ (y))
7518#define STR_BITWISE_XOR_BYTE(x, y) ((unsigned char)((x) ^ (y)))
7520STR_DEFINE_UNARY_BITWISE_KERNEL(str_bitwise_not, STR_BITWISE_NOT_WORD, STR_BITWISE_NOT_BYTE)
7521STR_DEFINE_BINARY_BITWISE_KERNEL(str_bitwise_and, STR_BITWISE_AND_WORD, STR_BITWISE_AND_BYTE)
7522STR_DEFINE_BINARY_BITWISE_KERNEL(str_bitwise_or, STR_BITWISE_OR_WORD, STR_BITWISE_OR_BYTE)
7523STR_DEFINE_BINARY_BITWISE_KERNEL(str_bitwise_xor, STR_BITWISE_XOR_WORD, STR_BITWISE_XOR_BYTE)
7533rb_str_bitwise_not(
VALUE str)
7535 long len = RSTRING_LEN(str);
7536 VALUE result = str_bitwise_result(str);
7537 str_bitwise_not((
unsigned char *)RSTRING_PTR(result),
7538 (
const unsigned char *)RSTRING_PTR(str),
len);
7550rb_str_bitwise_not_bang(
VALUE str)
7556 len = RSTRING_LEN(str);
7557 ptr = (
unsigned char *)RSTRING_PTR(str);
7558 str_bitwise_not(ptr, ptr,
len);
7562#define STR_DEFINE_BINARY_BITWISE_METHOD(name) \
7564 rb_str_bitwise_##name(VALUE str, VALUE other) \
7568 StringValue(other); \
7569 str_check_bitwise_length(str, other); \
7570 len = RSTRING_LEN(str); \
7571 result = str_bitwise_result(str); \
7572 str_bitwise_##name((unsigned char *)RSTRING_PTR(result), \
7573 (const unsigned char *)RSTRING_PTR(str), \
7574 (const unsigned char *)RSTRING_PTR(other), len); \
7578 rb_str_bitwise_##name##_bang(VALUE str, VALUE other) \
7581 unsigned char *ptr; \
7582 StringValue(other); \
7583 str_check_bitwise_length(str, other); \
7584 rb_str_modify(str); \
7585 len = RSTRING_LEN(str); \
7586 ptr = (unsigned char *)RSTRING_PTR(str); \
7587 str_bitwise_##name(ptr, ptr, \
7588 (const unsigned char *)RSTRING_PTR(other), len); \
7592STR_DEFINE_BINARY_BITWISE_METHOD(and)
7593STR_DEFINE_BINARY_BITWISE_METHOD(or)
7594STR_DEFINE_BINARY_BITWISE_METHOD(xor)
7597str_byte_substr(
VALUE str,
long beg,
long len,
int empty)
7599 long n = RSTRING_LEN(str);
7601 if (beg > n ||
len < 0)
return Qnil;
7604 if (beg < 0)
return Qnil;
7609 if (!empty)
return Qnil;
7613 VALUE str2 = str_subseq(str, beg,
len);
7615 str_enc_copy_direct(str2, str);
7617 if (RSTRING_LEN(str2) == 0) {
7618 if (!rb_enc_asciicompat(STR_ENC_GET(str)))
7652 long beg,
len = RSTRING_LEN(str);
7660 return str_byte_substr(str, beg,
len, TRUE);
7665 return str_byte_substr(str, idx, 1, FALSE);
7677rb_str_byteslice(
int argc,
VALUE *argv,
VALUE str)
7682 return str_byte_substr(str, beg,
len, TRUE);
7685 return str_byte_aref(str, argv[0]);
7689str_check_beg_len(
VALUE str,
long *beg,
long *
len)
7691 long end, slen = RSTRING_LEN(str);
7694 if ((slen < *beg) || ((*beg < 0) && (*beg + slen < 0))) {
7703 if (*
len > slen - *beg) {
7707 str_ensure_byte_pos(str, *beg);
7708 str_ensure_byte_pos(str, end);
7722rb_str_bytesplice(
int argc,
VALUE *argv,
VALUE str)
7724 long beg,
len, vbeg, vlen;
7729 if (!(argc == 2 || argc == 3 || argc == 5)) {
7730 rb_raise(rb_eArgError,
"wrong number of arguments (given %d, expected 2, 3, or 5)", argc);
7734 rb_raise(
rb_eTypeError,
"wrong argument type %s (expected Range)",
7735 rb_builtin_class_name(argv[0]));
7742 vlen = RSTRING_LEN(val);
7747 rb_raise(
rb_eTypeError,
"wrong argument type %s (expected Range)",
7748 rb_builtin_class_name(argv[2]));
7760 vlen = RSTRING_LEN(val);
7768 str_check_beg_len(str, &beg, &
len);
7769 str_check_beg_len(val, &vbeg, &vlen);
7770 str_modify_keep_cr(str);
7773 rb_enc_associate(str, rb_enc_check(str, val));
7776 rb_str_update_1(str, beg,
len, val, vbeg, vlen);
7798rb_str_reverse(
VALUE str)
7805 if (RSTRING_LEN(str) <= 1)
return str_duplicate(
rb_cString, str);
7806 enc = STR_ENC_GET(str);
7812 if (RSTRING_LEN(str) > 1) {
7813 if (single_byte_optimizable(str)) {
7820 int clen = rb_enc_fast_mbclen(s, e, enc);
7828 cr = rb_enc_asciicompat(enc) ?
7831 int clen = rb_enc_mbclen(s, e, enc);
7840 STR_SET_LEN(rev, RSTRING_LEN(str));
7841 str_enc_copy_direct(rev, str);
7863rb_str_reverse_bang(
VALUE str)
7865 if (RSTRING_LEN(str) > 1) {
7866 if (single_byte_optimizable(str)) {
7869 str_modify_keep_cr(str);
7870 s = RSTRING_PTR(str);
7879 str_shared_replace(str, rb_str_reverse(str));
7883 str_modify_keep_cr(str);
7912 i = rb_str_index(str, arg, 0);
7914 return RBOOL(i != -1);
7958 rb_raise(rb_eArgError,
"invalid radix %d", base);
7960 return rb_str_to_inum(str, base, FALSE);
7985rb_str_to_f(
VALUE str)
8002rb_str_to_s(
VALUE str)
8014 char s[RUBY_MAX_CHAR_LEN];
8015 int n = rb_enc_codelen(c, enc);
8017 rb_enc_mbcput(c, s, enc);
8022#define CHAR_ESC_LEN 13
8025rb_str_buf_cat_escaped_char(
VALUE result,
unsigned int c,
int unicode_p)
8027 char buf[CHAR_ESC_LEN + 1];
8035 snprintf(buf, CHAR_ESC_LEN,
"%c", c);
8037 else if (c < 0x10000) {
8038 snprintf(buf, CHAR_ESC_LEN,
"\\u%04X", c);
8041 snprintf(buf, CHAR_ESC_LEN,
"\\u{%X}", c);
8046 snprintf(buf, CHAR_ESC_LEN,
"\\x%02X", c);
8049 snprintf(buf, CHAR_ESC_LEN,
"\\x{%X}", c);
8052 l = (int)strlen(buf);
8058ruby_escaped_char(
int c)
8061 case '\0':
return "\\0";
8062 case '\n':
return "\\n";
8063 case '\r':
return "\\r";
8064 case '\t':
return "\\t";
8065 case '\f':
return "\\f";
8066 case '\013':
return "\\v";
8067 case '\010':
return "\\b";
8068 case '\007':
return "\\a";
8069 case '\033':
return "\\e";
8070 case '\x7f':
return "\\c?";
8076rb_str_escape(
VALUE str)
8080 const char *p = RSTRING_PTR(str);
8082 const char *prev = p;
8083 char buf[CHAR_ESC_LEN + 1];
8085 int unicode_p = rb_enc_unicode_p(enc);
8086 int asciicompat = rb_enc_asciicompat(enc);
8091 int n = rb_enc_precise_mbclen(p, pend, enc);
8093 if (p > prev) str_buf_cat(result, prev, p - prev);
8094 n = rb_enc_mbminlen(enc);
8096 n = (int)(pend - p);
8098 snprintf(buf, CHAR_ESC_LEN,
"\\x%02X", *p & 0377);
8099 str_buf_cat(result, buf, strlen(buf));
8105 c = rb_enc_mbc_to_codepoint(p, pend, enc);
8107 cc = ruby_escaped_char(c);
8109 if (p - n > prev) str_buf_cat(result, prev, p - n - prev);
8110 str_buf_cat(result, cc, strlen(cc));
8113 else if (asciicompat && rb_enc_isascii(c, enc) &&
ISPRINT(c)) {
8116 if (p - n > prev) str_buf_cat(result, prev, p - n - prev);
8117 rb_str_buf_cat_escaped_char(result, c, unicode_p);
8121 if (p > prev) str_buf_cat(result, prev, p - prev);
8131static const bool inspect_no_escape[256] = {
8132 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8133 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8134 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
8135 1, 1, 1, 1, 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, 0, 1, 1, 1,
8138 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
8139 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,
8155 const char *p, *pend, *prev;
8156 char buf[CHAR_ESC_LEN + 1];
8158 rb_encoding *resenc = rb_default_internal_encoding();
8159 int unicode_p = rb_enc_unicode_p(enc);
8160 int asciicompat = rb_enc_asciicompat(enc);
8161 int cr = rb_enc_str_coderange(str);
8163 if (resenc == NULL) resenc = rb_default_external_encoding();
8164 if (!rb_enc_asciicompat(resenc)) resenc = rb_usascii_encoding();
8165 rb_enc_associate(result, resenc);
8166 str_buf_cat2(result,
"\"");
8179 while (p < pend && inspect_no_escape[(
unsigned char)*p]) p++;
8180 if (p >= pend)
break;
8183 n = rb_enc_precise_mbclen(p, pend, enc);
8185 if (p > prev) str_buf_cat(result, prev, p - prev);
8186 n = rb_enc_mbminlen(enc);
8188 n = (int)(pend - p);
8190 snprintf(buf, CHAR_ESC_LEN,
"\\x%02X", *p & 0377);
8191 str_buf_cat(result, buf, strlen(buf));
8197 c = rb_enc_mbc_to_codepoint(p, pend, enc);
8199 if ((asciicompat || unicode_p) &&
8200 (c ==
'"'|| c ==
'\\' ||
8205 (cc ==
'$' || cc ==
'@' || cc ==
'{'))))) {
8206 if (p - n > prev) str_buf_cat(result, prev, p - n - prev);
8207 str_buf_cat2(result,
"\\");
8208 if (asciicompat || enc == resenc) {
8214 case '\n': cc =
'n';
break;
8215 case '\r': cc =
'r';
break;
8216 case '\t': cc =
't';
break;
8217 case '\f': cc =
'f';
break;
8218 case '\013': cc =
'v';
break;
8219 case '\010': cc =
'b';
break;
8220 case '\007': cc =
'a';
break;
8221 case 033: cc =
'e';
break;
8222 default: cc = 0;
break;
8225 if (p - n > prev) str_buf_cat(result, prev, p - n - prev);
8228 str_buf_cat(result, buf, 2);
8241 (asciicompat && rb_enc_isascii(c, enc) &&
ISPRINT(c))) {
8245 if (p - n > prev) str_buf_cat(result, prev, p - n - prev);
8246 rb_str_buf_cat_escaped_char(result, c, unicode_p);
8251 if (p > prev) str_buf_cat(result, prev, p - prev);
8252 str_buf_cat2(result,
"\"");
8257#define IS_EVSTR(p,e) ((p) < (e) && (*(p) == '$' || *(p) == '@' || *(p) == '{'))
8270 int encidx = rb_enc_get_index(str);
8273 const char *p, *pend;
8276 int u8 = (encidx == rb_utf8_encindex());
8277 static const char nonascii_suffix[] =
".dup.force_encoding(\"%s\")";
8280 if (!rb_enc_asciicompat(enc)) {
8282 len += strlen(enc->name);
8285 p = RSTRING_PTR(str); pend = p + RSTRING_LEN(str);
8288 unsigned char c = *p++;
8291 case '"':
case '\\':
8292 case '\n':
case '\r':
8293 case '\t':
case '\f':
8294 case '\013':
case '\010':
case '\007':
case '\033':
8299 clen = IS_EVSTR(p, pend) ? 2 : 1;
8307 if (u8 && c > 0x7F) {
8308 int n = rb_enc_precise_mbclen(p-1, pend, enc);
8310 unsigned int cc = rb_enc_mbc_to_codepoint(p-1, pend, enc);
8313 else if (cc <= 0xFFFFF)
8326 if (clen > LONG_MAX -
len) {
8333 p = RSTRING_PTR(str); pend = p + RSTRING_LEN(str);
8334 q = RSTRING_PTR(result); qend = q +
len + 1;
8338 unsigned char c = *p++;
8340 if (c ==
'"' || c ==
'\\') {
8344 else if (c ==
'#') {
8345 if (IS_EVSTR(p, pend)) *q++ =
'\\';
8348 else if (c ==
'\n') {
8352 else if (c ==
'\r') {
8356 else if (c ==
'\t') {
8360 else if (c ==
'\f') {
8364 else if (c ==
'\013') {
8368 else if (c ==
'\010') {
8372 else if (c ==
'\007') {
8376 else if (c ==
'\033') {
8386 int n = rb_enc_precise_mbclen(p-1, pend, enc) - 1;
8388 int cc = rb_enc_mbc_to_codepoint(p-1, pend, enc);
8391 snprintf(q, qend-q,
"u%04X", cc);
8393 snprintf(q, qend-q,
"u{%X}", cc);
8398 snprintf(q, qend-q,
"x%02X", c);
8404 if (!rb_enc_asciicompat(enc)) {
8405 snprintf(q, qend-q, nonascii_suffix, enc->name);
8406 encidx = rb_ascii8bit_encindex();
8409 rb_enc_associate_index(result, encidx);
8415unescape_ascii(
unsigned int c)
8439undump_after_backslash(
VALUE undumped,
const char **ss,
const char *s_end,
rb_encoding **penc,
bool *utf8,
bool *binary)
8441 const char *s = *ss;
8445 unsigned char buf[6];
8463 *buf = unescape_ascii(*s);
8475 if (enc_utf8 == NULL) enc_utf8 = rb_utf8_encoding();
8476 if (*penc != enc_utf8) {
8478 rb_enc_associate(undumped, enc_utf8);
8495 if (hexlen == 0 || hexlen > 6) {
8501 if (0xd800 <= c && c <= 0xdfff) {
8504 codelen = rb_enc_mbcput(c, (
char *)buf, *penc);
8514 if (0xd800 <= c && c <= 0xdfff) {
8517 codelen = rb_enc_mbcput(c, (
char *)buf, *penc);
8547static VALUE rb_str_is_ascii_only_p(
VALUE str);
8559str_undump(
VALUE str)
8561 const char *s = RSTRING_PTR(str);
8564 VALUE undumped = rb_enc_str_new(s, 0L, enc);
8566 bool binary =
false;
8570 if (rb_str_is_ascii_only_p(str) ==
Qfalse) {
8573 if (!str_null_check(str, &w)) {
8576 if (RSTRING_LEN(str) < 2)
goto invalid_format;
8577 if (*s !=
'"')
goto invalid_format;
8595 static const char force_encoding_suffix[] =
".force_encoding(\"";
8596 static const char dup_suffix[] =
".dup";
8597 const char *encname;
8602 size =
sizeof(dup_suffix) - 1;
8603 if (s_end - s > size && memcmp(s, dup_suffix, size) == 0) s += size;
8605 size =
sizeof(force_encoding_suffix) - 1;
8606 if (s_end - s <= size)
goto invalid_format;
8607 if (memcmp(s, force_encoding_suffix, size) != 0)
goto invalid_format;
8611 rb_raise(
rb_eRuntimeError,
"dumped string contained Unicode escape but used force_encoding");
8615 s = memchr(s,
'"', s_end-s);
8617 if (!s)
goto invalid_format;
8618 if (s_end - s != 2)
goto invalid_format;
8619 if (s[0] !=
'"' || s[1] !=
')')
goto invalid_format;
8621 encidx = rb_enc_find_index2(encname, (
long)size);
8625 rb_enc_associate_index(undumped, encidx);
8635 undump_after_backslash(undumped, &s, s_end, &enc, &utf8, &binary);
8646 rb_raise(
rb_eRuntimeError,
"invalid dumped string; not wrapped with '\"' nor '\"...\".force_encoding(\"...\")' form");
8652 if (rb_enc_dummy_p(enc)) {
8659str_true_enc(
VALUE str)
8662 rb_str_check_dummy_enc(enc);
8666static OnigCaseFoldType
8667check_case_options(
int argc,
VALUE *argv, OnigCaseFoldType flags)
8672 rb_raise(rb_eArgError,
"too many options");
8673 if (argv[0]==sym_turkic) {
8674 flags |= ONIGENC_CASE_FOLD_TURKISH_AZERI;
8676 if (argv[1]==sym_lithuanian)
8677 flags |= ONIGENC_CASE_FOLD_LITHUANIAN;
8679 rb_raise(rb_eArgError,
"invalid second option");
8682 else if (argv[0]==sym_lithuanian) {
8683 flags |= ONIGENC_CASE_FOLD_LITHUANIAN;
8685 if (argv[1]==sym_turkic)
8686 flags |= ONIGENC_CASE_FOLD_TURKISH_AZERI;
8688 rb_raise(rb_eArgError,
"invalid second option");
8692 rb_raise(rb_eArgError,
"too many options");
8693 else if (argv[0]==sym_ascii)
8694 flags |= ONIGENC_CASE_ASCII_ONLY;
8695 else if (argv[0]==sym_fold) {
8696 if ((flags & (ONIGENC_CASE_UPCASE|ONIGENC_CASE_DOWNCASE)) == ONIGENC_CASE_DOWNCASE)
8697 flags ^= ONIGENC_CASE_FOLD|ONIGENC_CASE_DOWNCASE;
8699 rb_raise(rb_eArgError,
"option :fold only allowed for downcasing");
8702 rb_raise(rb_eArgError,
"invalid option");
8709 if ((flags & ONIGENC_CASE_ASCII_ONLY) && (enc==rb_utf8_encoding() ||
rb_enc_mbmaxlen(enc) == 1))
8711 return !(flags & ONIGENC_CASE_FOLD_TURKISH_AZERI) &&
8716#define CASE_MAPPING_ADDITIONAL_LENGTH 20
8717#ifndef CASEMAP_DEBUG
8718# define CASEMAP_DEBUG 0
8726 OnigUChar space[FLEX_ARY_LEN];
8730mapping_buffer_free(
void *p)
8734 while (current_buffer) {
8735 previous_buffer = current_buffer;
8736 current_buffer = current_buffer->next;
8737 ruby_xfree_sized(previous_buffer, offsetof(
mapping_buffer, space) + previous_buffer->capa);
8743 {0, mapping_buffer_free,},
8744 0, 0, RUBY_TYPED_THREAD_SAFE_FREE | RUBY_TYPED_WB_PROTECTED
8752 const OnigUChar *source_current, *source_end;
8753 int target_length = 0;
8754 VALUE buffer_anchor;
8757 size_t buffer_count = 0;
8758 int buffer_length_or_invalid;
8760 if (RSTRING_LEN(source) == 0)
return str_duplicate(
rb_cString, source);
8762 source_current = (OnigUChar*)RSTRING_PTR(source);
8767 while (source_current < source_end) {
8769 size_t capa = (size_t)(source_end-source_current)*++buffer_count + CASE_MAPPING_ADDITIONAL_LENGTH;
8770 if (CASEMAP_DEBUG) {
8771 fprintf(stderr,
"Buffer allocation, capa is %"PRIuSIZE
"\n",
capa);
8774 *pre_buffer = current_buffer;
8775 pre_buffer = ¤t_buffer->next;
8776 current_buffer->next = NULL;
8777 current_buffer->capa =
capa;
8778 buffer_length_or_invalid = enc->case_map(flags,
8779 &source_current, source_end,
8780 current_buffer->space,
8781 current_buffer->space+current_buffer->capa,
8783 if (buffer_length_or_invalid < 0) {
8784 current_buffer =
DATA_PTR(buffer_anchor);
8786 mapping_buffer_free(current_buffer);
8787 rb_raise(rb_eArgError,
"input string invalid");
8789 target_length += current_buffer->used = buffer_length_or_invalid;
8791 if (CASEMAP_DEBUG) {
8792 fprintf(stderr,
"Buffer count is %"PRIuSIZE
"\n", buffer_count);
8795 if (buffer_count==1) {
8796 target =
rb_str_new((
const char*)current_buffer->space, target_length);
8799 char *target_current;
8802 target_current = RSTRING_PTR(target);
8803 current_buffer =
DATA_PTR(buffer_anchor);
8804 while (current_buffer) {
8805 memcpy(target_current, current_buffer->space, current_buffer->used);
8806 target_current += current_buffer->used;
8807 current_buffer = current_buffer->next;
8810 current_buffer =
DATA_PTR(buffer_anchor);
8812 mapping_buffer_free(current_buffer);
8817 str_enc_copy_direct(target, source);
8826 const OnigUChar *source_current, *source_end;
8827 OnigUChar *target_current, *target_end;
8828 long old_length = RSTRING_LEN(source);
8829 int length_or_invalid;
8831 if (old_length == 0)
return Qnil;
8833 source_current = (OnigUChar*)RSTRING_PTR(source);
8835 if (source == target) {
8836 target_current = (OnigUChar*)source_current;
8837 target_end = (OnigUChar*)source_end;
8840 target_current = (OnigUChar*)RSTRING_PTR(target);
8844 length_or_invalid = onigenc_ascii_only_case_map(flags,
8845 &source_current, source_end,
8846 target_current, target_end, enc);
8847 if (length_or_invalid < 0)
8848 rb_raise(rb_eArgError,
"input string invalid");
8849 if (CASEMAP_DEBUG && length_or_invalid != old_length) {
8850 fprintf(stderr,
"problem with rb_str_ascii_casemap"
8851 "; old_length=%ld, new_length=%d\n", old_length, length_or_invalid);
8852 rb_raise(rb_eArgError,
"internal problem with rb_str_ascii_casemap"
8853 "; old_length=%ld, new_length=%d\n", old_length, length_or_invalid);
8856 str_enc_copy(target, source);
8862upcase_single(
VALUE str)
8864 char *s = RSTRING_PTR(str), *send =
RSTRING_END(str);
8865 bool modified =
false;
8868 unsigned int c = *(
unsigned char*)s;
8870 if (
'a' <= c && c <=
'z') {
8871 *s =
'A' + (c -
'a');
8892rb_str_upcase_bang(
int argc,
VALUE *argv,
VALUE str)
8895 OnigCaseFoldType flags = ONIGENC_CASE_UPCASE;
8897 flags = check_case_options(argc, argv, flags);
8898 str_modify_keep_cr(str);
8899 enc = str_true_enc(str);
8900 if (case_option_single_p(flags, enc, str)) {
8901 if (upcase_single(str))
8902 flags |= ONIGENC_CASE_MODIFIED;
8904 else if (flags&ONIGENC_CASE_ASCII_ONLY)
8905 rb_str_ascii_casemap(str, str, &flags, enc);
8907 str_shared_replace(str, rb_str_casemap(str, &flags, enc));
8909 if (ONIGENC_CASE_MODIFIED&flags)
return str;
8922rb_str_upcase(
int argc,
VALUE *argv,
VALUE str)
8925 OnigCaseFoldType flags = ONIGENC_CASE_UPCASE;
8928 flags = check_case_options(argc, argv, flags);
8929 enc = str_true_enc(str);
8930 if (case_option_single_p(flags, enc, str)) {
8931 ret =
rb_str_new(RSTRING_PTR(str), RSTRING_LEN(str));
8932 str_enc_copy_direct(ret, str);
8935 else if (flags&ONIGENC_CASE_ASCII_ONLY) {
8937 rb_str_ascii_casemap(str, ret, &flags, enc);
8940 ret = rb_str_casemap(str, &flags, enc);
8947downcase_single(
VALUE str)
8949 char *s = RSTRING_PTR(str), *send =
RSTRING_END(str);
8950 bool modified =
false;
8953 unsigned int c = *(
unsigned char*)s;
8955 if (
'A' <= c && c <=
'Z') {
8956 *s =
'a' + (c -
'A');
8978rb_str_downcase_bang(
int argc,
VALUE *argv,
VALUE str)
8981 OnigCaseFoldType flags = ONIGENC_CASE_DOWNCASE;
8983 flags = check_case_options(argc, argv, flags);
8984 str_modify_keep_cr(str);
8985 enc = str_true_enc(str);
8986 if (case_option_single_p(flags, enc, str)) {
8987 if (downcase_single(str))
8988 flags |= ONIGENC_CASE_MODIFIED;
8990 else if (flags&ONIGENC_CASE_ASCII_ONLY)
8991 rb_str_ascii_casemap(str, str, &flags, enc);
8993 str_shared_replace(str, rb_str_casemap(str, &flags, enc));
8995 if (ONIGENC_CASE_MODIFIED&flags)
return str;
9009rb_str_downcase(
int argc,
VALUE *argv,
VALUE str)
9012 OnigCaseFoldType flags = ONIGENC_CASE_DOWNCASE;
9015 flags = check_case_options(argc, argv, flags);
9016 enc = str_true_enc(str);
9017 if (case_option_single_p(flags, enc, str)) {
9018 ret =
rb_str_new(RSTRING_PTR(str), RSTRING_LEN(str));
9019 str_enc_copy_direct(ret, str);
9020 downcase_single(ret);
9022 else if (flags&ONIGENC_CASE_ASCII_ONLY) {
9024 rb_str_ascii_casemap(str, ret, &flags, enc);
9027 ret = rb_str_casemap(str, &flags, enc);
9034capitalize_single(
VALUE str)
9036 char *s = RSTRING_PTR(str), *send =
RSTRING_END(str);
9037 bool modified =
false;
9040 unsigned int c = (
unsigned char)*s;
9042 if (
'a' <= c && c <=
'z') {
9043 *s =
'A' + (c -
'a');
9049 unsigned int c = (
unsigned char)*s;
9051 if (
'A' <= c && c <=
'Z') {
9052 *s =
'a' + (c -
'A');
9074rb_str_capitalize_bang(
int argc,
VALUE *argv,
VALUE str)
9077 OnigCaseFoldType flags = ONIGENC_CASE_UPCASE | ONIGENC_CASE_TITLECASE;
9079 flags = check_case_options(argc, argv, flags);
9080 str_modify_keep_cr(str);
9081 enc = str_true_enc(str);
9082 if (RSTRING_LEN(str) == 0 || !RSTRING_PTR(str))
return Qnil;
9083 if (case_option_single_p(flags, enc, str)) {
9084 if (capitalize_single(str))
9085 flags |= ONIGENC_CASE_MODIFIED;
9087 else if (flags&ONIGENC_CASE_ASCII_ONLY)
9088 rb_str_ascii_casemap(str, str, &flags, enc);
9090 str_shared_replace(str, rb_str_casemap(str, &flags, enc));
9092 if (ONIGENC_CASE_MODIFIED&flags)
return str;
9106rb_str_capitalize(
int argc,
VALUE *argv,
VALUE str)
9109 OnigCaseFoldType flags = ONIGENC_CASE_UPCASE | ONIGENC_CASE_TITLECASE;
9112 flags = check_case_options(argc, argv, flags);
9113 enc = str_true_enc(str);
9114 if (RSTRING_LEN(str) == 0 || !RSTRING_PTR(str))
return str;
9115 if (case_option_single_p(flags, enc, str)) {
9116 ret =
rb_str_new(RSTRING_PTR(str), RSTRING_LEN(str));
9117 str_enc_copy_direct(ret, str);
9118 capitalize_single(ret);
9120 else if (flags&ONIGENC_CASE_ASCII_ONLY) {
9122 rb_str_ascii_casemap(str, ret, &flags, enc);
9125 ret = rb_str_casemap(str, &flags, enc);
9144rb_str_swapcase_bang(
int argc,
VALUE *argv,
VALUE str)
9147 OnigCaseFoldType flags = ONIGENC_CASE_UPCASE | ONIGENC_CASE_DOWNCASE;
9149 flags = check_case_options(argc, argv, flags);
9150 str_modify_keep_cr(str);
9151 enc = str_true_enc(str);
9152 if (flags&ONIGENC_CASE_ASCII_ONLY)
9153 rb_str_ascii_casemap(str, str, &flags, enc);
9155 str_shared_replace(str, rb_str_casemap(str, &flags, enc));
9157 if (ONIGENC_CASE_MODIFIED&flags)
return str;
9171rb_str_swapcase(
int argc,
VALUE *argv,
VALUE str)
9174 OnigCaseFoldType flags = ONIGENC_CASE_UPCASE | ONIGENC_CASE_DOWNCASE;
9177 flags = check_case_options(argc, argv, flags);
9178 enc = str_true_enc(str);
9179 if (RSTRING_LEN(str) == 0 || !RSTRING_PTR(str))
return str_duplicate(
rb_cString, str);
9180 if (flags&ONIGENC_CASE_ASCII_ONLY) {
9182 rb_str_ascii_casemap(str, ret, &flags, enc);
9185 ret = rb_str_casemap(str, &flags, enc);
9190typedef unsigned char *USTR;
9194 unsigned int now, max;
9195 const char *p, *pend;
9206 if (t->p == t->pend)
return -1;
9207 if (rb_enc_ascget(t->p, t->pend, &n, enc) ==
'\\' && t->p + n < t->pend) {
9210 t->now = rb_enc_codepoint_len(t->p, t->pend, &n, enc);
9212 if (rb_enc_ascget(t->p, t->pend, &n, enc) ==
'-' && t->p + n < t->pend) {
9214 if (t->p < t->pend) {
9215 unsigned int c = rb_enc_codepoint_len(t->p, t->pend, &n, enc);
9218 if (t->now < 0x80 && c < 0x80) {
9219 rb_raise(rb_eArgError,
9220 "invalid range \"%c-%c\" in string transliteration",
9224 rb_raise(rb_eArgError,
"invalid range in string transliteration");
9228 else if (t->now < c) {
9237 while (ONIGENC_CODE_TO_MBCLEN(enc, ++t->now) <= 0) {
9238 if (t->now == t->max) {
9243 if (t->now < t->max) {
9259 const unsigned int errc = -1;
9260 unsigned int trans[256];
9262 struct tr trsrc, trrepl;
9264 unsigned int c, c0, last = 0;
9265 int modify = 0, i, l;
9266 unsigned char *s, *send;
9268 int singlebyte = single_byte_optimizable(str);
9272#define CHECK_IF_ASCII(c) \
9273 (void)((cr == ENC_CODERANGE_7BIT && !rb_isascii(c)) ? \
9274 (cr = ENC_CODERANGE_VALID) : 0)
9278 if (RSTRING_LEN(str) == 0 || !RSTRING_PTR(str))
return Qnil;
9279 if (RSTRING_LEN(repl) == 0) {
9280 return rb_str_delete_bang(1, &src, str);
9284 e1 = rb_enc_check(str, src);
9285 e2 = rb_enc_check(str, repl);
9290 enc = rb_enc_check(src, repl);
9292 trsrc.p = RSTRING_PTR(src); trsrc.pend = trsrc.p + RSTRING_LEN(src);
9293 if (RSTRING_LEN(src) > 1 &&
9294 rb_enc_ascget(trsrc.p, trsrc.pend, &l, enc) ==
'^' &&
9295 trsrc.p + l < trsrc.pend) {
9299 trrepl.p = RSTRING_PTR(repl);
9300 trrepl.pend = trrepl.p + RSTRING_LEN(repl);
9301 trsrc.gen = trrepl.gen = 0;
9302 trsrc.now = trrepl.now = 0;
9303 trsrc.max = trrepl.max = 0;
9306 for (i=0; i<256; i++) {
9309 while ((c = trnext(&trsrc, enc)) != errc) {
9314 if (!hash) hash = rb_hash_new();
9318 while ((c = trnext(&trrepl, enc)) != errc)
9321 for (i=0; i<256; i++) {
9322 if (trans[i] != errc) {
9330 for (i=0; i<256; i++) {
9333 while ((c = trnext(&trsrc, enc)) != errc) {
9334 r = trnext(&trrepl, enc);
9335 if (r == errc) r = trrepl.now;
9338 if (rb_enc_codelen(r, enc) != 1) singlebyte = 0;
9341 if (!hash) hash = rb_hash_new();
9349 str_modify_keep_cr(str);
9350 s = (
unsigned char *)RSTRING_PTR(str); send = (
unsigned char *)
RSTRING_END(str);
9351 termlen = rb_enc_mbminlen(enc);
9354 long offset, max = RSTRING_LEN(str);
9355 unsigned int save = -1;
9356 unsigned char *buf =
ALLOC_N(
unsigned char, max + termlen), *t = buf;
9361 int r = rb_enc_precise_mbclen((
char *)s, (
char *)send, e1);
9363 SIZED_FREE_N(buf, max + termlen);
9364 rb_raise(rb_eArgError,
"invalid byte sequence in %s", rb_enc_name(e1));
9367 c0 = c = rb_enc_mbc_to_codepoint((
char *)s, (
char *)send, e1);
9369 tlen = enc == e1 ? clen : rb_enc_codelen(c, enc);
9378 if (cflag) c = last;
9381 else if (cflag) c = errc;
9387 if (c != (
unsigned int)-1) {
9393 tlen = rb_enc_codelen(c, enc);
9399 if (enc != e1) may_modify = 1;
9401 if ((offset = t - buf) + tlen > max) {
9402 size_t MAYBE_UNUSED(old) = max + termlen;
9403 max = offset + tlen + (send - s);
9404 SIZED_REALLOC_N(buf,
unsigned char, max + termlen, old);
9407 rb_enc_mbcput(c, t, enc);
9408 if (may_modify && memcmp(s, t, tlen) != 0) {
9414 if (!STR_EMBED_P(str)) {
9415 SIZED_FREE_N(STR_HEAP_PTR(str), STR_HEAP_SIZE(str));
9417 TERM_FILL((
char *)t, termlen);
9418 RSTRING(str)->as.heap.ptr = (
char *)buf;
9419 STR_SET_LEN(str, t - buf);
9420 STR_SET_NOEMBED(str);
9421 RSTRING(str)->as.heap.aux.capa = max;
9425 c = (
unsigned char)*s;
9426 if (trans[c] != errc) {
9443 long offset, max = (long)((send - s) * 1.2);
9444 unsigned char *buf =
ALLOC_N(
unsigned char, max + termlen), *t = buf;
9449 int r = rb_enc_precise_mbclen((
char *)s, (
char *)send, e1);
9451 SIZED_FREE_N(buf, max + termlen);
9452 rb_raise(rb_eArgError,
"invalid byte sequence in %s", rb_enc_name(e1));
9455 c0 = c = rb_enc_mbc_to_codepoint((
char *)s, (
char *)send, e1);
9457 tlen = enc == e1 ? clen : rb_enc_codelen(c, enc);
9465 if (cflag) c = last;
9468 else if (cflag) c = errc;
9472 c = cflag ? last : errc;
9475 tlen = rb_enc_codelen(c, enc);
9480 if (enc != e1) may_modify = 1;
9482 if ((offset = t - buf) + tlen > max) {
9483 size_t MAYBE_UNUSED(old) = max + termlen;
9484 max = offset + tlen + (long)((send - s) * 1.2);
9485 SIZED_REALLOC_N(buf,
unsigned char, max + termlen, old);
9489 rb_enc_mbcput(c, t, enc);
9490 if (may_modify && memcmp(s, t, tlen) != 0) {
9497 if (!STR_EMBED_P(str)) {
9498 SIZED_FREE_N(STR_HEAP_PTR(str), STR_HEAP_SIZE(str));
9500 TERM_FILL((
char *)t, termlen);
9501 RSTRING(str)->as.heap.ptr = (
char *)buf;
9502 STR_SET_LEN(str, t - buf);
9503 STR_SET_NOEMBED(str);
9504 RSTRING(str)->as.heap.aux.capa = max;
9510 rb_enc_associate(str, enc);
9520 size_t initial_capa;
9524tr_buffer_init(
struct tr_buffer *buffer,
size_t initial_capa)
9526 if (initial_capa < 32) {
9529 *buffer = (
struct tr_buffer){ .initial_capa = initial_capa };
9533tr_buffer_ensure_capa(
struct tr_buffer *buffer,
size_t extra_capa)
9535 size_t offset = buffer->ptr - buffer->buf;
9536 size_t required_capa = offset + extra_capa;
9537 if (UNLIKELY(buffer->capa < required_capa)) {
9538 size_t new_capa = buffer->capa ? buffer->capa : buffer->initial_capa;
9540 while (new_capa < required_capa) {
9541 new_capa = (size_t)(new_capa * 1.2);
9543 SIZED_REALLOC_N(buffer->buf,
unsigned char, new_capa, buffer->capa);
9544 buffer->ptr = buffer->buf + offset;
9545 buffer->capa = new_capa;
9550tr_buffer_append(
struct tr_buffer *buffer,
const unsigned char *ptr,
size_t len)
9553 tr_buffer_ensure_capa(buffer,
len);
9554 memcpy(buffer->ptr, ptr,
len);
9562 tr_buffer_append(buffer, (
unsigned char *)RSTRING_PTR(str), RSTRING_LEN(str));
9568 tr_buffer_ensure_capa(buffer, 4);
9569 buffer->ptr += rb_enc_mbcput(codepoint, buffer->ptr, enc);
9576 SIZED_FREE_N(buffer->buf, buffer->capa);
9593tr_trans_pairs_coerce_i(st_data_t key, st_data_t value, st_data_t _args)
9596 struct tr_pair *pair = &args->pairs[args->index];
9604 if (RSTRING_LEN(search) != 1 && str_strlen(search, NULL) != 1) {
9605 rb_raise(rb_eArgError,
"keys must be of size 1");
9608 args->enc = rb_enc_check_multi_str(args->enc, &args->cr, search);
9609 args->enc = rb_enc_check_multi_str(args->enc, &args->cr, replace);
9611 pair->search = search;
9612 pair->replace = replace;
9616#define TR_TRANS_PAIRS_SIMD_MAX_NEEDLES 16
9619 const unsigned char *s;
9620 const unsigned char *send;
9623 unsigned char needles[TR_TRANS_PAIRS_SIMD_MAX_NEEDLES];
9624 unsigned int needles_count;
9625#ifdef HAVE_SIMD_NEON
9626 uint64_t matches_bitmap;
9628#ifdef HAVE_SIMD_SSE2
9633 VALUE trans_table[256];
9639 while (search->s < search->send) {
9640 VALUE repl = search->trans_table[*search->s];
9641 if (UNLIKELY(repl)) {
9651#ifdef HAVE_SIMD_SSE2
9656 size_t trailing_zeros = (size_t)ntz_int32(search->matches_bitmap);
9658 RUBY_ASSERT(trailing_zeros < (
sizeof(search->matches_bitmap) * CHAR_BIT));
9659 search->matches_bitmap >>= trailing_zeros;
9660 search->s += trailing_zeros;
9663 return search->trans_table[*search->s];
9669 const unsigned int needles_count = search->needles_count;
9670 if (needles_count) {
9673 if (search->matches_bitmap) {
9674 return tr_trans_pairs_next_match_sse2(search);
9677 if ((
size_t)(search->send - search->s) >=
sizeof(__m128i)) {
9679 __m128i masks[TR_TRANS_PAIRS_SIMD_MAX_NEEDLES];
9680 for (i = 0; i < needles_count; i++) {
9681 masks[i] = _mm_set1_epi8(search->needles[i]);
9685 const __m128i bytes = _mm_loadu_si128((__m128i
const *)search->s);
9687 __m128i matches[TR_TRANS_PAIRS_SIMD_MAX_NEEDLES];
9688 for (i = 0; i < needles_count; i++) {
9689 matches[i] = _mm_cmpeq_epi8(bytes, masks[i]);
9692 for (i = 1; i < needles_count; i++) {
9693 matches[0] = _mm_or_si128(matches[0], matches[i]);
9696 const int bitmap = _mm_movemask_epi8(matches[0]);
9699 search->matches_bitmap = bitmap;
9700 return tr_trans_pairs_next_match_sse2(search);
9702 search->s +=
sizeof(__m128i);
9703 }
while ((
size_t)(search->send - search->s) >=
sizeof(__m128i));
9706 return tr_trans_pairs_search_basic(search);
9709#define tr_trans_pairs_search_impl tr_trans_pairs_search_sse2
9712#ifdef HAVE_SIMD_NEON
9717 size_t trailing_zeros = (size_t)ntz_int64(search->matches_bitmap);
9720 RUBY_ASSERT(trailing_zeros < (
sizeof(search->matches_bitmap) * CHAR_BIT));
9721 search->matches_bitmap >>= trailing_zeros;
9722 search->s += trailing_zeros / 4;
9725 return search->trans_table[*search->s];
9731 const unsigned int needles_count = search->needles_count;
9732 if (needles_count) {
9735 if (search->matches_bitmap) {
9736 return tr_trans_pairs_next_match_neon(search);
9739 if ((
size_t)(search->send - search->s) >=
sizeof(uint8x16_t)) {
9741 uint8x16_t masks[TR_TRANS_PAIRS_SIMD_MAX_NEEDLES];
9742 for (i = 0; i < needles_count; i++) {
9743 masks[i] = vdupq_n_u8(search->needles[i]);
9747 const uint8x16_t bytes = vld1q_u8(search->s);
9749 uint8x16_t matches[TR_TRANS_PAIRS_SIMD_MAX_NEEDLES];
9750 for (i = 0; i < needles_count; i++) {
9751 matches[i] = vceqq_u8(bytes, masks[i]);
9754 for (i = 1; i < needles_count; i++) {
9755 matches[0] = vorrq_u8(matches[0], matches[i]);
9758 const uint8x8_t res = vshrn_n_u16(vreinterpretq_u16_u8(matches[0]), 4);
9759 const uint64_t bitmap = vget_lane_u64(vreinterpret_u64_u8(res), 0);
9762 search->matches_bitmap = bitmap & 0x8888888888888888ull;
9763 return tr_trans_pairs_next_match_neon(search);
9765 search->s +=
sizeof(uint8x16_t);
9766 }
while ((
size_t)(search->send - search->s) >=
sizeof(uint8x16_t));
9769 return tr_trans_pairs_search_basic(search);
9772#define tr_trans_pairs_search_impl tr_trans_pairs_search_neon
9775#ifndef tr_trans_pairs_search_impl
9776#define tr_trans_pairs_search_impl tr_trans_pairs_search_basic
9784 search->matches_bitmap >>= 1;
9793 mustnot_broken(str);
9796 if (RSTRING_LEN(str) == 0 || !RSTRING_PTR(str) || pairs_count == 0)
return Qnil;
9801 int cr = rb_enc_str_coderange(str);
9815 pairs_count = coerce_args.index;
9819 const unsigned char *sstart = (
unsigned char *)RSTRING_PTR(str);
9820 long str_len = RSTRING_LEN(str);
9821 int termlen = rb_enc_mbminlen(e1);
9824 tr_buffer_init(&buffer, str_len);
9825 bool modify =
false;
9827 if (RB_LIKELY(rb_str_encindex_fastpath(rb_enc_to_index(e1)))) {
9831 .send = sstart + str_len,
9834 for (
size_t index = 0; index < pairs_count; index++) {
9835 struct tr_pair *pair = &pairs[index];
9837 char *ptr = RSTRING_PTR(pair->search);
9838 unsigned int codepoint = rb_enc_mbc_to_codepoint(ptr,
RSTRING_END(pair->search), e1);
9840 const unsigned char first_byte = (
unsigned char)*ptr;
9843 if (pairs_count <= TR_TRANS_PAIRS_SIMD_MAX_NEEDLES) {
9844 search.needles[index] = first_byte;
9845 search.needles_count++;
9849 if (rb_enc_codelen(codepoint, e1) == 1) {
9850 search.trans_table[first_byte] = pair->replace;
9853 search.trans_table[first_byte] =
Qundef;
9855 hash =
rb_obj_hide(rb_hash_new_capa(pairs_count));
9857 rb_hash_aset(hash,
UINT2NUM(codepoint), pair->replace);
9861 const unsigned char *checkpoint = search.s;
9863 while ((repl = tr_trans_pairs_search_impl(&search))) {
9866 if (UNLIKELY(repl ==
Qundef)) {
9867 unsigned int c = rb_enc_mbc_to_codepoint((
char *)search.s, (
char *)search.send, e1);
9868 clen = rb_enc_codelen(c, e1);
9869 repl = rb_hash_lookup2(hash,
UINT2NUM(c), 0);
9871 tr_trans_pairs_consume_match(&search);
9879 if (checkpoint < search.s) {
9880 tr_buffer_append(&buffer, checkpoint, search.s - checkpoint);
9882 tr_buffer_append_str(&buffer, repl);
9883 checkpoint = search.s + clen;
9884 tr_trans_pairs_consume_match(&search);
9891 if (modify && checkpoint < search.s) {
9892 tr_buffer_append(&buffer, checkpoint, search.s - checkpoint);
9896 const unsigned char *s = sstart;
9897 const unsigned char *send = sstart + str_len;
9899 hash =
rb_obj_hide(rb_hash_new_capa(pairs_count));
9901 for (
size_t index = 0; index < pairs_count; index++) {
9902 struct tr_pair *pair = &pairs[index];
9904 unsigned int codepoint = rb_enc_mbc_to_codepoint(RSTRING_PTR(pair->search),
RSTRING_END(pair->search), e1);
9905 rb_hash_aset(hash,
UINT2NUM(codepoint), pair->replace);
9909 bool may_modify =
false;
9911 int r = rb_enc_precise_mbclen((
char *)s, (
char *)send, e1);
9913 tr_buffer_free(&buffer);
9914 rb_raise(rb_eArgError,
"invalid byte sequence in %s", rb_enc_name(e1));
9917 unsigned int c = rb_enc_mbc_to_codepoint((
char *)s, (
char *)send, e1);
9918 unsigned int c0 = c;
9920 long tlen = enc == e1 ? clen : rb_enc_codelen(c, e1);
9923 if (
NIL_P(replacement)) {
9924 tlen = enc == e1 ? clen : rb_enc_codelen(c, enc);
9926 if (enc != e1) may_modify =
true;
9929 tlen = RSTRING_LEN(replacement);
9933 if (
NIL_P(replacement)) {
9934 tr_buffer_mbcput(&buffer, c, enc);
9937 tr_buffer_append_str(&buffer, replacement);
9940 if (may_modify && memcmp(s, buffer.ptr - tlen, tlen) != 0) {
9958 if (!STR_EMBED_P(str)) {
9959 SIZED_FREE_N(STR_HEAP_PTR(str), STR_HEAP_SIZE(str));
9961 tr_buffer_ensure_capa(&buffer, termlen);
9962 TERM_FILL((
char *)buffer.ptr, termlen);
9963 RSTRING(str)->as.heap.ptr = (
char *)buffer.buf;
9964 STR_SET_LEN(str, buffer.ptr - buffer.buf);
9965 STR_SET_NOEMBED(str);
9966 RSTRING(str)->as.heap.aux.capa = buffer.capa - termlen;
9972 rb_enc_associate(str, e1);
9990rb_str_tr_bang(
int argc,
VALUE *argv,
VALUE str)
9995 VALUE pairs = argv[0];
9996 return tr_trans_pairs(str, pairs);
9999 VALUE src = argv[0], repl = argv[1];
10000 return tr_trans(str, src, repl, 0);
10064 VALUE pairs = argv[0];
10065 VALUE result = tr_trans_pairs(str, pairs);
10066 if (
NIL_P(result)) result = str;
10070 VALUE src = argv[0], repl = argv[1];
10071 tr_trans(str, src, repl, 0);
10075#define TR_TABLE_MAX (UCHAR_MAX+1)
10076#define TR_TABLE_SIZE (TR_TABLE_MAX+1)
10078tr_setup_table(
VALUE str,
char stable[TR_TABLE_SIZE],
int first,
10081 const unsigned int errc = -1;
10082 char buf[TR_TABLE_MAX];
10085 VALUE table = 0, ptable = 0;
10086 int i, l, cflag = 0;
10088 tr.p = RSTRING_PTR(str);
tr.pend =
tr.p + RSTRING_LEN(str);
10089 tr.gen =
tr.now =
tr.max = 0;
10091 if (RSTRING_LEN(str) > 1 && rb_enc_ascget(
tr.p,
tr.pend, &l, enc) ==
'^') {
10096 for (i=0; i<TR_TABLE_MAX; i++) {
10099 stable[TR_TABLE_MAX] = cflag;
10101 else if (stable[TR_TABLE_MAX] && !cflag) {
10102 stable[TR_TABLE_MAX] = 0;
10104 for (i=0; i<TR_TABLE_MAX; i++) {
10108 while ((c = trnext(&
tr, enc)) != errc) {
10109 if (c < TR_TABLE_MAX) {
10110 buf[(
unsigned char)c] = !cflag;
10115 if (!table && (first || *tablep || stable[TR_TABLE_MAX])) {
10118 table = ptable ? ptable : rb_hash_new();
10122 table = rb_hash_new();
10127 if (table && (!ptable || (cflag ^ !
NIL_P(rb_hash_aref(ptable, key))))) {
10128 rb_hash_aset(table, key,
Qtrue);
10132 for (i=0; i<TR_TABLE_MAX; i++) {
10133 stable[i] = stable[i] && buf[i];
10135 if (!table && !cflag) {
10142tr_find(
unsigned int c,
const char table[TR_TABLE_SIZE],
VALUE del,
VALUE nodel)
10144 if (c < TR_TABLE_MAX) {
10145 return table[c] != 0;
10151 if (!
NIL_P(rb_hash_lookup(del, v)) &&
10152 (!nodel ||
NIL_P(rb_hash_lookup(nodel, v)))) {
10156 else if (nodel && !
NIL_P(rb_hash_lookup(nodel, v))) {
10159 return table[TR_TABLE_MAX] ? TRUE : FALSE;
10174rb_str_delete_bang(
int argc,
VALUE *argv,
VALUE str)
10176 char squeez[TR_TABLE_SIZE];
10178 char *s, *send, *t;
10179 VALUE del = 0, nodel = 0;
10181 int i, ascompat, cr;
10183 if (RSTRING_LEN(str) == 0 || !RSTRING_PTR(str))
return Qnil;
10185 for (i=0; i<argc; i++) {
10189 enc = rb_enc_check(str, s);
10190 tr_setup_table(s, squeez, i==0, &del, &nodel, enc);
10193 str_modify_keep_cr(str);
10194 ascompat = rb_enc_asciicompat(enc);
10195 s = t = RSTRING_PTR(str);
10202 if (ascompat && (c = *(
unsigned char*)s) < 0x80) {
10207 if (t != s) *t = c;
10213 c = rb_enc_codepoint_len(s, send, &clen, enc);
10215 if (tr_find(c, squeez, del, nodel)) {
10219 if (t != s) rb_enc_mbcput(c, t, enc);
10226 TERM_FILL(t, TERM_LEN(str));
10227 STR_SET_LEN(str, t - RSTRING_PTR(str));
10230 if (modify)
return str;
10244rb_str_delete(
int argc,
VALUE *argv,
VALUE str)
10247 rb_str_delete_bang(argc, argv, str);
10265rb_str_squeeze_bang(
int argc,
VALUE *argv,
VALUE str)
10267 char squeez[TR_TABLE_SIZE];
10269 VALUE del = 0, nodel = 0;
10270 unsigned char *s, *send, *t;
10272 int ascompat, singlebyte = single_byte_optimizable(str);
10276 enc = STR_ENC_GET(str);
10279 for (i=0; i<argc; i++) {
10283 enc = rb_enc_check(str, s);
10284 if (singlebyte && !single_byte_optimizable(s))
10286 tr_setup_table(s, squeez, i==0, &del, &nodel, enc);
10290 str_modify_keep_cr(str);
10291 s = t = (
unsigned char *)RSTRING_PTR(str);
10292 if (!s || RSTRING_LEN(str) == 0)
return Qnil;
10295 ascompat = rb_enc_asciicompat(enc);
10299 unsigned int c = *s++;
10300 if (c != save || (argc > 0 && !squeez[c])) {
10310 if (ascompat && (c = *s) < 0x80) {
10311 if (c != save || (argc > 0 && !squeez[c])) {
10317 c = rb_enc_codepoint_len((
char *)s, (
char *)send, &clen, enc);
10319 if (c != save || (argc > 0 && !tr_find(c, squeez, del, nodel))) {
10320 if (t != s) rb_enc_mbcput(c, t, enc);
10329 TERM_FILL((
char *)t, TERM_LEN(str));
10330 if ((
char *)t - RSTRING_PTR(str) != RSTRING_LEN(str)) {
10331 STR_SET_LEN(str, (
char *)t - RSTRING_PTR(str));
10335 if (modify)
return str;
10349rb_str_squeeze(
int argc,
VALUE *argv,
VALUE str)
10352 rb_str_squeeze_bang(argc, argv, str);
10372 return tr_trans(str, src, repl, 1);
10400 tr_trans(str, src, repl, 1);
10413rb_str_count(
int argc,
VALUE *argv,
VALUE str)
10415 char table[TR_TABLE_SIZE];
10417 VALUE del = 0, nodel = 0, tstr;
10418 const char *s, *send;
10427 enc = rb_enc_check(str, tstr);
10430 if (RSTRING_LEN(tstr) == 1 && rb_enc_asciicompat(enc) &&
10431 (ptstr = RSTRING_PTR(tstr),
10432 ONIGENC_IS_ALLOWED_REVERSE_MATCH(enc, (
const unsigned char *)ptstr, (
const unsigned char *)ptstr+1)) &&
10433 !is_broken_string(str)) {
10435 unsigned char c = rb_enc_codepoint_len(ptstr, ptstr+1, &clen, enc);
10437 s = RSTRING_PTR(str);
10438 if (!s || RSTRING_LEN(str) == 0)
return INT2FIX(0);
10441 if (*(
unsigned char*)s++ == c) n++;
10447 tr_setup_table(tstr, table, TRUE, &del, &nodel, enc);
10448 for (i=1; i<argc; i++) {
10451 enc = rb_enc_check(str, tstr);
10452 tr_setup_table(tstr, table, FALSE, &del, &nodel, enc);
10455 s = RSTRING_PTR(str);
10456 if (!s || RSTRING_LEN(str) == 0)
return INT2FIX(0);
10458 ascompat = rb_enc_asciicompat(enc);
10462 if (ascompat && (c = *(
unsigned char*)s) < 0x80) {
10470 c = rb_enc_codepoint_len(s, send, &clen, enc);
10471 if (tr_find(c, table, del, nodel)) {
10482rb_fs_check(
VALUE val)
10486 if (
NIL_P(val))
return 0;
10491static const char isspacetable[256] = {
10492 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0,
10493 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
10494 1, 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,
10507 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
10510#define ascii_isspace(c) isspacetable[(unsigned char)(c)]
10513split_string(
VALUE result,
VALUE str,
long beg,
long len,
long empty_count)
10515 if (empty_count >= 0 &&
len == 0) {
10516 return empty_count + 1;
10518 if (empty_count > 0) {
10523 }
while (--empty_count > 0);
10527 rb_yield(str_new_empty_String(str));
10528 }
while (--empty_count > 0);
10538 return empty_count;
10542 SPLIT_TYPE_AWK, SPLIT_TYPE_STRING, SPLIT_TYPE_REGEXP, SPLIT_TYPE_CHARS
10546literal_split_pattern(
VALUE spat, split_type_t default_type)
10554 return SPLIT_TYPE_CHARS;
10556 else if (rb_enc_asciicompat(enc)) {
10557 if (
len == 1 && ptr[0] ==
' ') {
10558 return SPLIT_TYPE_AWK;
10563 if (rb_enc_ascget(ptr, ptr +
len, &l, enc) ==
' ' &&
len == l) {
10564 return SPLIT_TYPE_AWK;
10567 return default_type;
10580rb_str_split_m(
int argc,
VALUE *argv,
VALUE str)
10585 split_type_t split_type;
10586 long beg, end, i = 0, empty_count = -1;
10591 if (
rb_scan_args(argc, argv,
"02", &spat, &limit) == 2) {
10593 if (lim <= 0) limit =
Qnil;
10594 else if (lim == 1) {
10595 if (RSTRING_LEN(str) == 0)
10606 if (
NIL_P(limit) && !lim) empty_count = 0;
10608 enc = STR_ENC_GET(str);
10609 split_type = SPLIT_TYPE_REGEXP;
10610 if (!
NIL_P(spat)) {
10611 spat = get_pat_quoted(spat, 0);
10613 else if (
NIL_P(spat = rb_fs)) {
10614 split_type = SPLIT_TYPE_AWK;
10616 else if (!(spat = rb_fs_check(spat))) {
10617 rb_raise(
rb_eTypeError,
"value of $; must be String or Regexp");
10622 if (split_type != SPLIT_TYPE_AWK) {
10627 split_type = literal_split_pattern(tmp, SPLIT_TYPE_REGEXP);
10628 if (split_type == SPLIT_TYPE_AWK) {
10630 split_type = SPLIT_TYPE_STRING;
10635 mustnot_broken(spat);
10636 split_type = literal_split_pattern(spat, SPLIT_TYPE_STRING);
10644#define SPLIT_STR(beg, len) ( \
10645 empty_count = split_string(result, str, beg, len, empty_count), \
10646 str_mod_check(str, str_start, str_len))
10649 const char *ptr = RSTRING_PTR(str);
10650 const char *
const str_start = ptr;
10651 const long str_len = RSTRING_LEN(str);
10652 const char *
const eptr = str_start + str_len;
10653 if (split_type == SPLIT_TYPE_AWK) {
10654 const char *bptr = ptr;
10660 if (is_ascii_string(str)) {
10661 while (ptr < eptr) {
10662 c = (
unsigned char)*ptr++;
10664 if (ascii_isspace(c)) {
10670 if (!
NIL_P(limit) && lim <= i)
break;
10673 else if (ascii_isspace(c)) {
10674 SPLIT_STR(beg, end-beg);
10677 if (!
NIL_P(limit)) ++i;
10685 while (ptr < eptr) {
10688 c = rb_enc_codepoint_len(ptr, eptr, &n, enc);
10697 if (!
NIL_P(limit) && lim <= i)
break;
10701 SPLIT_STR(beg, end-beg);
10704 if (!
NIL_P(limit)) ++i;
10712 else if (split_type == SPLIT_TYPE_STRING) {
10713 const char *substr_start = ptr;
10714 const char *sptr = RSTRING_PTR(spat);
10715 long slen = RSTRING_LEN(spat);
10718 mustnot_broken(str);
10719 enc = rb_enc_check(str, spat);
10720 while (ptr < eptr &&
10721 (end =
rb_memsearch(sptr, slen, ptr, eptr - ptr, enc)) >= 0) {
10724 if (t != ptr + end) {
10728 SPLIT_STR(substr_start - str_start, (ptr+end) - substr_start);
10729 str_mod_check(spat, sptr, slen);
10731 substr_start = ptr;
10732 if (!
NIL_P(limit) && lim <= ++i)
break;
10734 beg = ptr - str_start;
10736 else if (split_type == SPLIT_TYPE_CHARS) {
10740 mustnot_broken(str);
10741 enc = rb_enc_get(str);
10742 while (ptr < eptr &&
10743 (n = rb_enc_precise_mbclen(ptr, eptr, enc)) > 0) {
10744 SPLIT_STR(ptr - str_start, n);
10746 if (!
NIL_P(limit) && lim <= ++i)
break;
10748 beg = ptr - str_start;
10752 long len = RSTRING_LEN(str);
10759 (match ? (rb_match_unbusy(match),
rb_backref_set(match)) : (void)0)) {
10762 end = RMATCH_BEG(match, 0);
10763 if (start == end && RMATCH_BEG(match, 0) == RMATCH_END(match, 0)) {
10768 else if (last_null == 1) {
10769 SPLIT_STR(beg, rb_enc_fast_mbclen(ptr+beg, eptr, enc));
10776 start += rb_enc_fast_mbclen(ptr+start,eptr,enc);
10782 SPLIT_STR(beg, end-beg);
10783 beg = start = RMATCH_END(match, 0);
10787 for (idx = 1; idx < RMATCH_NREGS(match); idx++) {
10788 if (RMATCH_BEG(match, idx) == -1)
continue;
10789 SPLIT_STR(RMATCH_BEG(match, idx), RMATCH_END(match, idx) - RMATCH_BEG(match, idx));
10791 if (!
NIL_P(limit) && lim <= ++i)
break;
10793 if (match) rb_match_unbusy(match);
10795 if (RSTRING_LEN(str) > 0 && (!
NIL_P(limit) || RSTRING_LEN(str) > beg || lim < 0)) {
10796 SPLIT_STR(beg, RSTRING_LEN(str)-beg);
10799 return result ? result : str;
10809 return rb_str_split_m(1, &sep, str);
10812#define WANTARRAY(m, size) (!rb_block_given_p() ? rb_ary_new_capa(size) : 0)
10827#define ENUM_ELEM(ary, e) enumerator_element(ary, e)
10830chomp_newline(
const char *p,
const char *e,
rb_encoding *enc)
10832 const char *prev = rb_enc_prev_char(p, e, e, enc);
10835 prev = rb_enc_prev_char(p, e, e, enc);
10836 if (prev && rb_enc_ascget(prev, e, NULL, enc) ==
'\r')
10848 RSTRING_LEN(rs) != 1 ||
10849 RSTRING_PTR(rs)[0] !=
'\n')) {
10855#define rb_rs get_rs()
10862 const char *pend, *subptr, *subend, *rsptr, *hit, *adjusted;
10868 if (!
NIL_P(opts)) {
10869 static ID keywords[1];
10870 if (!keywords[0]) {
10874 chomp = (!UNDEF_P(chomp) &&
RTEST(chomp));
10878 if (!ENUM_ELEM(ary, str)) {
10886 if (!RSTRING_LEN(str))
goto end;
10888 const char *
const ptr = subptr = RSTRING_PTR(str);
10889 const long len = RSTRING_LEN(str);
10892 rslen = RSTRING_LEN(rs);
10895 enc = rb_enc_get(str);
10897 enc = rb_enc_check(str, rs);
10902 const char *eol = NULL;
10904 while (subend < pend) {
10905 long chomp_rslen = 0;
10907 if (rb_enc_ascget(subend, pend, &n, enc) !=
'\r')
10909 rslen = n + rb_enc_mbclen(subend + n, pend, enc);
10911 if (eol == subend)
break;
10915 chomp_rslen = -rslen;
10919 if (!subptr) subptr = subend;
10923 }
while (subend < pend);
10924 if (!subptr)
break;
10925 if (rslen == 0) chomp_rslen = 0;
10927 subend - subptr + (chomp ? chomp_rslen : rslen));
10928 if (ENUM_ELEM(ary, line)) {
10929 str_mod_check(str, ptr,
len);
10931 subptr = eol = NULL;
10936 rsptr = RSTRING_PTR(rs);
10937 if (RSTRING_LEN(rs) == rb_enc_mbminlen(enc) &&
10946 rsptr = RSTRING_PTR(rs);
10947 rslen = RSTRING_LEN(rs);
10950 while (subptr < pend) {
10951 pos =
rb_memsearch(rsptr, rslen, subptr, pend - subptr, enc);
10952 if (pos < 0)
break;
10953 hit = subptr + pos;
10955 if (hit != adjusted) {
10959 subend = hit += rslen;
10962 subend = chomp_newline(subptr, subend, enc);
10969 if (ENUM_ELEM(ary, line)) {
10970 str_mod_check(str, ptr,
len);
10971 str_mod_check(rs, rsptr, rslen);
10976 if (subptr < pend) {
10979 pend = chomp_newline(subptr, pend, enc);
10981 else if (pend - subptr >= rslen &&
10982 memcmp(pend - rslen, rsptr, rslen) == 0) {
10987 ENUM_ELEM(ary, line);
11008rb_str_each_line(
int argc,
VALUE *argv,
VALUE str)
11011 return rb_str_enumerate_lines(argc, argv, str, 0);
11066rb_str_lines(
int argc,
VALUE *argv,
VALUE str)
11068 VALUE ary = WANTARRAY(
"lines", 0);
11069 return rb_str_enumerate_lines(argc, argv, str, ary);
11075 return LONG2FIX(RSTRING_LEN(str));
11083 for (i=0; i<RSTRING_LEN(str); i++) {
11084 ENUM_ELEM(ary,
INT2FIX((
unsigned char)RSTRING_PTR(str)[i]));
11102rb_str_each_byte(
VALUE str)
11105 return rb_str_enumerate_bytes(str, 0);
11117rb_str_bytes(
VALUE str)
11119 VALUE ary = WANTARRAY(
"bytes", RSTRING_LEN(str));
11120 return rb_str_enumerate_bytes(str, ary);
11138 ptr = RSTRING_PTR(str);
11139 len = RSTRING_LEN(str);
11140 enc = rb_enc_get(str);
11143 for (i = 0; i <
len; i += n) {
11144 n = rb_enc_fast_mbclen(ptr + i, ptr +
len, enc);
11149 for (i = 0; i <
len; i += n) {
11150 n = rb_enc_mbclen(ptr + i, ptr +
len, enc);
11171rb_str_each_char(
VALUE str)
11174 return rb_str_enumerate_chars(str, 0);
11186rb_str_chars(
VALUE str)
11189 return rb_str_enumerate_chars(str, ary);
11193rb_str_enumerate_codepoints(
VALUE str,
VALUE ary)
11198 const char *ptr, *end;
11200 int enc_asciicompat;
11202 if (single_byte_optimizable(str))
11203 return rb_str_enumerate_bytes(str, ary);
11206 ptr = RSTRING_PTR(str);
11208 enc = STR_ENC_GET(str);
11209 enc_asciicompat = rb_enc_asciicompat(enc);
11211 while (ptr < end) {
11216 c = (enc_asciicompat &&
ISASCII(*ptr)) ?
11217 (
unsigned char)*ptr : rb_enc_codepoint_len(ptr, end, &n, enc);
11238rb_str_each_codepoint(
VALUE str)
11241 return rb_str_enumerate_codepoints(str, 0);
11253rb_str_codepoints(
VALUE str)
11256 return rb_str_enumerate_codepoints(str, ary);
11262 int encidx = rb_enc_to_index(enc);
11264 const OnigUChar source_ascii[] =
"\\X";
11265 const OnigUChar *source = source_ascii;
11266 size_t source_len =
sizeof(source_ascii) - 1;
11269#define CHARS_16BE(x) (OnigUChar)((x)>>8), (OnigUChar)(x)
11270#define CHARS_16LE(x) (OnigUChar)(x), (OnigUChar)((x)>>8)
11271#define CHARS_32BE(x) CHARS_16BE((x)>>16), CHARS_16BE(x)
11272#define CHARS_32LE(x) CHARS_16LE(x), CHARS_16LE((x)>>16)
11273#define CASE_UTF(e) \
11274 case ENCINDEX_UTF_##e: { \
11275 static const OnigUChar source_UTF_##e[] = {CHARS_##e('\\'), CHARS_##e('X')}; \
11276 source = source_UTF_##e; \
11277 source_len = sizeof(source_UTF_##e); \
11280 CASE_UTF(16BE); CASE_UTF(16LE); CASE_UTF(32BE); CASE_UTF(32LE);
11288 regex_t *reg_grapheme_cluster;
11290 int r = onig_new(®_grapheme_cluster, source, source + source_len,
11291 ONIG_OPTION_DEFAULT, enc, OnigDefaultSyntax, &einfo);
11293 UChar message[ONIG_MAX_ERROR_MESSAGE_LEN];
11294 onig_error_code_to_str(message, r, &einfo);
11295 rb_fatal(
"cannot compile grapheme cluster regexp: %s", (
char *)message);
11298 return reg_grapheme_cluster;
11304 int encidx = rb_enc_to_index(enc);
11305 static regex_t *reg_grapheme_cluster_utf8 = NULL;
11307 if (encidx == rb_utf8_encindex()) {
11308 if (!reg_grapheme_cluster_utf8) {
11309 reg_grapheme_cluster_utf8 = get_reg_grapheme_cluster(enc);
11312 return reg_grapheme_cluster_utf8;
11321 size_t grapheme_cluster_count = 0;
11323 const char *ptr, *end;
11325 if (!rb_enc_unicode_p(enc)) {
11329 bool cached_reg_grapheme_cluster =
true;
11330 regex_t *reg_grapheme_cluster = get_cached_reg_grapheme_cluster(enc);
11331 if (!reg_grapheme_cluster) {
11332 reg_grapheme_cluster = get_reg_grapheme_cluster(enc);
11333 cached_reg_grapheme_cluster =
false;
11336 ptr = RSTRING_PTR(str);
11339 while (ptr < end) {
11340 OnigPosition
len = onig_match(reg_grapheme_cluster,
11341 (
const OnigUChar *)ptr, (
const OnigUChar *)end,
11342 (
const OnigUChar *)ptr, NULL, 0);
11343 if (
len <= 0)
break;
11344 grapheme_cluster_count++;
11348 if (!cached_reg_grapheme_cluster) {
11349 onig_free(reg_grapheme_cluster);
11352 return SIZET2NUM(grapheme_cluster_count);
11356rb_str_enumerate_grapheme_clusters(
VALUE str,
VALUE ary)
11360 const char *ptr0, *ptr, *end;
11362 if (!rb_enc_unicode_p(enc)) {
11363 return rb_str_enumerate_chars(str, ary);
11368 bool cached_reg_grapheme_cluster =
true;
11369 regex_t *reg_grapheme_cluster = get_cached_reg_grapheme_cluster(enc);
11370 if (!reg_grapheme_cluster) {
11371 reg_grapheme_cluster = get_reg_grapheme_cluster(enc);
11372 cached_reg_grapheme_cluster =
false;
11375 ptr0 = ptr = RSTRING_PTR(str);
11378 while (ptr < end) {
11379 OnigPosition
len = onig_match(reg_grapheme_cluster,
11380 (
const OnigUChar *)ptr, (
const OnigUChar *)end,
11381 (
const OnigUChar *)ptr, NULL, 0);
11382 if (
len <= 0)
break;
11387 if (!cached_reg_grapheme_cluster) {
11388 onig_free(reg_grapheme_cluster);
11408rb_str_each_grapheme_cluster(
VALUE str)
11411 return rb_str_enumerate_grapheme_clusters(str, 0);
11423rb_str_grapheme_clusters(
VALUE str)
11426 return rb_str_enumerate_grapheme_clusters(str, ary);
11430chopped_length(
VALUE str)
11433 const char *p, *p2, *beg, *end;
11435 beg = RSTRING_PTR(str);
11436 end = beg + RSTRING_LEN(str);
11437 if (beg >= end)
return 0;
11438 p = rb_enc_prev_char(beg, end, end, enc);
11440 if (p > beg && rb_enc_ascget(p, end, 0, enc) ==
'\n') {
11441 p2 = rb_enc_prev_char(beg, p, end, enc);
11442 if (p2 && rb_enc_ascget(p2, end, 0, enc) ==
'\r') p = p2;
11460rb_str_chop_bang(
VALUE str)
11462 str_modify_keep_cr(str);
11463 if (RSTRING_LEN(str) > 0) {
11465 len = chopped_length(str);
11466 STR_SET_LEN(str,
len);
11467 TERM_FILL(&RSTRING_PTR(str)[
len], TERM_LEN(str));
11486rb_str_chop(
VALUE str)
11492smart_chomp(
VALUE str,
const char *e,
const char *p)
11495 if (rb_enc_mbminlen(enc) > 1) {
11497 if (e - p < rb_enc_mbminlen(enc))
return e - p;
11502 pp = e - rb_enc_mbminlen(enc);
11505 if (rb_enc_ascget(pp, e, 0, enc) ==
'\r') {
11513 if (--e > p && *(e-1) ==
'\r') {
11530 const char *pp, *e, *rsptr;
11532 const char *
const p = RSTRING_PTR(str);
11533 long len = RSTRING_LEN(str);
11535 if (
len == 0)
return 0;
11538 return smart_chomp(str, e, p);
11541 enc = rb_enc_get(str);
11544 if (rb_enc_mbminlen(enc) > 1) {
11545 while (e - p >= rb_enc_mbminlen(enc)) {
11549 pp -= rb_enc_mbminlen(enc);
11552 if (rb_enc_ascget(pp, e, 0, enc) ==
'\r') {
11559 while (e > p && *(e-1) ==
'\n') {
11561 if (e > p && *(e-1) ==
'\r')
11567 if (rslen >
len)
return len;
11569 enc = rb_enc_get(rs);
11570 newline = rsptr[rslen-1];
11571 if (rslen == rb_enc_mbminlen(enc)) {
11573 if (newline ==
'\n')
11574 return smart_chomp(str, e, p);
11578 return smart_chomp(str, e, p);
11582 enc = rb_enc_check(str, rs);
11583 if (is_broken_string(rs)) {
11587 if (p[
len-1] == newline &&
11589 memcmp(rsptr, pp, rslen) == 0)) {
11590 if (at_char_boundary(p, pp, e, enc))
11591 return len - rslen;
11603chomp_rs(
int argc,
const VALUE *argv)
11607 VALUE rs = argv[0];
11619 str_modify_keep_cr(str);
11620 STR_SET_LEN(str,
len);
11621 TERM_FILL(&RSTRING_PTR(str)[
len], TERM_LEN(str));
11631 long olen = RSTRING_LEN(str);
11632 long len = chompped_length(str, rs);
11633 if (
len >= olen)
return Qnil;
11634 return str_shrink(str,
len);
11650rb_str_chomp_bang(
int argc,
VALUE *argv,
VALUE str)
11653 str_modifiable(str);
11654 if (RSTRING_LEN(str) == 0 && argc < 2)
return Qnil;
11655 rs = chomp_rs(argc, argv);
11657 return rb_str_chomp_string(str, rs);
11670rb_str_chomp(
int argc,
VALUE *argv,
VALUE str)
11672 VALUE rs = chomp_rs(argc, argv);
11678tr_setup_table_multi(
char table[TR_TABLE_SIZE],
VALUE *tablep,
VALUE *ctablep,
11679 VALUE str,
int num_selectors,
VALUE *selectors)
11683 for (i=0; i<num_selectors; i++) {
11684 VALUE selector = selectors[i];
11688 enc = rb_enc_check(str, selector);
11689 tr_setup_table(selector, table, i==0, tablep, ctablep, enc);
11696 const char *
const start = s;
11698 if (!s || s >= e)
return 0;
11701 if (single_byte_optimizable(str)) {
11702 while (s < e && (*s ==
'\0' || ascii_isspace(*s))) s++;
11707 unsigned int cc = rb_enc_codepoint_len(s, e, &n, enc);
11717lstrip_offset_table(
VALUE str,
const char *s,
const char *e,
rb_encoding *enc,
11718 char table[TR_TABLE_SIZE],
VALUE del,
VALUE nodel)
11720 const char *
const start = s;
11722 if (!s || s >= e)
return 0;
11727 unsigned int cc = rb_enc_codepoint_len(s, e, &n, enc);
11729 if (!tr_find(cc, table, del, nodel))
break;
11748rb_str_lstrip_bang(
int argc,
VALUE *argv,
VALUE str)
11752 long olen, loffset;
11754 str_modify_keep_cr(str);
11755 enc = STR_ENC_GET(str);
11758 char table[TR_TABLE_SIZE];
11759 VALUE del = 0, nodel = 0;
11761 tr_setup_table_multi(table, &del, &nodel, str, argc, argv);
11764 str_modify_keep_cr(str);
11765 enc = STR_ENC_GET(str);
11768 loffset = lstrip_offset_table(str, start, start+olen, enc, table, del, nodel);
11771 loffset = lstrip_offset(str, start, start+olen, enc);
11775 long len = olen-loffset;
11776 memmove(start, start + loffset,
len);
11777 STR_SET_LEN(str,
len);
11778 TERM_FILL(start+
len, rb_enc_mbminlen(enc));
11813rb_str_lstrip(
int argc,
VALUE *argv,
VALUE str)
11820 char table[TR_TABLE_SIZE];
11821 VALUE del = 0, nodel = 0;
11823 tr_setup_table_multi(table, &del, &nodel, str, argc, argv);
11828 loffset = lstrip_offset_table(str, start, start+
len, STR_ENC_GET(str), table, del, nodel);
11831 loffset = lstrip_offset(str, start, start+
len, STR_ENC_GET(str));
11833 if (loffset <= 0)
return str_duplicate(
rb_cString, str);
11842 rb_str_check_dummy_enc(enc);
11846 if (!s || s >= e)
return 0;
11850 if (single_byte_optimizable(str)) {
11852 while (s < t && ((c = *(t-1)) ==
'\0' || ascii_isspace(c))) t--;
11857 while ((tp = rb_enc_prev_char(s, t, e, enc)) != NULL) {
11867rstrip_offset_table(
VALUE str,
const char *s,
const char *e,
rb_encoding *enc,
11868 char table[TR_TABLE_SIZE],
VALUE del,
VALUE nodel)
11870 const char *t, *tp;
11872 rb_str_check_dummy_enc(enc);
11876 if (!s || s >= e)
return 0;
11880 while ((tp = rb_enc_prev_char(s, t, e, enc)) != NULL) {
11882 if (!tr_find(c, table, del, nodel))
break;
11902rb_str_rstrip_bang(
int argc,
VALUE *argv,
VALUE str)
11906 long olen, roffset;
11908 str_modify_keep_cr(str);
11909 enc = STR_ENC_GET(str);
11912 char table[TR_TABLE_SIZE];
11913 VALUE del = 0, nodel = 0;
11915 tr_setup_table_multi(table, &del, &nodel, str, argc, argv);
11918 str_modify_keep_cr(str);
11919 enc = STR_ENC_GET(str);
11922 roffset = rstrip_offset_table(str, start, start+olen, enc, table, del, nodel);
11925 roffset = rstrip_offset(str, start, start+olen, enc);
11928 long len = olen - roffset;
11930 STR_SET_LEN(str,
len);
11931 TERM_FILL(start+
len, rb_enc_mbminlen(enc));
11965rb_str_rstrip(
int argc,
VALUE *argv,
VALUE str)
11969 long olen, roffset;
11971 enc = STR_ENC_GET(str);
11974 char table[TR_TABLE_SIZE];
11975 VALUE del = 0, nodel = 0;
11977 tr_setup_table_multi(table, &del, &nodel, str, argc, argv);
11980 enc = STR_ENC_GET(str);
11983 roffset = rstrip_offset_table(str, start, start+olen, enc, table, del, nodel);
11986 roffset = rstrip_offset(str, start, start+olen, enc);
11988 if (roffset <= 0)
return str_duplicate(
rb_cString, str);
12006rb_str_strip_bang(
int argc,
VALUE *argv,
VALUE str)
12009 long olen, loffset, roffset;
12012 str_modify_keep_cr(str);
12013 enc = STR_ENC_GET(str);
12017 char table[TR_TABLE_SIZE];
12018 VALUE del = 0, nodel = 0;
12020 tr_setup_table_multi(table, &del, &nodel, str, argc, argv);
12023 str_modify_keep_cr(str);
12024 enc = STR_ENC_GET(str);
12027 loffset = lstrip_offset_table(str, start, start+olen, enc, table, del, nodel);
12028 roffset = rstrip_offset_table(str, start+loffset, start+olen, enc, table, del, nodel);
12031 loffset = lstrip_offset(str, start, start+olen, enc);
12032 roffset = rstrip_offset(str, start+loffset, start+olen, enc);
12035 if (loffset > 0 || roffset > 0) {
12036 long len = olen-roffset;
12039 memmove(start, start + loffset,
len);
12041 STR_SET_LEN(str,
len);
12042 TERM_FILL(start+
len, rb_enc_mbminlen(enc));
12077rb_str_strip(
int argc,
VALUE *argv,
VALUE str)
12080 long olen, loffset, roffset;
12086 char table[TR_TABLE_SIZE];
12087 VALUE del = 0, nodel = 0;
12089 tr_setup_table_multi(table, &del, &nodel, str, argc, argv);
12092 enc = STR_ENC_GET(str);
12095 loffset = lstrip_offset_table(str, start, start+olen, enc, table, del, nodel);
12096 roffset = rstrip_offset_table(str, start+loffset, start+olen, enc, table, del, nodel);
12099 loffset = lstrip_offset(str, start, start+olen, enc);
12100 roffset = rstrip_offset(str, start+loffset, start+olen, enc);
12103 if (loffset <= 0 && roffset <= 0)
return str_duplicate(
rb_cString, str);
12108scan_once(
VALUE str,
VALUE pat,
long *start,
int set_backref_str)
12111 long end, pos = rb_pat_search(pat, str, *start, set_backref_str);
12115 end = pos + RSTRING_LEN(pat);
12119 pos = RMATCH_BEG(match, 0);
12120 end = RMATCH_END(match, 0);
12128 if (RSTRING_LEN(str) > end)
12129 *start = end + rb_enc_fast_mbclen(RSTRING_PTR(str) + end,
12138 if (
NIL_P(match) || RMATCH_NREGS(match) == 1) {
12143 int num_regs = RMATCH_NREGS(match);
12145 for (
int i = 1; i < num_regs; i++) {
12147 if (RMATCH_BEG(match, i) >= 0) {
12148 s =
rb_str_subseq(str, RMATCH_BEG(match, i), RMATCH_END(match, i) - RMATCH_BEG(match, i));
12176 long last = -1, prev = 0;
12177 const char *p = RSTRING_PTR(str);
12178 long len = RSTRING_LEN(str);
12180 pat = get_pat_quoted(pat, 1);
12181 mustnot_broken(str);
12185 while (!
NIL_P(result = scan_once(str, pat, &start, 0))) {
12190 if (last >= 0) rb_pat_search(pat, str, last, 1);
12195 while (!
NIL_P(result = scan_once(str, pat, &start, 1))) {
12199 str_mod_check(str, p,
len);
12201 if (last >= 0) rb_pat_search(pat, str, last, 1);
12253rb_str_hex(
VALUE str)
12255 return rb_str_to_inum(str, 16, FALSE);
12339rb_str_oct(
VALUE str)
12341 return rb_str_to_inum(str, -8, FALSE);
12344#ifndef HAVE_CRYPT_R
12349 rb_nativethread_lock_t lock;
12350} crypt_mutex = {PTHREAD_MUTEX_INITIALIZER};
12419# define CRYPT_END() ALLOCV_END(databuf)
12422 extern char *crypt(
const char *,
const char *);
12423# define CRYPT_END() rb_nativethread_lock_unlock(&crypt_mutex.lock)
12426 const char *s, *saltp, *res;
12428 char salt_8bit_clean[3];
12432 mustnot_wchar(str);
12433 mustnot_wchar(salt);
12435 saltp = RSTRING_PTR(salt);
12436 if (RSTRING_LEN(salt) < 2 || !saltp[0] || !saltp[1]) {
12437 rb_raise(rb_eArgError,
"salt too short (need >=2 bytes)");
12441 if (!
ISASCII((
unsigned char)saltp[0]) || !
ISASCII((
unsigned char)saltp[1])) {
12442 salt_8bit_clean[0] = saltp[0] & 0x7f;
12443 salt_8bit_clean[1] = saltp[1] & 0x7f;
12444 salt_8bit_clean[2] =
'\0';
12445 saltp = salt_8bit_clean;
12450# ifdef HAVE_STRUCT_CRYPT_DATA_INITIALIZED
12451 data->initialized = 0;
12453 res = crypt_r(s, saltp, data);
12456 res = crypt(s, saltp);
12471 size_t res_size = strlen(res);
12472 tmp_buf =
ALLOCA_N(
char, res_size);
12473 memcpy(tmp_buf, res, res_size);
12509 char *ptr, *p, *pend;
12512 unsigned long sum0 = 0;
12517 ptr = p = RSTRING_PTR(str);
12518 len = RSTRING_LEN(str);
12524 str_mod_check(str, ptr,
len);
12527 sum0 += (
unsigned char)*p;
12538 if (bits < (
int)
sizeof(
long)*CHAR_BIT) {
12539 sum0 &= (((
unsigned long)1)<<bits)-1;
12559rb_str_justify(
int argc,
VALUE *argv,
VALUE str,
char jflag)
12563 long width,
len, flen = 1, fclen = 1;
12566 const char *f =
" ";
12567 long n, size, llen, rlen, llen2 = 0, rlen2 = 0;
12569 int singlebyte = 1, cr;
12573 enc = STR_ENC_GET(str);
12577 enc = rb_enc_check(str, pad);
12578 f = RSTRING_PTR(pad);
12579 flen = RSTRING_LEN(pad);
12580 fclen = str_strlen(pad, enc);
12581 singlebyte = single_byte_optimizable(pad);
12582 if (flen == 0 || fclen == 0) {
12583 rb_raise(rb_eArgError,
"zero width padding");
12586 termlen = rb_enc_mbminlen(enc);
12587 len = str_strlen(str, enc);
12588 if (width < 0 || len >= width)
return str_duplicate(
rb_cString, str);
12590 llen = (jflag ==
'l') ? 0 : ((jflag ==
'r') ? n : n/2);
12594 llen2 = str_offset(f, f + flen, llen % fclen, enc, singlebyte);
12595 rlen2 = str_offset(f, f + flen, rlen % fclen, enc, singlebyte);
12597 size = RSTRING_LEN(str);
12598 if ((
len = llen / fclen + rlen / fclen) >= LONG_MAX / flen ||
12599 (
len *= flen) >= LONG_MAX - llen2 - rlen2 ||
12600 (
len += llen2 + rlen2) >= LONG_MAX - size) {
12601 rb_raise(rb_eArgError,
"argument too big");
12605 p = RSTRING_PTR(res);
12607 memset(p, *f, llen);
12611 while (llen >= fclen) {
12617 memcpy(p, f, llen2);
12621 memcpy(p, RSTRING_PTR(str), size);
12624 memset(p, *f, rlen);
12628 while (rlen >= fclen) {
12634 memcpy(p, f, rlen2);
12638 TERM_FILL(p, termlen);
12639 STR_SET_LEN(res, p-RSTRING_PTR(res));
12660rb_str_ljust(
int argc,
VALUE *argv,
VALUE str)
12662 return rb_str_justify(argc, argv, str,
'l');
12674rb_str_rjust(
int argc,
VALUE *argv,
VALUE str)
12676 return rb_str_justify(argc, argv, str,
'r');
12689rb_str_center(
int argc,
VALUE *argv,
VALUE str)
12691 return rb_str_justify(argc, argv, str,
'c');
12707 sep = get_pat_quoted(sep, 0);
12714 pos = RMATCH_BEG(match, 0);
12718 pos = rb_str_index(str, sep, 0);
12719 if (pos < 0)
goto failed;
12722 long rpos = pos + RSTRING_LEN(sep);
12723 if (rpos > RSTRING_LEN(str))
goto failed;
12729 return rb_ary_new3(3, str_duplicate(
rb_cString, str), str_new_empty_String(str), str_new_empty_String(str));
12745 sep = get_pat_quoted(sep, 0);
12747 pos = RSTRING_LEN(str);
12753 pos = RMATCH_BEG(match, 0);
12759 pos = rb_str_rindex(str, sep, pos);
12765 long rpos = pos + RSTRING_LEN(sep);
12766 if (rpos > RSTRING_LEN(str))
goto failed;
12771 return rb_ary_new3(3, str_new_empty_String(str), str_new_empty_String(str), str_duplicate(
rb_cString, str));
12783rb_str_start_with(
int argc,
VALUE *argv,
VALUE str)
12787 for (i=0; i<argc; i++) {
12788 VALUE tmp = argv[i];
12790 if (rb_reg_start_with_p(tmp, str))
12794 const char *p, *s, *e;
12799 enc = rb_enc_check(str, tmp);
12800 if ((tlen = RSTRING_LEN(tmp)) == 0)
return Qtrue;
12801 if ((slen = RSTRING_LEN(str)) < tlen)
continue;
12802 p = RSTRING_PTR(str);
12805 if (!at_char_right_boundary(p, s, e, enc))
12807 if (memcmp(p, RSTRING_PTR(tmp), tlen) == 0)
12823rb_str_end_with(
int argc,
VALUE *argv,
VALUE str)
12827 for (i=0; i<argc; i++) {
12828 VALUE tmp = argv[i];
12829 const char *p, *s, *e;
12834 enc = rb_enc_check(str, tmp);
12835 if ((tlen = RSTRING_LEN(tmp)) == 0)
return Qtrue;
12836 if ((slen = RSTRING_LEN(str)) < tlen)
continue;
12837 p = RSTRING_PTR(str);
12840 if (!at_char_boundary(p, s, e, enc))
12842 if (memcmp(s, RSTRING_PTR(tmp), tlen) == 0)
12858deleted_prefix_length(
VALUE str,
VALUE prefix)
12860 const char *strptr, *prefixptr;
12861 long olen, prefixlen;
12866 if (!is_broken_string(prefix) ||
12867 !rb_enc_asciicompat(enc) ||
12868 !rb_enc_asciicompat(rb_enc_get(prefix))) {
12869 enc = rb_enc_check(str, prefix);
12873 prefixlen = RSTRING_LEN(prefix);
12874 if (prefixlen <= 0)
return 0;
12875 olen = RSTRING_LEN(str);
12876 if (olen < prefixlen)
return 0;
12877 strptr = RSTRING_PTR(str);
12878 prefixptr = RSTRING_PTR(prefix);
12879 if (memcmp(strptr, prefixptr, prefixlen) != 0)
return 0;
12880 if (is_broken_string(prefix)) {
12881 if (!is_broken_string(str)) {
12885 const char *strend = strptr + olen;
12886 const char *after_prefix = strptr + prefixlen;
12887 if (!at_char_right_boundary(strptr, after_prefix, strend, enc)) {
12908rb_str_delete_prefix_bang(
VALUE str,
VALUE prefix)
12911 str_modify_keep_cr(str);
12913 prefixlen = deleted_prefix_length(str, prefix);
12914 if (prefixlen <= 0)
return Qnil;
12928rb_str_delete_prefix(
VALUE str,
VALUE prefix)
12932 prefixlen = deleted_prefix_length(str, prefix);
12933 if (prefixlen <= 0)
return str_duplicate(
rb_cString, str);
12935 return rb_str_subseq(str, prefixlen, RSTRING_LEN(str) - prefixlen);
12948deleted_suffix_length(
VALUE str,
VALUE suffix)
12950 const char *strptr, *suffixptr;
12951 long olen, suffixlen;
12955 if (is_broken_string(suffix))
return 0;
12956 enc = rb_enc_check(str, suffix);
12959 suffixlen = RSTRING_LEN(suffix);
12960 if (suffixlen <= 0)
return 0;
12961 olen = RSTRING_LEN(str);
12962 if (olen < suffixlen)
return 0;
12963 strptr = RSTRING_PTR(str);
12964 suffixptr = RSTRING_PTR(suffix);
12965 const char *strend = strptr + olen;
12966 const char *before_suffix = strend - suffixlen;
12967 if (memcmp(before_suffix, suffixptr, suffixlen) != 0)
return 0;
12968 if (!at_char_boundary(strptr, before_suffix, strend, enc))
return 0;
12984rb_str_delete_suffix_bang(
VALUE str,
VALUE suffix)
12987 str_modifiable(str);
12989 suffixlen = deleted_suffix_length(str, suffix);
12990 if (suffixlen <= 0)
return Qnil;
12992 return str_shrink(str, RSTRING_LEN(str) - suffixlen);
13004rb_str_delete_suffix(
VALUE str,
VALUE suffix)
13008 suffixlen = deleted_suffix_length(str, suffix);
13009 if (suffixlen <= 0)
return str_duplicate(
rb_cString, str);
13011 return rb_str_subseq(str, 0, RSTRING_LEN(str) - suffixlen);
13018 rb_raise(
rb_eTypeError,
"value of %"PRIsVALUE
" must be String", rb_id2str(
id));
13024nil_setter_warning(
ID id)
13026 rb_warn_deprecated(
"non-nil '%"PRIsVALUE
"'", NULL, rb_id2str(
id));
13033 if (!
NIL_P(*var)) {
13034 nil_setter_warning(
id);
13041 val = rb_fs_check(val);
13044 "value of %"PRIsVALUE
" must be String or Regexp",
13048 nil_setter_warning(
id);
13065 str_modifiable(str);
13068 int idx = rb_enc_to_index(encoding);
13075 rb_enc_associate_index(str, idx);
13099 if (STR_EMBED_P(str)) {
13100 str2 = str_alloc_embed(
rb_cString, RSTRING_LEN(str) + TERM_LEN(str));
13105 str_replace_shared_without_enc(str2, str);
13107 if (rb_enc_asciicompat(STR_ENC_GET(str))) {
13130rb_str_valid_encoding_p(
VALUE str)
13132 int cr = rb_enc_str_coderange(str);
13139rb_str_is_ascii_only_p(
VALUE str)
13141 int cr = rb_enc_str_coderange(str);
13149 static const char ellipsis[] =
"...";
13150 const long ellipsislen =
sizeof(ellipsis) - 1;
13152 const long blen = RSTRING_LEN(str);
13153 const char *
const p = RSTRING_PTR(str), *e = p + blen;
13154 VALUE estr, ret = 0;
13157 if (
len * rb_enc_mbminlen(enc) >= blen ||
13161 else if (
len <= ellipsislen ||
13163 if (rb_enc_asciicompat(enc)) {
13165 rb_enc_associate(ret, enc);
13172 else if (ret =
rb_str_subseq(str, 0, e - p), rb_enc_asciicompat(enc)) {
13177 rb_enc_from_encoding(enc), 0,
Qnil);
13188 cr = rb_enc_str_coderange(str);
13190 rb_raise(rb_eArgError,
"replacement must be valid byte sequence '%+"PRIsVALUE
"'", str);
13196 rb_enc_inspect_name(enc), rb_enc_inspect_name(e));
13215 if (enc == STR_ENC_GET(str)) {
13220 return enc_str_scrub(enc, str, repl, cr);
13228 const char *rep, *p, *e, *p1, *sp;
13234 rb_raise(rb_eArgError,
"both of block and replacement given");
13241 if (!
NIL_P(repl)) {
13242 repl = str_compat_and_valid(repl, enc);
13245 if (rb_enc_dummy_p(enc)) {
13248 encidx = rb_enc_to_index(enc);
13250#define DEFAULT_REPLACE_CHAR(str) do { \
13251 RBIMPL_ATTR_NONSTRING() static const char replace[sizeof(str)-1] = str; \
13252 rep = replace; replen = (int)sizeof(replace); \
13255 slen = RSTRING_LEN(str);
13256 p = RSTRING_PTR(str);
13261 if (rb_enc_asciicompat(enc)) {
13267 else if (!
NIL_P(repl)) {
13268 rep = RSTRING_PTR(repl);
13269 replen = RSTRING_LEN(repl);
13272 else if (encidx == rb_utf8_encindex()) {
13273 DEFAULT_REPLACE_CHAR(
"\xEF\xBF\xBD");
13277 DEFAULT_REPLACE_CHAR(
"?");
13282 p = search_nonascii(p, e);
13287 int ret = rb_enc_precise_mbclen(p, e, enc);
13295 p = search_nonascii(p, e);
13312 if (e - p < clen) clen = e - p;
13319 for (; clen > 1; clen--) {
13320 ret = rb_enc_precise_mbclen(q, q + clen, enc);
13331 repl =
rb_yield(rb_enc_str_new(p, clen, enc));
13332 str_mod_check(str, sp, slen);
13333 repl = str_compat_and_valid(repl, enc);
13340 p = search_nonascii(p, e);
13366 repl =
rb_yield(rb_enc_str_new(p, e-p, enc));
13367 str_mod_check(str, sp, slen);
13368 repl = str_compat_and_valid(repl, enc);
13377 long mbminlen = rb_enc_mbminlen(enc);
13381 else if (!
NIL_P(repl)) {
13382 rep = RSTRING_PTR(repl);
13383 replen = RSTRING_LEN(repl);
13385 else if (encidx == ENCINDEX_UTF_16BE) {
13386 DEFAULT_REPLACE_CHAR(
"\xFF\xFD");
13388 else if (encidx == ENCINDEX_UTF_16LE) {
13389 DEFAULT_REPLACE_CHAR(
"\xFD\xFF");
13391 else if (encidx == ENCINDEX_UTF_32BE) {
13392 DEFAULT_REPLACE_CHAR(
"\x00\x00\xFF\xFD");
13394 else if (encidx == ENCINDEX_UTF_32LE) {
13395 DEFAULT_REPLACE_CHAR(
"\xFD\xFF\x00\x00");
13398 DEFAULT_REPLACE_CHAR(
"?");
13402 int ret = rb_enc_precise_mbclen(p, e, enc);
13415 if (e - p < clen) clen = e - p;
13416 if (clen <= mbminlen * 2) {
13421 for (; clen > mbminlen; clen-=mbminlen) {
13422 ret = rb_enc_precise_mbclen(q, q + clen, enc);
13432 repl =
rb_yield(rb_enc_str_new(p, clen, enc));
13433 str_mod_check(str, sp, slen);
13434 repl = str_compat_and_valid(repl, enc);
13459 repl =
rb_yield(rb_enc_str_new(p, e-p, enc));
13460 str_mod_check(str, sp, slen);
13461 repl = str_compat_and_valid(repl, enc);
13501str_scrub_bang(
int argc,
VALUE *argv,
VALUE str)
13509static ID id_normalize;
13510static ID id_normalized_p;
13511static VALUE mUnicodeNormalize;
13514unicode_normalize_common(
int argc,
VALUE *argv,
VALUE str,
ID id)
13516 static int UnicodeNormalizeRequired = 0;
13519 if (!UnicodeNormalizeRequired) {
13520 rb_require(
"unicode_normalize/normalize.rb");
13521 UnicodeNormalizeRequired = 1;
13525 return rb_funcallv(mUnicodeNormalize,
id, argc+1, argv2);
13536rb_str_unicode_normalize(
int argc,
VALUE *argv,
VALUE str)
13538 return unicode_normalize_common(argc, argv, str, id_normalize);
13552rb_str_unicode_normalize_bang(
int argc,
VALUE *argv,
VALUE str)
13554 return rb_str_replace(str, unicode_normalize_common(argc, argv, str, id_normalize));
13581rb_str_unicode_normalized_p(
int argc,
VALUE *argv,
VALUE str)
13583 return unicode_normalize_common(argc, argv, str, id_normalized_p);
13715#define sym_equal rb_obj_equal
13718sym_printable(
const char *s,
const char *send,
rb_encoding *enc)
13722 int c = rb_enc_precise_mbclen(s, send, enc);
13726 c = rb_enc_mbc_to_codepoint(s, send, enc);
13734rb_str_symname_p(
VALUE sym)
13739 rb_encoding *resenc = rb_default_internal_encoding();
13741 if (resenc == NULL) resenc = rb_default_external_encoding();
13742 enc = STR_ENC_GET(sym);
13743 ptr = RSTRING_PTR(sym);
13744 len = RSTRING_LEN(sym);
13745 if ((resenc != enc && !rb_str_is_ascii_only_p(sym)) ||
len != (
long)strlen(ptr) ||
13753rb_str_quote_unprintable(
VALUE str)
13761 resenc = rb_default_internal_encoding();
13762 if (resenc == NULL) resenc = rb_default_external_encoding();
13763 enc = STR_ENC_GET(str);
13764 ptr = RSTRING_PTR(str);
13765 len = RSTRING_LEN(str);
13766 if ((resenc != enc && !rb_str_is_ascii_only_p(str)) ||
13767 !sym_printable(ptr, ptr +
len, enc)) {
13768 return rb_str_escape(str);
13774rb_id_quote_unprintable(
ID id)
13776 VALUE str = rb_id2str(
id);
13777 if (!rb_str_symname_p(str)) {
13778 return rb_str_escape(str);
13796sym_inspect(
VALUE sym)
13803 if (!rb_str_symname_p(str)) {
13805 len = RSTRING_LEN(str);
13806 rb_str_resize(str,
len + 1);
13807 dest = RSTRING_PTR(str);
13808 memmove(dest + 1, dest,
len);
13812 VALUE orig_str = str;
13814 len = RSTRING_LEN(orig_str);
13815 str = rb_enc_str_new(0,
len + 1, enc);
13818 ptr = RSTRING_PTR(orig_str);
13819 dest = RSTRING_PTR(str);
13820 memcpy(dest + 1, ptr,
len);
13838rb_sym_proc_call(
ID mid,
int argc,
const VALUE *argv,
int kw_splat,
VALUE passed_proc)
13843 rb_raise(rb_eArgError,
"no receiver given");
13946 return rb_str_match(
rb_sym2str(sym), other);
13961sym_match_m(
int argc,
VALUE *argv,
VALUE sym)
13963 return rb_str_match_m(argc, argv,
rb_sym2str(sym));
13976sym_match_m_p(
int argc,
VALUE *argv,
VALUE sym)
13978 return rb_str_match_m_p(argc, argv, sym);
13996 return rb_str_aref_m(argc, argv,
rb_sym2str(sym));
14007sym_length(
VALUE sym)
14041sym_downcase(
int argc,
VALUE *argv,
VALUE sym)
14057sym_capitalize(
int argc,
VALUE *argv,
VALUE sym)
14073sym_swapcase(
int argc,
VALUE *argv,
VALUE sym)
14087sym_start_with(
int argc,
VALUE *argv,
VALUE sym)
14089 return rb_str_start_with(argc, argv,
rb_sym2str(sym));
14102sym_end_with(
int argc,
VALUE *argv,
VALUE sym)
14104 return rb_str_end_with(argc, argv,
rb_sym2str(sym));
14116sym_encoding(
VALUE sym)
14122string_for_symbol(
VALUE name)
14127 rb_raise(
rb_eTypeError,
"%+"PRIsVALUE
" is not a symbol nor a string",
14141 name = string_for_symbol(name);
14142 return rb_intern_str(name);
14151 name = string_for_symbol(name);
14175 return rb_fstring(str);
14181 struct RString fake_str = {RBASIC_INIT};
14182 int encidx = ENCINDEX_US_ASCII;
14185 encidx = ENCINDEX_ASCII_8BIT;
14188 VALUE str = setup_fake_str(&fake_str,
ptr,
len, encidx);
14190 return register_fstring(str,
true,
false);
14202 if (enc != NULL && UNLIKELY(rb_enc_autoload_p(enc))) {
14203 rb_enc_autoload(enc);
14206 struct RString fake_str = {RBASIC_INIT};
14207 return register_fstring(rb_setup_fake_str(&fake_str,
ptr,
len, enc),
true,
false);
14213 if (enc != NULL && UNLIKELY(rb_enc_autoload_p(enc))) {
14214 rb_enc_autoload(enc);
14217 struct RString fake_str = {RBASIC_INIT};
14218 VALUE str = register_fstring(rb_setup_fake_str(&fake_str,
ptr,
len, enc),
true,
true);
14229#if USE_YJIT || USE_ZJIT
14231rb_jit_str_concat_codepoint(
VALUE str,
VALUE codepoint)
14236 if (RB_LIKELY(code >= 0 && code < 0xff)) {
14237 rb_str_buf_cat_byte(str, (
char) code);
14247fstring_set_class_i(
VALUE *str,
void *data)
14251 return ST_CONTINUE;
14259 rb_concurrent_set_foreach_with_replace(fstring_table_obj, fstring_set_class_i, NULL);
14427 mUnicodeNormalize = rb_define_module(
"UnicodeNormalize");
14438 rb_gc_register_address(&
rb_fs);
14476#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 ALLOCV_END
Old name of RB_ALLOCV_END.
#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.