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 rb_len_t 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
214#if SHARABLE_MIDDLE_SUBSTRING
218 rb_len_t 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);
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);
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);
294static inline void str_modifiable(
VALUE str);
299str_make_independent(
VALUE 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;
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_RB_LEN_T == 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)
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#ifdef PRECOMPUTED_FAKESTR_HASH
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);
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));
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);
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);
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);
1220 RUBY_DTRACE_CREATE_HOOK(STRING,
len);
1227 rb_enc_associate_index(str, encindex);
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)) {
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);
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 &&
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)
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);
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)) {
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);
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 rb_len_t *len_out,
size_t *byte_size_out)
2090 if (!STR_EMBED_P(str))
return false;
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 (!NIL_OR_UNDEF_P(venc)) {
2159 enc = rb_to_encoding(venc);
2161 if (!NIL_OR_UNDEF_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);
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 if (!enc || rb_enc_get(orig) == enc) {
2198 rb_enc_cr_str_exact_copy(str, orig);
2202 FL_SET(str, STR_NOEMBED);
2209 str_modifiable(str);
2210 rb_enc_raw_set(str, enc);
2222rb_str_s_new(
int argc,
VALUE *argv,
VALUE klass)
2228 static ID keyword_ids[2];
2238 keyword_ids[0] = rb_id_encoding();
2239 CONST_ID(keyword_ids[1],
"capacity");
2241 encoding = kwargs[0];
2242 capacity = kwargs[1];
2251 if (UNDEF_P(encoding)) {
2253 encoding = rb_obj_encoding(orig);
2257 if (!UNDEF_P(encoding)) {
2258 enc = rb_to_encoding(encoding);
2262 if (UNDEF_P(capacity)) {
2264 VALUE empty_str = str_new(klass,
"", 0);
2266 rb_enc_associate(empty_str, enc);
2270 VALUE copy = str_duplicate(klass, orig);
2271 rb_enc_associate(copy, enc);
2284 if (orig_capa >
capa) {
2289 VALUE str = str_enc_new(klass, NULL,
capa, enc);
2290 STR_SET_LEN(str, 0);
2301#define is_utf8_lead_byte(c) (((c)&0xC0) != 0x80)
2316static inline uintptr_t
2317count_utf8_lead_bytes_with_word(
const uintptr_t *s)
2322 d = (d>>6) | (~d>>7);
2323 d &= NONASCII_MASK >> 7;
2326#if defined(HAVE_BUILTIN___BUILTIN_POPCOUNT) && defined(__POPCNT__)
2328 return rb_popcount_intptr(d);
2332# if SIZEOF_VOIDP == 8
2341enc_strlen(
const char *p,
const char *e,
rb_encoding *enc,
int cr)
2348 return diff / rb_enc_mbminlen(enc) + !!(diff % rb_enc_mbminlen(enc));
2353 if ((
int)
sizeof(uintptr_t) * 2 < e - p) {
2354 const uintptr_t *s, *t;
2355 const uintptr_t lowbits =
sizeof(uintptr_t) - 1;
2356 s = (
const uintptr_t*)(~lowbits & ((uintptr_t)p + lowbits));
2357 t = (
const uintptr_t*)(~lowbits & (uintptr_t)e);
2358 while (p < (
const char *)s) {
2359 if (is_utf8_lead_byte(*p))
len++;
2363 len += count_utf8_lead_bytes_with_word(s);
2366 p = (
const char *)s;
2369 if (is_utf8_lead_byte(*p))
len++;
2375 else if (rb_enc_asciicompat(enc)) {
2379 q = search_nonascii(p, e);
2384 p += rb_enc_fast_mbclen(p, e, enc);
2390 q = search_nonascii(p, e);
2395 p += rb_enc_mbclen(p, e, enc);
2402 for (c=0; p<e; c++) {
2403 p += rb_enc_mbclen(p, e, enc);
2418rb_enc_strlen_cr(
const char *p,
const char *e,
rb_encoding *enc,
int *cr)
2427 return diff / rb_enc_mbminlen(enc) + !!(diff % rb_enc_mbminlen(enc));
2429 else if (rb_enc_asciicompat(enc)) {
2432 q = search_nonascii(p, e);
2439 ret = rb_enc_precise_mbclen(p, e, enc);
2454 for (c=0; p<e; c++) {
2455 ret = rb_enc_precise_mbclen(p, e, enc);
2462 if (p + rb_enc_mbminlen(enc) <= e)
2463 p += rb_enc_mbminlen(enc);
2479 if (single_byte_optimizable(str))
return RSTRING_LEN(str);
2480 if (!enc) enc = STR_ENC_GET(str);
2481 p = RSTRING_PTR(str);
2486 rb_len_t n = rb_enc_strlen_cr(p, e, enc, &cr);
2491 return enc_strlen(p, e, enc, cr);
2498 return str_strlen(str, NULL);
2512 return LEN2NUM(str_strlen(str, NULL));
2524rb_str_bytesize(
VALUE str)
2526 return LEN2NUM(RSTRING_LEN(str));
2543rb_str_empty(
VALUE str)
2545 return RBOOL(RSTRING_LEN(str) == 0);
2564 const char *ptr1, *ptr2;
2570 enc = rb_enc_check_str(str1, str2);
2573 termlen = rb_enc_mbminlen(enc);
2575 rb_raise(rb_eArgError,
"string size too big");
2577 str3 = str_enc_new(
rb_cString, 0, len1+len2, enc);
2578 ptr3 = RSTRING_PTR(str3);
2579 memcpy(ptr3, ptr1, len1);
2580 memcpy(ptr3+len1, ptr2, len2);
2581 TERM_FILL(&ptr3[len1+len2], termlen);
2597 MAYBE_UNUSED(
char) *ptr1, *ptr2;
2600 int enc1 = rb_enc_get_index(str1);
2601 int enc2 = rb_enc_get_index(str2);
2606 else if (enc2 < 0) {
2609 else if (enc1 != enc2) {
2646 rb_enc_copy(str2, str);
2651 rb_raise(rb_eArgError,
"negative argument");
2653 if (RSTRING_LEN(str) == 1 && RSTRING_PTR(str)[0] == 0) {
2654 if (STR_EMBEDDABLE_P(
len, 1)) {
2656 memset(RSTRING_PTR(str2), 0,
len + 1);
2663 STR_SET_LEN(str2,
len);
2664 rb_enc_copy(str2, str);
2668 rb_raise(rb_eArgError,
"argument too big");
2671 len *= RSTRING_LEN(str);
2672 termlen = TERM_LEN(str);
2674 ptr2 = RSTRING_PTR(str2);
2676 n = RSTRING_LEN(str);
2677 memcpy(ptr2, RSTRING_PTR(str), n);
2678 while (n <=
len/2) {
2679 memcpy(ptr2 + n, ptr2, n);
2682 memcpy(ptr2 + n, ptr2,
len-n);
2684 STR_SET_LEN(str2,
len);
2685 TERM_FILL(&ptr2[
len], termlen);
2686 rb_enc_cr_str_copy_for_substr(str2, str);
2725rb_check_lockedtmp(
VALUE str)
2727 if (
FL_TEST(str, STR_TMPLOCK)) {
2734#define STR_UNMODIFIABLE_MASK (FL_FREEZE | STR_TMPLOCK | STR_CHILLED)
2736str_modifiable(
VALUE str)
2740 if (RB_UNLIKELY(
FL_ANY_RAW(str, STR_UNMODIFIABLE_MASK))) {
2741 if (CHILLED_STRING_P(str)) {
2742 CHILLED_STRING_MUTATED(str);
2744 rb_check_lockedtmp(str);
2745 rb_check_frozen(str);
2750str_dependent_p(
VALUE str)
2752 if (STR_EMBED_P(str) || !
FL_TEST(str, STR_SHARED|STR_NOFREE)) {
2762#define STR_DEPENDANT_MASK (STR_UNMODIFIABLE_MASK | STR_SHARED | STR_NOFREE)
2764str_independent(
VALUE str)
2768 if (RB_UNLIKELY(
FL_ANY_RAW(str, STR_DEPENDANT_MASK))) {
2769 str_modifiable(str);
2770 return !str_dependent_p(str);
2786 if (!STR_EMBED_P(str) && str_embed_capa(str) >=
capa + termlen) {
2791 STR_SET_LEN(str,
len);
2796 oldptr = RSTRING_PTR(str);
2798 memcpy(
ptr, oldptr,
len);
2800 if (
FL_TEST_RAW(str, STR_NOEMBED|STR_NOFREE|STR_SHARED) == STR_NOEMBED) {
2801 SIZED_FREE_N(oldptr, STR_HEAP_SIZE(str));
2803 STR_SET_NOEMBED(str);
2804 FL_UNSET(str, STR_SHARED|STR_NOFREE);
2805 TERM_FILL(
ptr +
len, termlen);
2807 STR_SET_LEN(str,
len);
2814 if (!str_independent(str))
2815 str_make_independent(str);
2824 int termlen = TERM_LEN(str);
2828 rb_raise(rb_eArgError,
"negative expanding string size");
2831 rb_raise(rb_eArgError,
"string size too big");
2834 if (!str_independent(str)) {
2835 str_make_independent_expand(str,
len, expand, termlen);
2837 else if (expand > 0) {
2838 RESIZE_CAPA_TERM(str,
len + expand, termlen);
2845str_modify_keep_cr(
VALUE str)
2847 if (!str_independent(str))
2848 str_make_independent(str);
2855str_discard(
VALUE str)
2857 str_modifiable(str);
2858 if (!STR_EMBED_P(str) && !
FL_TEST(str, STR_SHARED|STR_NOFREE)) {
2859 SIZED_FREE_N(STR_HEAP_PTR(str), STR_HEAP_SIZE(str));
2860 RSTRING(str)->as.heap.ptr = 0;
2861 STR_SET_LEN(str, 0);
2868 int encindex = rb_enc_get_index(str);
2870 if (RB_UNLIKELY(encindex == -1)) {
2874 if (RB_LIKELY(rb_str_encindex_fastpath(encindex))) {
2879 if (!rb_enc_asciicompat(enc)) {
2901 return RSTRING_PTR(str);
2907 const char *e = s +
len;
2909 for (; s + minlen <= e; s += rb_enc_mbclen(s, e, enc)) {
2910 if (zero_filled(s, minlen))
return s;
2921 if (str_dependent_p(str)) {
2922 if (!zero_filled(s +
len, termlen))
2923 str_make_independent_expand(str,
len, 0L, termlen);
2926 TERM_FILL(s +
len, termlen);
2929 return RSTRING_PTR(str);
2933rb_str_change_terminator_length(
VALUE str,
const int oldtermlen,
const int termlen)
2935 rb_len_t capa = str_capacity(str, oldtermlen) + oldtermlen;
2940 rb_check_lockedtmp(str);
2941 str_make_independent_expand(str,
len, 0L, termlen);
2943 else if (str_dependent_p(str)) {
2944 if (termlen > oldtermlen)
2945 str_make_independent_expand(str,
len, 0L, termlen);
2948 if (!STR_EMBED_P(str)) {
2953 if (termlen > oldtermlen) {
2954 TERM_FILL(RSTRING_PTR(str) +
len, termlen);
2962str_null_check(
VALUE str,
int *w)
2964 char *s = RSTRING_PTR(str);
2968 if (RB_UNLIKELY(!rb_str_enc_fastpath(str))) {
2970 minlen = rb_enc_mbminlen(enc);
2974 if (str_null_char(s,
len, minlen, enc)) {
2977 return str_fill_term(str, s,
len, minlen);
2982 if (!s || memchr(s, 0,
len)) {
2986 s = str_fill_term(str, s,
len, minlen);
2991static char *str_to_cstr(
VALUE str);
2994rb_str_null_check(
VALUE str)
3002 if (RB_LIKELY(rb_str_enc_fastpath(str))) {
3003 if (!s || memchr(s, 0,
len)) {
3004 rb_raise(rb_eArgError,
"string contains null byte");
3015rb_str_to_cstr(
VALUE str)
3018 return str_null_check(str, &w);
3025 return str_to_cstr(str);
3029str_to_cstr(
VALUE str)
3032 char *s = str_null_check(str, &w);
3035 rb_raise(rb_eArgError,
"string contains null char");
3037 rb_raise(rb_eArgError,
"string contains null byte");
3043rb_str_fill_terminator(
VALUE str,
const int newminlen)
3045 char *s = RSTRING_PTR(str);
3047 return str_fill_term(str, s,
len, newminlen);
3053 str = rb_check_convert_type_with_id(str,
T_STRING,
"String", idTo_str);
3088 else if (rb_enc_asciicompat(enc)) {
3089 const char *p2, *e2;
3092 while (p < e && 0 < nth) {
3098 p2 = search_nonascii(p, e2);
3106 n = rb_enc_mbclen(p, e, enc);
3117 while (p < e && nth--) {
3118 p += rb_enc_mbclen(p, e, enc);
3129 return str_nth_len(p, e, &nth, enc);
3138 p = str_nth_len(p, e, &nth, enc);
3149 const char *pp = str_nth(p, e, nth, enc, singlebyte);
3150 if (!pp)
return e - p;
3157 return str_offset(RSTRING_PTR(str),
RSTRING_END(str), pos,
3158 STR_ENC_GET(str), single_byte_optimizable(str));
3163str_utf8_nth(
const char *p,
const char *e,
rb_len_t *nthp)
3166 if ((
int)SIZEOF_VOIDP * 2 < e - p && (
int)SIZEOF_VOIDP * 2 < nth) {
3167 const uintptr_t *s, *t;
3168 const uintptr_t lowbits = SIZEOF_VOIDP - 1;
3169 s = (
const uintptr_t*)(~lowbits & ((uintptr_t)p + lowbits));
3170 t = (
const uintptr_t*)(~lowbits & (uintptr_t)e);
3171 while (p < (
const char *)s) {
3172 if (is_utf8_lead_byte(*p)) nth--;
3176 nth -= count_utf8_lead_bytes_with_word(s);
3178 }
while (s < t && (
int)SIZEOF_VOIDP <= nth);
3182 if (is_utf8_lead_byte(*p)) {
3183 if (nth == 0)
break;
3193str_utf8_offset(
const char *p,
const char *e,
rb_len_t nth)
3195 const char *pp = str_utf8_nth(p, e, &nth);
3204 if (single_byte_optimizable(str) || pos < 0)
3207 const char *p = RSTRING_PTR(str);
3208 return enc_strlen(p, p + pos, STR_ENC_GET(str),
ENC_CODERANGE(str));
3221 const int termlen = TERM_LEN(str);
3222 if (!SHARABLE_SUBSTRING_P(str, beg,
len)) {
3223 str2 = rb_enc_str_new(RSTRING_PTR(str) + beg,
len, rb_str_enc_get(str));
3233 const bool root_available = STR_SHARED_P(str) ||
3235 const size_t max_embed_size = root_available ?
3236 rb_gc_size_slot_size(
sizeof(
struct RString)) : STR_COPY_MAX_EMBED_SIZE;
3237 const size_t embed_size = rb_str_embed_size(
len, termlen);
3239 if (embed_size <= max_embed_size && rb_gc_size_allocatable_p(embed_size)) {
3241 char *ptr2 =
RSTRING(str2)->as.embed.ary;
3242 memcpy(ptr2, RSTRING_PTR(str) + beg,
len);
3243 TERM_FILL(ptr2 +
len, termlen);
3245 STR_SET_LEN(str2,
len);
3254 str_replace_shared(str2, str);
3260 RSTRING(str2)->as.heap.ptr += beg;
3261 if (RSTRING_LEN(str2) >
len) {
3262 STR_SET_LEN(str2,
len);
3272 VALUE str2 = str_subseq(str, beg,
len);
3273 rb_enc_cr_str_copy_for_substr(str2, str);
3282 const rb_len_t blen = RSTRING_LEN(str);
3284 const char *p, *s = RSTRING_PTR(str), *e = s + blen;
3286 if (
len < 0)
return 0;
3287 if (beg < 0 && -beg < 0)
return 0;
3291 if (single_byte_optimizable(str)) {
3292 if (beg > blen)
return 0;
3295 if (beg < 0)
return 0;
3297 if (
len > blen - beg)
3299 if (
len < 0)
return 0;
3304 if (
len > -beg)
len = -beg;
3308 while (beg-- >
len && (e = rb_enc_prev_char(s, e, e, enc)) != 0);
3311 while (
len-- > 0 && (p = rb_enc_prev_char(s, p, e, enc)) != 0);
3317 slen = str_strlen(str, enc);
3319 if (beg < 0)
return 0;
3321 if (
len == 0)
goto end;
3324 else if (beg > 0 && beg > blen) {
3328 if (beg > str_strlen(str, enc))
return 0;
3333 enc == rb_utf8_encoding()) {
3334 p = str_utf8_nth(s, e, &beg);
3335 if (beg > 0)
return 0;
3336 len = str_utf8_offset(p, e,
len);
3342 p = s + beg * char_sz;
3346 else if (
len * char_sz > e - p)
3351 else if ((p = str_nth_len(s, e, &beg, enc)) == e) {
3352 if (beg > 0)
return 0;
3356 len = str_offset(p, e,
len, enc, 0);
3369 return str_substr(str, beg,
len, TRUE);
3383 if (!p)
return Qnil;
3384 if (!
len && !empty)
return Qnil;
3386 beg = p - RSTRING_PTR(str);
3388 VALUE str2 = str_subseq(str, beg,
len);
3389 rb_enc_cr_str_copy_for_substr(str2, str);
3397 if (CHILLED_STRING_P(str)) {
3402 rb_str_resize(str, RSTRING_LEN(str));
3420 if (
OBJ_FROZEN(str) || CHILLED_STRING_P(str)) {
3463str_uminus(
VALUE str)
3468 return rb_fstring(str);
3472#define rb_str_dup_frozen rb_str_new_frozen
3477 rb_check_frozen(str);
3478 if (
FL_TEST(str, STR_TMPLOCK)) {
3481 FL_SET(str, STR_TMPLOCK);
3488 rb_check_frozen(str);
3489 if (!
FL_TEST(str, STR_TMPLOCK)) {
3509 const int termlen = TERM_LEN(str);
3511 str_modifiable(str);
3512 if (STR_SHARED_P(str)) {
3516 rb_bug(
"probable buffer overflow: %"PRIdLEN
" for %"PRIdLEN,
len,
capa);
3527 else if (
len > RSTRING_LEN(str)) {
3531 const char *
const new_end = RSTRING_PTR(str) +
len;
3541 else if (
len < RSTRING_LEN(str)) {
3549 STR_SET_LEN(str,
len);
3550 TERM_FILL(&RSTRING_PTR(str)[
len], termlen);
3557 rb_raise(rb_eArgError,
"negative string size (or size too big)");
3560 int independent = str_independent(str);
3562 const int termlen = TERM_LEN(str);
3564 if (slen >
len || (termlen != 1 && slen <
len)) {
3570 if (STR_EMBED_P(str)) {
3571 if (
len == slen)
return str;
3572 if (str_embed_capa(str) >=
len + termlen) {
3573 STR_SET_LEN(str,
len);
3577 str_make_independent_expand(str, slen,
len - slen, termlen);
3579 else if (str_embed_capa(str) >=
len + termlen) {
3581 char *
ptr = STR_HEAP_PTR(str);
3583 if (slen >
len) slen =
len;
3586 STR_SET_LEN(str,
len);
3588 SIZED_FREE_N(
ptr,
capa + termlen);
3592 else if (!independent) {
3593 if (
len == slen)
return str;
3594 str_make_independent_expand(str, slen,
len - slen, termlen);
3598 SIZED_REALLOC_N(
RSTRING(str)->
as.heap.ptr,
char,
3599 (
size_t)
len + termlen, STR_HEAP_SIZE(str));
3602 else if (
len == slen)
return str;
3603 STR_SET_LEN(str,
len);
3612 str_modify_keep_cr(str);
3614 const int termlen = TERM_LEN(str);
3618 rb_raise(rb_eArgError,
"string sizes too big");
3628 while (total >
capa) {
3631 RESIZE_CAPA_TERM(str,
capa, termlen);
3639 str_modify_keep_cr(str);
3644 if (
len == 0)
return 0;
3648 const int termlen = TERM_LEN(str);
3651 if (
ptr >= sptr &&
ptr <= sptr + olen) {
3658 rb_raise(rb_eArgError,
"string sizes too big");
3665 while (total >
capa) {
3668 RESIZE_CAPA_TERM(str,
capa, termlen);
3669 sptr = RSTRING_PTR(str);
3674 memcpy(sptr + olen,
ptr,
len);
3675 STR_SET_LEN(str, total);
3676 TERM_FILL(sptr + total, termlen);
3681#define str_buf_cat(str, ptr, len) str_buf_cat4((str), (ptr), len, false)
3682#define str_buf_cat2(str, ptr) str_buf_cat4((str), (ptr), rb_strlen_lit(ptr), false)
3687 if (
len == 0)
return str;
3689 rb_raise(rb_eArgError,
"negative string size (or size too big)");
3691 return str_buf_cat(str,
ptr,
len);
3702rb_str_buf_cat_byte(
VALUE str,
unsigned char byte)
3707 if (UNLIKELY(!str_independent(str))) {
3708 str_make_independent(str);
3712 const int null_terminator_length = 1;
3717 if (UNLIKELY(string_length >
RB_LEN_MAX - 1)) {
3718 rb_raise(rb_eArgError,
"string sizes too big");
3721 rb_len_t string_capacity = str_capacity(str, null_terminator_length);
3727 if (LIKELY(string_capacity >= string_length + 1)) {
3729 sptr[string_length] = byte;
3730 STR_SET_LEN(str, string_length + 1);
3731 TERM_FILL(sptr + string_length + 1, null_terminator_length);
3735 str_buf_cat(str, (
char *)&
byte, 1);
3751 rb_enc_associate_index(str, ENCINDEX_ASCII_8BIT);
3763 int ptr_encindex,
int ptr_cr,
int *ptr_cr_ret)
3772 if (str_encindex == ptr_encindex) {
3774 ptr_cr = coderange_scan(
ptr,
len, rb_enc_from_index(ptr_encindex));
3778 str_enc = rb_enc_from_index(str_encindex);
3779 ptr_enc = rb_enc_from_index(ptr_encindex);
3780 if (!rb_enc_asciicompat(str_enc) || !rb_enc_asciicompat(ptr_enc)) {
3783 if (RSTRING_LEN(str) == 0) {
3786 rb_str_change_terminator_length(str, rb_enc_mbminlen(str_enc), rb_enc_mbminlen(ptr_enc));
3792 ptr_cr = coderange_scan(
ptr,
len, ptr_enc);
3796 str_cr = rb_enc_str_coderange(str);
3801 *ptr_cr_ret = ptr_cr;
3803 if (str_encindex != ptr_encindex &&
3806 str_enc = rb_enc_from_index(str_encindex);
3807 ptr_enc = rb_enc_from_index(ptr_encindex);
3812 res_encindex = str_encindex;
3817 res_encindex = str_encindex;
3821 res_encindex = ptr_encindex;
3826 res_encindex = str_encindex;
3833 res_encindex = str_encindex;
3839 rb_raise(rb_eArgError,
"negative string size (or size too big)");
3841 str_buf_cat(str,
ptr,
len);
3847 rb_enc_inspect_name(str_enc), rb_enc_inspect_name(ptr_enc));
3854 return rb_enc_cr_str_buf_cat(str,
ptr,
len,
3864 if (rb_enc_asciicompat(enc)) {
3865 return rb_enc_cr_str_buf_cat(str,
ptr, strlen(
ptr),
3871 unsigned int c = (
unsigned char)*
ptr;
3872 int len = rb_enc_codelen(c, enc);
3873 rb_enc_mbcput(c, buf, enc);
3874 rb_enc_cr_str_buf_cat(str, buf,
len,
3885 int str2_cr = rb_enc_str_coderange(str2);
3887 if (rb_str_enc_fastpath(str)) {
3891 str_buf_cat4(str, RSTRING_PTR(str2), RSTRING_LEN(str2),
true);
3897 str_buf_cat4(str, RSTRING_PTR(str2), RSTRING_LEN(str2),
true);
3908 rb_enc_cr_str_buf_cat(str, RSTRING_PTR(str2), RSTRING_LEN(str2),
3924rb_str_concat_literals(
size_t num,
const VALUE *strary)
3933 for (i = 0; i < num; ++i) {
len += RSTRING_LEN(strary[i]); }
3935 str_enc_copy_direct(str, strary[0]);
3937 for (i = s; i < num; ++i) {
3938 const VALUE v = strary[i];
3942 if (encidx != ENCINDEX_US_ASCII) {
3944 rb_enc_set_index(str, encidx);
3957rb_str_concat_multi(
int argc,
VALUE *argv,
VALUE str)
3959 str_modifiable(str);
3964 else if (argc > 1) {
3967 rb_enc_copy(arg_str, str);
3968 for (i = 0; i < argc; i++) {
4003rb_str_append_as_bytes(
int argc,
VALUE *argv,
VALUE str)
4009 for (
int index = 0; index < argc; index++) {
4010 VALUE obj = argv[index];
4018 needed_capacity += RSTRING_LEN(obj);
4023 "wrong argument type %"PRIsVALUE
" (expected String or Integer)",
4030 str_ensure_available_capa(str, needed_capacity);
4033 for (
int index = 0; index < argc; index++) {
4034 VALUE obj = argv[index];
4039 argv[index] = obj = rb_int_and(obj,
INT2FIX(0xff));
4040 char byte = (char)(
NUM2INT(obj) & 0xFF);
4054 rb_bug(
"append_as_bytes arguments should have been validated");
4058 STR_SET_LEN(str, RSTRING_LEN(str) + needed_capacity);
4059 TERM_FILL(sptr, TERM_LEN(str));
4064 for (
int index = 0; index < argc; index++) {
4065 VALUE obj = argv[index];
4082 rb_bug(
"append_as_bytes arguments should have been validated");
4160 if (rb_num_to_uint(str2, &code) == 0) {
4173 encidx = rb_ascii8bit_appendable_encoding_index(enc, code);
4176 rb_str_buf_cat_byte(str1, (
unsigned char)code);
4184 switch (
len = rb_enc_codelen(code, enc)) {
4185 case ONIGERR_INVALID_CODE_POINT_VALUE:
4186 rb_raise(
rb_eRangeError,
"invalid codepoint 0x%X in %s", code, rb_enc_name(enc));
4188 case ONIGERR_TOO_BIG_WIDE_CHAR_VALUE:
4194 rb_enc_mbcput(code, buf, enc);
4195 if (rb_enc_precise_mbclen(buf, buf +
len + 1, enc) !=
len) {
4196 rb_raise(
rb_eRangeError,
"invalid codepoint 0x%X in %s", code, rb_enc_name(enc));
4198 rb_str_resize(str1, pos+
len);
4199 memcpy(RSTRING_PTR(str1) + pos, buf,
len);
4212rb_ascii8bit_appendable_encoding_index(
rb_encoding *enc,
unsigned int code)
4214 int encidx = rb_enc_to_index(enc);
4216 if (encidx == ENCINDEX_ASCII_8BIT || encidx == ENCINDEX_US_ASCII) {
4221 if (encidx == ENCINDEX_US_ASCII && code > 127) {
4222 return ENCINDEX_ASCII_8BIT;
4244rb_str_prepend_multi(
int argc,
VALUE *argv,
VALUE str)
4246 str_modifiable(str);
4251 else if (argc > 1) {
4254 rb_enc_copy(arg_str, str);
4255 for (i = 0; i < argc; i++) {
4268 st_index_t precomputed_hash;
4269 memcpy(&precomputed_hash,
RSTRING_END(str) + TERM_LEN(str),
sizeof(precomputed_hash));
4271 RUBY_ASSERT(precomputed_hash == str_do_hash(str));
4272 return precomputed_hash;
4275 return str_do_hash(str);
4282 const char *ptr1, *ptr2;
4285 return (len1 != len2 ||
4287 memcmp(ptr1, ptr2, len1) != 0);
4299rb_str_hash_m(
VALUE str)
4305#define lesser(a,b) (((a)>(b))?(b):(a))
4313 if (RSTRING_LEN(str1) == 0)
return TRUE;
4314 if (RSTRING_LEN(str2) == 0)
return TRUE;
4317 if (idx1 == idx2)
return TRUE;
4318 rc1 = rb_enc_str_coderange(str1);
4319 rc2 = rb_enc_str_coderange(str2);
4322 if (rb_enc_asciicompat(rb_enc_from_index(idx2)))
4326 if (rb_enc_asciicompat(rb_enc_from_index(idx1)))
4336 const char *ptr1, *ptr2;
4339 if (str1 == str2)
return 0;
4342 if (ptr1 == ptr2 || (retval = memcmp(ptr1, ptr2, lesser(len1, len2))) == 0) {
4351 if (len1 > len2)
return 1;
4354 if (retval > 0)
return 1;
4388 if (str1 == str2)
return Qtrue;
4395 return rb_str_eql_internal(str1, str2);
4409 if (str1 == str2)
return Qtrue;
4411 return rb_str_eql_internal(str1, str2);
4449 return rb_invcmp(str1, str2);
4491 return str_casecmp(str1, s);
4499 const char *p1, *p1end, *p2, *p2end;
4501 enc = rb_enc_compatible(str1, str2);
4506 p1 = RSTRING_PTR(str1); p1end =
RSTRING_END(str1);
4507 p2 = RSTRING_PTR(str2); p2end =
RSTRING_END(str2);
4508 if (single_byte_optimizable(str1) && single_byte_optimizable(str2)) {
4509 while (p1 < p1end && p2 < p2end) {
4511 unsigned int c1 =
TOLOWER(*p1 & 0xff);
4512 unsigned int c2 =
TOLOWER(*p2 & 0xff);
4514 return INT2FIX(c1 < c2 ? -1 : 1);
4521 while (p1 < p1end && p2 < p2end) {
4522 int l1, c1 = rb_enc_ascget(p1, p1end, &l1, enc);
4523 int l2, c2 = rb_enc_ascget(p2, p2end, &l2, enc);
4525 if (0 <= c1 && 0 <= c2) {
4529 return INT2FIX(c1 < c2 ? -1 : 1);
4533 l1 = rb_enc_mbclen(p1, p1end, enc);
4534 l2 = rb_enc_mbclen(p2, p2end, enc);
4535 len = l1 < l2 ? l1 : l2;
4536 r = memcmp(p1, p2,
len);
4538 return INT2FIX(r < 0 ? -1 : 1);
4540 return INT2FIX(l1 < l2 ? -1 : 1);
4546 if (p1 == p1end && p2 == p2end)
return INT2FIX(0);
4547 if (p1 == p1end)
return INT2FIX(-1);
4580 return str_casecmp_p(str1, s);
4587 VALUE folded_str1, folded_str2;
4588 VALUE fold_opt = sym_fold;
4590 enc = rb_enc_compatible(str1, str2);
4595 if (is_ascii_string(str1) && is_ascii_string(str2)) {
4596 if (RSTRING_LEN(str1) != RSTRING_LEN(str2))
return Qfalse;
4597 const char *p1 = RSTRING_PTR(str1), *p1end =
RSTRING_END(str1);
4598 const char *p2 = RSTRING_PTR(str2);
4599 while (p1 < p1end) {
4600 if (*p1 != *p2 &&
TOLOWER((
unsigned char)*p1) !=
TOLOWER((
unsigned char)*p2)) {
4609 folded_str1 = rb_str_downcase(1, &fold_opt, str1);
4610 folded_str2 = rb_str_downcase(1, &fold_opt, str2);
4612 return rb_str_eql(folded_str1, folded_str2);
4616strseq_core(
const char *str_ptr,
const char *str_ptr_end,
rb_len_t str_len,
4619 const char *search_start = str_ptr;
4620 rb_len_t pos, search_len = str_len - offset;
4624 pos =
rb_memsearch(sub_ptr, sub_len, search_start, search_len, enc);
4625 if (pos < 0)
return pos;
4627 if (t == search_start + pos)
break;
4628 search_len -= t - search_start;
4629 if (search_len <= 0)
return -1;
4630 offset += t - search_start;
4633 return pos + offset;
4637#define rb_str_index(str, sub, offset) rb_strseq_index(str, sub, offset, 0)
4638#define rb_str_byteindex(str, sub, offset) rb_strseq_index(str, sub, offset, 1)
4643 const char *str_ptr, *str_ptr_end, *sub_ptr;
4647 enc = rb_enc_check(str, sub);
4648 if (is_broken_string(sub))
return -1;
4650 str_ptr = RSTRING_PTR(str);
4652 str_len = RSTRING_LEN(str);
4653 sub_ptr = RSTRING_PTR(sub);
4654 sub_len = RSTRING_LEN(sub);
4656 if (str_len < sub_len)
return -1;
4659 rb_len_t str_len_char, sub_len_char;
4660 int single_byte = single_byte_optimizable(str);
4661 str_len_char = (in_byte || single_byte) ? str_len : str_strlen(str, enc);
4662 sub_len_char = in_byte ? sub_len : str_strlen(sub, enc);
4664 offset += str_len_char;
4665 if (offset < 0)
return -1;
4667 if (str_len_char - offset < sub_len_char)
return -1;
4668 if (!in_byte) offset = str_offset(str_ptr, str_ptr_end, offset, enc, single_byte);
4671 if (sub_len == 0)
return offset;
4674 return strseq_core(str_ptr, str_ptr_end, str_len, sub_ptr, sub_len, offset, enc);
4687rb_str_index_m(
int argc,
VALUE *argv,
VALUE str)
4694 if (
rb_scan_args(argc, argv,
"11", &sub, &initpos) == 2) {
4695 rb_len_t slen = str_strlen(str, enc);
4697 if (pos < 0 ? (pos += slen) < 0 : pos > slen) {
4709 pos = str_offset(RSTRING_PTR(str),
RSTRING_END(str), pos,
4710 enc, single_byte_optimizable(str));
4720 pos = rb_str_index(str, sub, pos);
4736 if (!single_byte_optimizable(str)) {
4737 const char *s = RSTRING_PTR(str);
4739 const char *p = s + pos;
4740 if (!at_char_boundary(s, p, e, rb_enc_get(str))) {
4742 "offset %"PRIdLEN
" does not land on character boundary", pos);
4815rb_str_byteindex_m(
int argc,
VALUE *argv,
VALUE str)
4821 if (
rb_scan_args(argc, argv,
"11", &sub, &initpos) == 2) {
4824 if (pos < 0 ? (pos += slen) < 0 : pos > slen) {
4835 str_ensure_byte_pos(str, pos);
4840 pos = RMATCH_BEG(match, 0);
4846 pos = rb_str_byteindex(str, sub, pos);
4847 if (pos >= 0)
return LEN2NUM(pos);
4855 const char *hit, *adjusted, *sbeg, *e, *t;
4859 sbeg = RSTRING_PTR(str);
4860 slen = RSTRING_LEN(sub);
4861 if (slen == 0)
return s - sbeg;
4863 t = RSTRING_PTR(sub);
4865 searchlen = s - sbeg + 1;
4867 if (s + slen <= e && memcmp(s, t, slen) == 0) {
4872 hit = memrchr(sbeg, c, searchlen);
4875 if (hit != adjusted) {
4876 searchlen = adjusted - sbeg;
4879 if (hit + slen <= e && memcmp(hit, t, slen) == 0)
4881 searchlen = adjusted - sbeg;
4882 }
while (searchlen > 0);
4892 const char *sbeg, *s;
4896 enc = rb_enc_check(str, sub);
4897 if (is_broken_string(sub))
return -1;
4898 singlebyte = single_byte_optimizable(str);
4899 len = singlebyte ? RSTRING_LEN(str) : str_strlen(str, enc);
4900 slen = str_strlen(sub, enc);
4903 if (
len < slen)
return -1;
4905 if (
len - pos < slen) pos =
len - slen;
4906 if (
len == 0)
return pos;
4908 sbeg = RSTRING_PTR(str);
4911 if (RSTRING_LEN(sub) <= RSTRING_LEN(str) &&
4912 memcmp(sbeg, RSTRING_PTR(sub), RSTRING_LEN(sub)) == 0) {
4920 s = str_nth(sbeg,
RSTRING_END(str), pos, enc, singlebyte);
4921 return str_rindex(str, sub, s, enc);
4933rb_str_rindex_m(
int argc,
VALUE *argv,
VALUE str)
4940 if (
rb_scan_args(argc, argv,
"11", &sub, &initpos) == 2) {
4942 if (pos < 0 && (pos +=
len) < 0) {
4948 if (pos >
len) pos =
len;
4956 pos = str_offset(RSTRING_PTR(str),
RSTRING_END(str), pos,
4957 enc, single_byte_optimizable(str));
4967 pos = rb_str_rindex(str, sub, pos);
4980 const char *sbeg, *s;
4983 enc = rb_enc_check(str, sub);
4984 if (is_broken_string(sub))
return -1;
4985 len = RSTRING_LEN(str);
4986 slen = RSTRING_LEN(sub);
4989 if (
len < slen)
return -1;
4990 if (
len - pos < slen) pos =
len - slen;
4991 if (
len == 0)
return pos;
4993 sbeg = RSTRING_PTR(str);
4996 if (memcmp(sbeg, RSTRING_PTR(sub), RSTRING_LEN(sub)) == 0)
5003 return str_rindex(str, sub, s, enc);
5093rb_str_byterindex_m(
int argc,
VALUE *argv,
VALUE str)
5099 if (
rb_scan_args(argc, argv,
"11", &sub, &initpos) == 2) {
5102 if (pos < 0 && (pos +=
len) < 0) {
5108 if (pos >
len) pos =
len;
5111 pos = RSTRING_LEN(str);
5114 str_ensure_byte_pos(str, pos);
5119 pos = RMATCH_BEG(match, 0);
5125 pos = rb_str_byterindex(str, sub, pos);
5126 if (pos >= 0)
return LEN2NUM(pos);
5168 switch (OBJ_BUILTIN_TYPE(y)) {
5220rb_str_match_m(
int argc,
VALUE *argv,
VALUE str)
5227 result =
rb_funcallv(get_pat(re), rb_intern(
"match"), argc, argv);
5258rb_str_match_m_p(
int argc,
VALUE *argv,
VALUE str)
5262 re = get_pat(argv[0]);
5263 return rb_reg_match_p(re, str, argc > 1 ?
NUM2LEN(argv[1]) : 0);
5272static enum neighbor_char
5278 if (rb_enc_mbminlen(enc) > 1) {
5280 int r = rb_enc_precise_mbclen(p, p +
len, enc), c;
5282 return NEIGHBOR_NOT_CHAR;
5284 c = rb_enc_mbc_to_codepoint(p, p +
len, enc) + 1;
5286 if (!l)
return NEIGHBOR_NOT_CHAR;
5287 if (l !=
len)
return NEIGHBOR_WRAPPED;
5288 rb_enc_mbcput(c, p, enc);
5289 r = rb_enc_precise_mbclen(p, p +
len, enc);
5291 return NEIGHBOR_NOT_CHAR;
5293 return NEIGHBOR_FOUND;
5296 for (i =
len-1; 0 <= i && (
unsigned char)p[i] == 0xff; i--)
5299 return NEIGHBOR_WRAPPED;
5300 ++((
unsigned char*)p)[i];
5301 l = rb_enc_precise_mbclen(p, p+
len, enc);
5305 return NEIGHBOR_FOUND;
5308 memset(p+l, 0xff,
len-l);
5314 for (len2 =
len-1; 0 < len2; len2--) {
5315 l2 = rb_enc_precise_mbclen(p, p+len2, enc);
5319 memset(p+len2+1, 0xff,
len-(len2+1));
5324static enum neighbor_char
5329 if (rb_enc_mbminlen(enc) > 1) {
5331 int r = rb_enc_precise_mbclen(p, p +
len, enc), c;
5333 return NEIGHBOR_NOT_CHAR;
5335 c = rb_enc_mbc_to_codepoint(p, p +
len, enc);
5336 if (!c)
return NEIGHBOR_NOT_CHAR;
5339 if (!l)
return NEIGHBOR_NOT_CHAR;
5340 if (l !=
len)
return NEIGHBOR_WRAPPED;
5341 rb_enc_mbcput(c, p, enc);
5342 r = rb_enc_precise_mbclen(p, p +
len, enc);
5344 return NEIGHBOR_NOT_CHAR;
5346 return NEIGHBOR_FOUND;
5349 for (i =
len-1; 0 <= i && (
unsigned char)p[i] == 0; i--)
5352 return NEIGHBOR_WRAPPED;
5353 --((
unsigned char*)p)[i];
5354 l = rb_enc_precise_mbclen(p, p+
len, enc);
5358 return NEIGHBOR_FOUND;
5361 memset(p+l, 0,
len-l);
5367 for (len2 =
len-1; 0 < len2; len2--) {
5368 l2 = rb_enc_precise_mbclen(p, p+len2, enc);
5372 memset(p+len2+1, 0,
len-(len2+1));
5386static enum neighbor_char
5389 enum neighbor_char ret;
5393 char save[ONIGENC_CODE_TO_MBC_MAXLEN];
5397 const int max_gaps = 1;
5399 c = rb_enc_mbc_to_codepoint(p, p+
len, enc);
5401 ctype = ONIGENC_CTYPE_DIGIT;
5403 ctype = ONIGENC_CTYPE_ALPHA;
5405 return NEIGHBOR_NOT_CHAR;
5408 for (
try = 0;
try <= max_gaps; ++
try) {
5409 ret = enc_succ_char(p,
len, enc);
5410 if (ret == NEIGHBOR_FOUND) {
5411 c = rb_enc_mbc_to_codepoint(p, p+
len, enc);
5413 return NEIGHBOR_FOUND;
5420 ret = enc_pred_char(p,
len, enc);
5421 if (ret == NEIGHBOR_FOUND) {
5422 c = rb_enc_mbc_to_codepoint(p, p+
len, enc);
5435 return NEIGHBOR_NOT_CHAR;
5438 if (ctype != ONIGENC_CTYPE_DIGIT) {
5440 return NEIGHBOR_WRAPPED;
5444 enc_succ_char(carry,
len, enc);
5445 return NEIGHBOR_WRAPPED;
5463 str =
rb_str_new(RSTRING_PTR(orig), RSTRING_LEN(orig));
5464 rb_enc_cr_str_copy_for_substr(str, orig);
5465 return str_succ(str);
5472 char *sbeg, *s, *e, *last_alnum = 0;
5473 int found_alnum = 0;
5475 char carry[ONIGENC_CODE_TO_MBC_MAXLEN] =
"\1";
5476 rb_len_t carry_pos = 0, carry_len = 1;
5477 enum neighbor_char neighbor = NEIGHBOR_FOUND;
5479 slen = RSTRING_LEN(str);
5480 if (slen == 0)
return str;
5482 enc = STR_ENC_GET(str);
5483 sbeg = RSTRING_PTR(str);
5484 s = e = sbeg + slen;
5486 while ((s = rb_enc_prev_char(sbeg, s, e, enc)) != 0) {
5487 if (neighbor == NEIGHBOR_NOT_CHAR && last_alnum) {
5493 l = rb_enc_precise_mbclen(s, e, enc);
5494 if (!ONIGENC_MBCLEN_CHARFOUND_P(l))
continue;
5495 l = ONIGENC_MBCLEN_CHARFOUND_LEN(l);
5496 neighbor = enc_succ_alnum_char(s, l, enc, carry);
5498 case NEIGHBOR_NOT_CHAR:
5500 case NEIGHBOR_FOUND:
5502 case NEIGHBOR_WRAPPED:
5507 carry_pos = s - sbeg;
5512 while ((s = rb_enc_prev_char(sbeg, s, e, enc)) != 0) {
5513 enum neighbor_char neighbor;
5514 char tmp[ONIGENC_CODE_TO_MBC_MAXLEN];
5515 l = rb_enc_precise_mbclen(s, e, enc);
5516 if (!ONIGENC_MBCLEN_CHARFOUND_P(l))
continue;
5517 l = ONIGENC_MBCLEN_CHARFOUND_LEN(l);
5519 neighbor = enc_succ_char(tmp, l, enc);
5521 case NEIGHBOR_FOUND:
5525 case NEIGHBOR_WRAPPED:
5528 case NEIGHBOR_NOT_CHAR:
5531 if (rb_enc_precise_mbclen(s, s+l, enc) != l) {
5533 enc_succ_char(s, l, enc);
5535 if (!rb_enc_asciicompat(enc)) {
5536 MEMCPY(carry, s,
char, l);
5539 carry_pos = s - sbeg;
5543 RESIZE_CAPA(str, slen + carry_len);
5544 sbeg = RSTRING_PTR(str);
5545 s = sbeg + carry_pos;
5546 memmove(s + carry_len, s, slen - carry_pos);
5547 memmove(s, carry, carry_len);
5549 STR_SET_LEN(str, slen);
5550 TERM_FILL(&sbeg[slen], rb_enc_mbminlen(enc));
5551 rb_enc_str_coderange(str);
5566rb_str_succ_bang(
VALUE str)
5602 VALUE end, exclusive;
5606 return rb_str_upto_each(beg, end,
RTEST(exclusive), str_upto_i,
Qnil);
5612 VALUE current, after_end;
5619 enc = rb_enc_check(beg, end);
5620 ascii = (is_ascii_string(beg) && is_ascii_string(end));
5622 if (RSTRING_LEN(beg) == 1 && RSTRING_LEN(end) == 1 && ascii) {
5623 char c = RSTRING_PTR(beg)[0];
5624 char e = RSTRING_PTR(end)[0];
5626 if (c > e || (excl && c == e))
return beg;
5628 VALUE str = rb_enc_str_new(&c, 1, enc);
5630 if ((*each)(str, arg))
break;
5631 if (!excl && c == e)
break;
5633 if (excl && c == e)
break;
5638 if (ascii &&
ISDIGIT(RSTRING_PTR(beg)[0]) &&
ISDIGIT(RSTRING_PTR(end)[0]) &&
5639 all_digits_p(RSTRING_PTR(beg), RSTRING_LEN(beg)) &&
5640 all_digits_p(RSTRING_PTR(end), RSTRING_LEN(end))) {
5645 b = rb_str_to_inum(beg, 10, FALSE);
5646 e = rb_str_to_inum(end, 10, FALSE);
5653 if (excl && bi == ei)
break;
5654 if ((*each)(
rb_enc_sprintf(usascii,
"%.*ld", width, bi), arg))
break;
5659 ID op = excl ?
'<' : idLE;
5660 VALUE args[2], fmt = rb_fstring_lit(
"%.*d");
5665 if ((*each)(
rb_str_format(numberof(args), args, fmt), arg))
break;
5673 if (n > 0 || (excl && n == 0))
return beg;
5681 if ((*each)(current, arg))
break;
5682 if (
NIL_P(next))
break;
5686 if (RSTRING_LEN(current) > RSTRING_LEN(end) || RSTRING_LEN(current) == 0)
5701 if (is_ascii_string(beg) &&
ISDIGIT(RSTRING_PTR(beg)[0]) &&
5702 all_digits_p(RSTRING_PTR(beg), RSTRING_LEN(beg))) {
5703 VALUE b, args[2], fmt = rb_fstring_lit(
"%.*d");
5705 b = rb_str_to_inum(beg, 10, FALSE);
5711 if ((*each)(
rb_enc_sprintf(usascii,
"%.*ld", width, bi), arg))
break;
5719 if ((*each)(
rb_str_format(numberof(args), args, fmt), arg))
break;
5727 if ((*each)(current, arg))
break;
5730 if (RSTRING_LEN(current) == 0)
5741 if (!
rb_equal(str, *argp))
return 0;
5755 if (rb_enc_asciicompat(STR_ENC_GET(beg)) &&
5756 rb_enc_asciicompat(STR_ENC_GET(end)) &&
5757 rb_enc_asciicompat(STR_ENC_GET(val))) {
5758 const char *bp = RSTRING_PTR(beg);
5759 const char *ep = RSTRING_PTR(end);
5760 const char *vp = RSTRING_PTR(val);
5761 if (RSTRING_LEN(beg) == 1 && RSTRING_LEN(end) == 1) {
5762 if (RSTRING_LEN(val) == 0 || RSTRING_LEN(val) > 1)
5770 if (b <= v && v < e)
return Qtrue;
5771 return RBOOL(!
RTEST(exclusive) && b <= v && v == e);
5778 all_digits_p(bp, RSTRING_LEN(beg)) &&
5779 all_digits_p(ep, RSTRING_LEN(end))) {
5784 rb_str_upto_each(beg, end,
RTEST(exclusive), include_range_i, (
VALUE)&val);
5786 return RBOOL(
NIL_P(val));
5809 return rb_str_subpat(str, indx,
INT2FIX(0));
5812 if (rb_str_index(str, indx, 0) != -1)
5830 return str_substr(str, idx, 1, FALSE);
5847rb_str_aref_m(
int argc,
VALUE *argv,
VALUE str)
5851 return rb_str_subpat(str, argv[0], argv[1]);
5854 return rb_str_substr_two_fixnums(str, argv[0], argv[1], TRUE);
5858 return rb_str_aref(str, argv[0]);
5864 char *
ptr = RSTRING_PTR(str);
5865 rb_len_t olen = RSTRING_LEN(str), nlen;
5867 str_modifiable(str);
5868 if (
len > olen)
len = olen;
5870 if (str_embed_capa(str) >= nlen + TERM_LEN(str)) {
5872 size_t old_capa =
RSTRING(str)->as.heap.aux.capa + TERM_LEN(str);
5873 int fl = (int)(
RBASIC(str)->flags & (STR_NOEMBED|STR_SHARED|STR_NOFREE));
5876 memmove(
ptr, oldptr +
len, nlen);
5877 if (fl == STR_NOEMBED) {
5878 SIZED_FREE_N(oldptr, old_capa);
5882 if (!STR_SHARED_P(str)) {
5884 rb_enc_cr_str_exact_copy(
shared, str);
5889 STR_SET_LEN(str, nlen);
5891 if (!SHARABLE_MIDDLE_SUBSTRING) {
5892 TERM_FILL(
ptr + nlen, TERM_LEN(str));
5905 if (beg == 0 && vlen == 0) {
5910 str_modify_keep_cr(str);
5914 RESIZE_CAPA(str, slen + vlen -
len);
5915 sptr = RSTRING_PTR(str);
5919 cr = rb_enc_str_coderange(val);
5924 memmove(sptr + beg + vlen,
5926 slen - (beg +
len));
5928 if (vlen < beg &&
len < 0) {
5932 memmove(sptr + beg, RSTRING_PTR(val) + vbeg, vlen);
5935 STR_SET_LEN(str, slen);
5936 TERM_FILL(&sptr[slen], TERM_LEN(str));
5943 rb_str_update_1(str, beg,
len, val, 0, RSTRING_LEN(val));
5952 int singlebyte = single_byte_optimizable(str);
5958 enc = rb_enc_check(str, val);
5959 slen = str_strlen(str, enc);
5961 if ((slen < beg) || ((beg < 0) && (beg + slen < 0))) {
5970 if (
len > slen - beg) {
5973 p = str_nth(RSTRING_PTR(str),
RSTRING_END(str), beg, enc, singlebyte);
5978 beg = p - RSTRING_PTR(str);
5980 rb_str_update_0(str, beg,
len, val);
5981 rb_enc_associate(str, enc);
6000 int num_regs = RMATCH_NREGS(match);
6001 if ((nth >= num_regs) || ((nth < 0) && (-nth >= num_regs))) {
6008 start = RMATCH_BEG(match, nth);
6012 end = RMATCH_END(match, nth);
6016 if (start +
len > RSTRING_LEN(str)) {
6020 enc = rb_enc_check_str(str, val);
6021 rb_str_update_0(str, start,
len, val);
6022 rb_enc_associate(str, enc);
6030 switch (
TYPE(indx)) {
6032 rb_str_subpat_set(str, indx,
INT2FIX(0), val);
6036 beg = rb_str_index(str, indx, 0);
6075rb_str_aset_m(
int argc,
VALUE *argv,
VALUE str)
6079 rb_str_subpat_set(str, argv[0], argv[1], argv[2]);
6087 return rb_str_aset(str, argv[0], argv[1]);
6139rb_str_slice_bang(
int argc,
VALUE *argv,
VALUE str)
6147 str_modify_keep_cr(str);
6152 int num_regs = RMATCH_NREGS(match);
6155 if ((nth += num_regs) <= 0)
return Qnil;
6157 else if (nth >= num_regs)
return Qnil;
6158 beg = RMATCH_BEG(match, nth);
6159 len = RMATCH_END(match, nth) - beg;
6161 if (beg > RSTRING_LEN(str))
return Qnil;
6162 if (
len > RSTRING_LEN(str) - beg)
len = RSTRING_LEN(str) - beg;
6165 else if (argc == 2) {
6174 beg = p - RSTRING_PTR(str);
6178 beg = rb_str_index(str, indx, 0);
6179 if (beg == -1)
return Qnil;
6180 len = RSTRING_LEN(indx);
6192 beg = p - RSTRING_PTR(str);
6201 beg = p - RSTRING_PTR(str);
6205 rb_enc_cr_str_copy_for_substr(result, str);
6213 char *sptr = RSTRING_PTR(str);
6215 if (beg +
len > slen)
6219 slen - (beg +
len));
6221 STR_SET_LEN(str, slen);
6222 TERM_FILL(&sptr[slen], TERM_LEN(str));
6233 switch (OBJ_BUILTIN_TYPE(pat)) {
6252get_pat_quoted(
VALUE pat,
int check)
6256 switch (OBJ_BUILTIN_TYPE(pat)) {
6270 if (check && is_broken_string(pat)) {
6280 pos = rb_str_byteindex(str, pat, pos);
6281 if (set_backref_str) {
6283 str = rb_str_new_frozen_String(str);
6284 VALUE match_data = rb_backref_set_string(str, pos, RSTRING_LEN(pat));
6286 *match = match_data;
6296 return rb_reg_search0(pat, str, pos, 0, set_backref_str, match);
6303 return rb_pat_search0(pat, str, pos, set_backref_str, NULL);
6321rb_str_sub_bang(
int argc,
VALUE *argv,
VALUE str)
6336 hash = rb_check_hash_type(repl);
6343 pat = get_pat_quoted(argv[0], 1);
6345 str_modifiable(str);
6346 beg = rb_pat_search(pat, str, 0, 1);
6358 end0 = beg0 + RSTRING_LEN(pat);
6362 beg0 = RMATCH_BEG(match, 0);
6363 end0 = RMATCH_END(match, 0);
6367 if (iter || !
NIL_P(hash)) {
6368 p = RSTRING_PTR(str);
len = RSTRING_LEN(str);
6374 repl = rb_hash_aref(hash,
rb_str_subseq(str, beg0, end0 - beg0));
6377 str_mod_check(str, p,
len);
6378 rb_check_frozen(str);
6381 repl = rb_reg_regsub_match(repl, str, match);
6384 enc = rb_enc_compatible(str, repl);
6387 p = RSTRING_PTR(str);
len = RSTRING_LEN(str);
6391 rb_enc_inspect_name(str_enc),
6392 rb_enc_inspect_name(STR_ENC_GET(repl)));
6394 enc = STR_ENC_GET(repl);
6397 rb_enc_associate(str, enc);
6407 rlen = RSTRING_LEN(repl);
6408 len = RSTRING_LEN(str);
6410 RESIZE_CAPA(str,
len + rlen - plen);
6412 p = RSTRING_PTR(str);
6414 memmove(p + beg0 + rlen, p + beg0 + plen,
len - beg0 - plen);
6416 rp = RSTRING_PTR(repl);
6417 memmove(p + beg0, rp, rlen);
6419 STR_SET_LEN(str,
len);
6420 TERM_FILL(&RSTRING_PTR(str)[
len], TERM_LEN(str));
6443 rb_str_sub_bang(argc, argv, str);
6448str_gsub(
int argc,
VALUE *argv,
VALUE str,
int bang)
6453 enum {STR, ITER, FAST_MAP, MAP} mode = STR;
6455 int need_backref_str = -1;
6466 hash = rb_check_hash_type(repl);
6470 else if (rb_hash_default_unredefined(hash) && !
FL_TEST_RAW(hash, RHASH_PROC_DEFAULT)) {
6479 rb_error_arity(argc, 1, 2);
6482 pat = get_pat_quoted(argv[0], 1);
6483 beg = rb_pat_search0(pat, str, 0, need_backref_str, &match);
6486 if (bang)
return Qnil;
6489 if (bang) str_modify_keep_cr(str);
6492 blen = RSTRING_LEN(str) + 30;
6494 sp = RSTRING_PTR(str);
6495 slen = RSTRING_LEN(str);
6497 str_enc = STR_ENC_GET(str);
6498 rb_enc_associate(dest, str_enc);
6504 end0 = beg0 + RSTRING_LEN(pat);
6508 beg0 = RMATCH_BEG(match, 0);
6509 end0 = RMATCH_END(match, 0);
6518 struct RString fake_str = {RBASIC_INIT};
6520 if (mode == FAST_MAP) {
6529 val = rb_hash_aref(hash, key);
6532 str_mod_check(str, sp, slen);
6537 else if (need_backref_str) {
6538 val = rb_reg_regsub_match(repl, str, match);
6539 if (need_backref_str < 0) {
6540 need_backref_str = val != repl;
6547 len = beg0 - offset;
6561 if (RSTRING_LEN(str) <= end0)
break;
6562 len = rb_enc_fast_mbclen(RSTRING_PTR(str)+end0,
RSTRING_END(str), str_enc);
6564 offset = end0 +
len;
6566 cp = RSTRING_PTR(str) + offset;
6567 if (offset > RSTRING_LEN(str))
break;
6570 if (mode != FAST_MAP && mode != STR) {
6573 beg = rb_pat_search0(pat, str, offset, need_backref_str, &match);
6578 if (RSTRING_LEN(str) > offset) {
6581 rb_pat_search0(pat, str, last, 1, &match);
6583 str_shared_replace(str, dest);
6608rb_str_gsub_bang(
int argc,
VALUE *argv,
VALUE str)
6610 str_modifiable(str);
6611 return str_gsub(argc, argv, str, 1);
6661 return str_gsub(argc, argv, str, 0);
6681 str_modifiable(str);
6682 if (str == str2)
return str;
6686 return str_replace(str, str2);
6703rb_str_clear(
VALUE str)
6707 STR_SET_LEN(str, 0);
6708 RSTRING_PTR(str)[0] = 0;
6709 if (rb_enc_asciicompat(STR_ENC_GET(str)))
6725rb_str_chr(
VALUE str)
6743 pos += RSTRING_LEN(str);
6744 if (pos < 0 || RSTRING_LEN(str) <= pos)
6747 return INT2FIX((
unsigned char)RSTRING_PTR(str)[pos]);
6767 char *
ptr, *head, *left = 0;
6773 char byte = (char)(
NUM2INT(w) & 0xFF);
6776 if (pos < -
len ||
len <= pos)
6781 if (!str_independent(str))
6782 str_make_independent(str);
6783 enc = STR_ENC_GET(str);
6784 head = RSTRING_PTR(str);
6786 if (!STR_EMBED_P(str)) {
6793 nlen = rb_enc_precise_mbclen(left, head+
len, enc);
6801 width = rb_enc_precise_mbclen(left, head+
len, enc);
6803 nlen = rb_enc_precise_mbclen(left, head+
len, enc);
6819str_bit_offset_out_of_range(
rb_len_t byte_len, uint64_t bit_offset)
6822 return bit_offset / CHAR_BIT >= (uint64_t)byte_len;
6838str_bit_offset_from_index(
VALUE index)
6851 offset.index_value =
FIX2LONG(integer);
6852 if (offset.index_value < 0) {
6855 offset.value = (uint64_t)offset.index_value;
6856 offset.fits_index =
true;
6861 if (rb_int_negative_p(integer)) {
6864 if (rb_cmpint(rb_int_cmp(integer,
ULL2NUM(UINT64_MAX)), integer,
ULL2NUM(UINT64_MAX)) > 0) {
6865 rb_raise(rb_eArgError,
"bit index out of representable range");
6868 offset.value = (uint64_t)
NUM2ULL(integer);
6870 offset.index_value = (
rb_len_t)offset.value;
6871 offset.fits_index =
true;
6874 offset.index_value = 0;
6875 offset.fits_index =
false;
6885str_bit_length_from_index(
VALUE index)
6892 rb_raise(rb_eArgError,
"negative bit length");
6894 return (uint64_t)value;
6898 if (rb_int_negative_p(integer)) {
6899 rb_raise(rb_eArgError,
"negative bit length");
6901 if (rb_cmpint(rb_int_cmp(integer,
ULL2NUM(UINT64_MAX)), integer,
ULL2NUM(UINT64_MAX)) > 0) {
6902 rb_raise(rb_eArgError,
"bit length out of representable range");
6904 return (uint64_t)
NUM2ULL(integer);
6907static inline uint64_t
6914 if ((uint64_t)byte_len > UINT64_MAX / CHAR_BIT)
return UINT64_MAX;
6915 return (uint64_t)byte_len * CHAR_BIT;
6920 uint64_t end_exclusive;
6943 out->beg =
NIL_P(beg_v) ? 0 : str_bit_offset_from_index(beg_v).value;
6945 out->end_open =
true;
6946 out->end_exclusive = 0;
6949 uint64_t end = str_bit_offset_from_index(end_v).value;
6950 out->end_open =
false;
6955 out->end_exclusive = (excl || end == UINT64_MAX) ? end : end + 1;
6965str_bit_range_resolve(
const struct str_bit_range *range, uint64_t total_bits, uint64_t *begp, uint64_t *lenp)
6967 uint64_t beg = range->beg;
6968 if (beg > total_bits)
return false;
6970 uint64_t end_exclusive = range->end_open ? total_bits : range->end_exclusive;
6971 if (end_exclusive < beg) end_exclusive = beg;
6974 *lenp = end_exclusive - beg;
6979str_lsb_first_from_opts(
VALUE opts)
6981 static ID keywords[1];
6989 if (vlsb_first ==
Qundef || vlsb_first ==
Qtrue) {
6992 if (vlsb_first ==
Qfalse) {
6995 rb_raise(rb_eArgError,
"lsb_first must be true or false");
7000str_lsb_first(
int argc,
VALUE *argv,
VALUE *index)
7005 return str_lsb_first_from_opts(opts);
7008static inline uint64_t
7009str_logical_to_physical_bit64(uint64_t logical,
bool lsb_first)
7011 return lsb_first ? logical : ((logical & ~(uint64_t)7) | (7 - (logical & 7)));
7015str_logical_to_physical_bit(
rb_len_t logical,
bool lsb_first)
7017 return lsb_first ? logical : ((logical & ~7L) | (7 - (logical & 7L)));
7022 unsigned int bit_offset;
7026str_bit_location_from_offset(uint64_t logical, bool lsb_first)
7032 uint64_t physical = str_logical_to_physical_bit64(logical, lsb_first);
7034 location.byte_index = (
rb_len_t)(physical / CHAR_BIT);
7035 location.bit_offset = (
unsigned int)(physical % CHAR_BIT);
7040str_get_bit(
const char *ptr,
rb_len_t bit_index)
7042 return (((
unsigned char)ptr[bit_index / CHAR_BIT]) >> (bit_index % CHAR_BIT)) & 1;
7048 return (((
unsigned char)ptr[location.byte_index]) >> location.bit_offset) & 1;
7055 bool lsb_first = str_lsb_first(argc, argv, &index);
7058 if (str_bit_offset_out_of_range(RSTRING_LEN(str), offset.value)) {
7062 if (offset.fits_index) {
7063 return str_get_bit(RSTRING_PTR(str), str_logical_to_physical_bit(offset.index_value, lsb_first));
7066 return str_get_bit_location(RSTRING_PTR(str), str_bit_location_from_offset(offset.value, lsb_first));
7078rb_str_bit_get(
int argc,
VALUE *argv,
VALUE str)
7080 int bit = str_bit_get(argc, argv, str);
7092rb_str_bit_set_p(
int argc,
VALUE *argv,
VALUE str)
7094 int bit = str_bit_get(argc, argv, str);
7095 return bit < 0 ?
Qnil : RBOOL(bit);
7098enum str_bit_mutation {
7109static inline unsigned char
7110str_bit_region_byte_mask(
unsigned int lo,
unsigned int hi,
bool lsb_first)
7113 return (
unsigned char)((0xFFu >> (7 - hi)) & (0xFFu << lo));
7116 return (
unsigned char)((0xFFu >> lo) & (0xFFu << (7 - hi)));
7121str_apply_bit_mask(
unsigned char *
byte,
unsigned char mask,
enum str_bit_mutation mutation)
7128 *
byte &= (
unsigned char)~mask;
7138str_mutate_bit_region(
unsigned char *ptr, uint64_t beg, uint64_t
len,
bool lsb_first,
enum str_bit_mutation mutation)
7140 uint64_t first_bit = beg;
7141 uint64_t last_bit = beg +
len - 1;
7144 unsigned int first_off = (
unsigned int)(first_bit % CHAR_BIT);
7145 unsigned int last_off = (
unsigned int)(last_bit % CHAR_BIT);
7147 if (first_byte == last_byte) {
7148 str_apply_bit_mask(ptr + first_byte, str_bit_region_byte_mask(first_off, last_off, lsb_first), mutation);
7152 str_apply_bit_mask(ptr + first_byte, str_bit_region_byte_mask(first_off, 7, lsb_first), mutation);
7153 rb_len_t middle_len = last_byte - first_byte - 1;
7154 if (middle_len > 0) {
7155 unsigned char *middle = ptr + first_byte + 1;
7158 memset(middle, 0xFF, middle_len);
7161 memset(middle, 0, middle_len);
7169 for (
rb_len_t i = 0; i < middle_len; i++) {
7175 str_apply_bit_mask(ptr + last_byte, str_bit_region_byte_mask(0, last_off, lsb_first), mutation);
7179str_mutate_single_bit(
VALUE str,
VALUE index,
bool lsb_first,
enum str_bit_mutation mutation)
7187 rb_check_frozen(str);
7189 if (str_bit_offset_out_of_range(RSTRING_LEN(str), offset.value)) {
7194 ptr = (
unsigned char *)RSTRING_PTR(str);
7195 if (offset.fits_index) {
7196 bit_index = str_logical_to_physical_bit(offset.index_value, lsb_first);
7197 mask = (
unsigned char)(1u << (bit_index % CHAR_BIT));
7198 location.byte_index = bit_index / CHAR_BIT;
7201 location = str_bit_location_from_offset(offset.value, lsb_first);
7202 mask = (
unsigned char)(1u << location.bit_offset);
7205 str_apply_bit_mask(ptr + location.byte_index, mask, mutation);
7210str_mutate_bit(
int argc,
VALUE *argv,
VALUE str,
enum str_bit_mutation mutation)
7212 VALUE target, length_v, opts;
7213 uint64_t beg = 0,
len = 0;
7216 int nargs =
rb_scan_args(argc, argv,
"11:", &target, &length_v, &opts);
7217 bool lsb_first = str_lsb_first_from_opts(opts);
7220 if (nargs == 1 && !is_range) {
7221 return str_mutate_single_bit(str, target, lsb_first, mutation);
7228 rb_raise(rb_eArgError,
"bit length not allowed with a Range");
7230 str_bit_range_to_offsets(target, &range);
7233 offset = str_bit_offset_from_index(target);
7234 len = str_bit_length_from_index(length_v);
7238 rb_check_frozen(str);
7246 uint64_t total_bits = str_bit_size(RSTRING_LEN(str));
7248 if (!str_bit_range_resolve(&range, total_bits, &beg, &
len) ||
len > total_bits - beg) {
7254 if (beg > total_bits ||
len > total_bits - beg) {
7259 if (
len == 0)
return str;
7262 str_mutate_bit_region((
unsigned char *)RSTRING_PTR(str), beg,
len, lsb_first, mutation);
7276rb_str_bit_set(
int argc,
VALUE *argv,
VALUE str)
7278 return str_mutate_bit(argc, argv, str, STR_BIT_SET);
7291rb_str_bit_clear(
int argc,
VALUE *argv,
VALUE str)
7293 return str_mutate_bit(argc, argv, str, STR_BIT_CLEAR);
7306rb_str_bit_flip(
int argc,
VALUE *argv,
VALUE str)
7308 return str_mutate_bit(argc, argv, str, STR_BIT_FLIP);
7312str_count_bits(
const unsigned char *ptr,
rb_len_t len)
7320 for (;
off < unrolled_end;
off += 32) {
7321 uint64_t w0, w1, w2, w3;
7322 memcpy(&w0, ptr +
off, 8);
7323 memcpy(&w1, ptr +
off + 8, 8);
7324 memcpy(&w2, ptr +
off + 16, 8);
7325 memcpy(&w3, ptr +
off + 24, 8);
7326 count += rb_popcount64(w0);
7327 count += rb_popcount64(w1);
7328 count += rb_popcount64(w2);
7329 count += rb_popcount64(w3);
7333 for (;
off < aligned_end;
off += 8) {
7335 memcpy(&word, ptr +
off, 8);
7336 count += rb_popcount64(word);
7343 for (;
off <
len;
off++, shift += CHAR_BIT) {
7344 word |= (uint64_t)ptr[
off] << shift;
7346 count += rb_popcount64(word);
7353str_count_bits_region(
const unsigned char *ptr, uint64_t beg, uint64_t
len,
bool lsb_first)
7355 uint64_t first_bit = beg;
7356 uint64_t last_bit = beg +
len - 1;
7359 unsigned int first_off = (
unsigned int)(first_bit % CHAR_BIT);
7360 unsigned int last_off = (
unsigned int)(last_bit % CHAR_BIT);
7362 if (first_byte == last_byte) {
7363 return rb_popcount32((uint32_t)(ptr[first_byte] & str_bit_region_byte_mask(first_off, last_off, lsb_first)));
7366 uint64_t count = rb_popcount32((uint32_t)(ptr[first_byte] & str_bit_region_byte_mask(first_off, 7, lsb_first)));
7367 count += str_count_bits(ptr + first_byte + 1, last_byte - first_byte - 1);
7368 count += rb_popcount32((uint32_t)(ptr[last_byte] & str_bit_region_byte_mask(0, last_off, lsb_first)));
7382rb_str_bit_count(
int argc,
VALUE *argv,
VALUE str)
7385 uint64_t beg = 0,
len = 0;
7388 int nargs =
rb_scan_args(argc, argv,
"02:", &v0, &v1, &opts);
7393 bool lsb_first = str_lsb_first_from_opts(opts);
7396 return ULL2NUM(str_count_bits((
const unsigned char *)RSTRING_PTR(str), RSTRING_LEN(str)));
7403 rb_raise(rb_eArgError,
"bit length not allowed with a Range");
7405 str_bit_range_to_offsets(v0, &range);
7407 else if (nargs == 1) {
7408 rb_raise(rb_eArgError,
"no bit length given");
7411 beg = str_bit_offset_from_index(v0).value;
7412 len = str_bit_length_from_index(v1);
7415 const unsigned char *ptr = (
const unsigned char *)RSTRING_PTR(str);
7416 uint64_t total_bits = str_bit_size(RSTRING_LEN(str));
7418 if (!str_bit_range_resolve(&range, total_bits, &beg, &
len)) {
7422 else if (beg >= total_bits) {
7427 if (
len > total_bits - beg)
len = total_bits - beg;
7429 return ULL2NUM(str_count_bits_region(ptr, beg,
len, lsb_first));
7433str_check_bitwise_length(
VALUE str,
VALUE other)
7435 if (RSTRING_LEN(str) != RSTRING_LEN(other)) {
7436 rb_raise(rb_eArgError,
"operands must have the same length (%"PRIdLEN
" vs %"PRIdLEN
")",
7437 RSTRING_LEN(str), RSTRING_LEN(other));
7442str_bitwise_result(
VALUE str)
7446 rb_str_resize(result,
len);
7447 rb_enc_associate(result, rb_ascii8bit_encoding());
7452#define STR_DEFINE_UNARY_BITWISE_KERNEL(name, expr_word, expr_byte) \
7454 name(unsigned char *dst, const unsigned char *src, rb_len_t len) \
7457 rb_len_t unrolled_end = len & ~31L; \
7458 rb_len_t aligned_end = len & ~7L; \
7459 for (; off < unrolled_end; off += 32) { \
7460 uint64_t s0, s1, s2, s3; \
7461 memcpy(&s0, src + off, 8); \
7462 memcpy(&s1, src + off + 8, 8); \
7463 memcpy(&s2, src + off + 16, 8); \
7464 memcpy(&s3, src + off + 24, 8); \
7465 s0 = (expr_word(s0)); \
7466 s1 = (expr_word(s1)); \
7467 s2 = (expr_word(s2)); \
7468 s3 = (expr_word(s3)); \
7469 memcpy(dst + off, &s0, 8); \
7470 memcpy(dst + off + 8, &s1, 8); \
7471 memcpy(dst + off + 16, &s2, 8); \
7472 memcpy(dst + off + 24, &s3, 8); \
7474 for (; off < aligned_end; off += 8) { \
7476 memcpy(&word, src + off, 8); \
7477 word = (expr_word(word)); \
7478 memcpy(dst + off, &word, 8); \
7480 for (; off < len; off++) dst[off] = (expr_byte(src[off])); \
7483#define STR_DEFINE_BINARY_BITWISE_KERNEL(name, expr_word, expr_byte) \
7485 name(unsigned char *dst, const unsigned char *lhs, \
7486 const unsigned char *rhs, rb_len_t len) \
7489 rb_len_t unrolled_end = len & ~31L; \
7490 rb_len_t aligned_end = len & ~7L; \
7491 for (; off < unrolled_end; off += 32) { \
7492 uint64_t l0, l1, l2, l3, r0, r1, r2, r3; \
7493 memcpy(&l0, lhs + off, 8); memcpy(&r0, rhs + off, 8); \
7494 memcpy(&l1, lhs + off + 8, 8); memcpy(&r1, rhs + off + 8, 8); \
7495 memcpy(&l2, lhs + off + 16, 8); memcpy(&r2, rhs + off + 16, 8); \
7496 memcpy(&l3, lhs + off + 24, 8); memcpy(&r3, rhs + off + 24, 8); \
7497 l0 = expr_word(l0, r0); \
7498 l1 = expr_word(l1, r1); \
7499 l2 = expr_word(l2, r2); \
7500 l3 = expr_word(l3, r3); \
7501 memcpy(dst + off, &l0, 8); \
7502 memcpy(dst + off + 8, &l1, 8); \
7503 memcpy(dst + off + 16, &l2, 8); \
7504 memcpy(dst + off + 24, &l3, 8); \
7506 for (; off < aligned_end; off += 8) { \
7507 uint64_t lhs_word, rhs_word; \
7508 memcpy(&lhs_word, lhs + off, 8); \
7509 memcpy(&rhs_word, rhs + off, 8); \
7510 lhs_word = expr_word(lhs_word, rhs_word); \
7511 memcpy(dst + off, &lhs_word, 8); \
7513 for (; off < len; off++) dst[off] = expr_byte(lhs[off], rhs[off]); \
7516#define STR_BITWISE_NOT_WORD(x) (~(x))
7517#define STR_BITWISE_NOT_BYTE(x) ((unsigned char)~(x))
7518#define STR_BITWISE_AND_WORD(x, y) ((x) & (y))
7519#define STR_BITWISE_AND_BYTE(x, y) ((unsigned char)((x) & (y)))
7520#define STR_BITWISE_OR_WORD(x, y) ((x) | (y))
7521#define STR_BITWISE_OR_BYTE(x, y) ((unsigned char)((x) | (y)))
7522#define STR_BITWISE_XOR_WORD(x, y) ((x) ^ (y))
7523#define STR_BITWISE_XOR_BYTE(x, y) ((unsigned char)((x) ^ (y)))
7525STR_DEFINE_UNARY_BITWISE_KERNEL(str_bitwise_not, STR_BITWISE_NOT_WORD, STR_BITWISE_NOT_BYTE)
7526STR_DEFINE_BINARY_BITWISE_KERNEL(str_bitwise_and, STR_BITWISE_AND_WORD, STR_BITWISE_AND_BYTE)
7527STR_DEFINE_BINARY_BITWISE_KERNEL(str_bitwise_or, STR_BITWISE_OR_WORD, STR_BITWISE_OR_BYTE)
7528STR_DEFINE_BINARY_BITWISE_KERNEL(str_bitwise_xor, STR_BITWISE_XOR_WORD, STR_BITWISE_XOR_BYTE)
7538rb_str_bitwise_not(
VALUE str)
7541 VALUE result = str_bitwise_result(str);
7542 str_bitwise_not((
unsigned char *)RSTRING_PTR(result),
7543 (
const unsigned char *)RSTRING_PTR(str),
len);
7555rb_str_bitwise_not_bang(
VALUE str)
7561 len = RSTRING_LEN(str);
7562 ptr = (
unsigned char *)RSTRING_PTR(str);
7563 str_bitwise_not(ptr, ptr,
len);
7567#define STR_DEFINE_BINARY_BITWISE_METHOD(name) \
7569 rb_str_bitwise_##name(VALUE str, VALUE other) \
7573 StringValue(other); \
7574 str_check_bitwise_length(str, other); \
7575 len = RSTRING_LEN(str); \
7576 result = str_bitwise_result(str); \
7577 str_bitwise_##name((unsigned char *)RSTRING_PTR(result), \
7578 (const unsigned char *)RSTRING_PTR(str), \
7579 (const unsigned char *)RSTRING_PTR(other), len); \
7583 rb_str_bitwise_##name##_bang(VALUE str, VALUE other) \
7586 unsigned char *ptr; \
7587 StringValue(other); \
7588 str_check_bitwise_length(str, other); \
7589 rb_str_modify(str); \
7590 len = RSTRING_LEN(str); \
7591 ptr = (unsigned char *)RSTRING_PTR(str); \
7592 str_bitwise_##name(ptr, ptr, \
7593 (const unsigned char *)RSTRING_PTR(other), len); \
7597STR_DEFINE_BINARY_BITWISE_METHOD(and)
7598STR_DEFINE_BINARY_BITWISE_METHOD(or)
7599STR_DEFINE_BINARY_BITWISE_METHOD(xor)
7606 if (beg > n ||
len < 0)
return Qnil;
7609 if (beg < 0)
return Qnil;
7614 if (!empty)
return Qnil;
7618 VALUE str2 = str_subseq(str, beg,
len);
7620 str_enc_copy_direct(str2, str);
7622 if (RSTRING_LEN(str2) == 0) {
7623 if (!rb_enc_asciicompat(STR_ENC_GET(str)))
7665 return str_byte_substr(str, beg,
len, TRUE);
7670 return str_byte_substr(str, idx, 1, FALSE);
7682rb_str_byteslice(
int argc,
VALUE *argv,
VALUE str)
7687 return str_byte_substr(str, beg,
len, TRUE);
7690 return str_byte_aref(str, argv[0]);
7696 rb_len_t end, slen = RSTRING_LEN(str);
7699 if ((slen < *beg) || ((*beg < 0) && (*beg + slen < 0))) {
7700 rb_raise(
rb_eIndexError,
"index %"PRIdLEN
" out of string", *beg);
7708 if (*
len > slen - *beg) {
7712 str_ensure_byte_pos(str, *beg);
7713 str_ensure_byte_pos(str, end);
7727rb_str_bytesplice(
int argc,
VALUE *argv,
VALUE str)
7734 if (!(argc == 2 || argc == 3 || argc == 5)) {
7735 rb_raise(rb_eArgError,
"wrong number of arguments (given %d, expected 2, 3, or 5)", argc);
7739 rb_raise(
rb_eTypeError,
"wrong argument type %s (expected Range)",
7740 rb_builtin_class_name(argv[0]));
7747 vlen = RSTRING_LEN(val);
7752 rb_raise(
rb_eTypeError,
"wrong argument type %s (expected Range)",
7753 rb_builtin_class_name(argv[2]));
7765 vlen = RSTRING_LEN(val);
7773 str_check_beg_len(str, &beg, &
len);
7774 str_check_beg_len(val, &vbeg, &vlen);
7775 str_modify_keep_cr(str);
7778 rb_enc_associate(str, rb_enc_check(str, val));
7781 rb_str_update_1(str, beg,
len, val, vbeg, vlen);
7803rb_str_reverse(
VALUE str)
7810 if (RSTRING_LEN(str) <= 1)
return str_duplicate(
rb_cString, str);
7811 enc = STR_ENC_GET(str);
7817 if (RSTRING_LEN(str) > 1) {
7818 if (single_byte_optimizable(str)) {
7825 int clen = rb_enc_fast_mbclen(s, e, enc);
7833 cr = rb_enc_asciicompat(enc) ?
7836 int clen = rb_enc_mbclen(s, e, enc);
7845 STR_SET_LEN(rev, RSTRING_LEN(str));
7846 str_enc_copy_direct(rev, str);
7868rb_str_reverse_bang(
VALUE str)
7870 if (RSTRING_LEN(str) > 1) {
7871 if (single_byte_optimizable(str)) {
7874 str_modify_keep_cr(str);
7875 s = RSTRING_PTR(str);
7884 str_shared_replace(str, rb_str_reverse(str));
7888 str_modify_keep_cr(str);
7917 i = rb_str_index(str, arg, 0);
7919 return RBOOL(i != -1);
7963 rb_raise(rb_eArgError,
"invalid radix %d", base);
7965 return rb_str_to_inum(str, base, FALSE);
7990rb_str_to_f(
VALUE str)
8007rb_str_to_s(
VALUE str)
8019 char s[RUBY_MAX_CHAR_LEN];
8020 int n = rb_enc_codelen(c, enc);
8022 rb_enc_mbcput(c, s, enc);
8027#define CHAR_ESC_LEN 13
8030rb_str_buf_cat_escaped_char(
VALUE result,
unsigned int c,
int unicode_p)
8032 char buf[CHAR_ESC_LEN + 1];
8040 snprintf(buf, CHAR_ESC_LEN,
"%c", c);
8042 else if (c < 0x10000) {
8043 snprintf(buf, CHAR_ESC_LEN,
"\\u%04X", c);
8046 snprintf(buf, CHAR_ESC_LEN,
"\\u{%X}", c);
8051 snprintf(buf, CHAR_ESC_LEN,
"\\x%02X", c);
8054 snprintf(buf, CHAR_ESC_LEN,
"\\x{%X}", c);
8057 l = (int)strlen(buf);
8063ruby_escaped_char(
int c)
8066 case '\0':
return "\\0";
8067 case '\n':
return "\\n";
8068 case '\r':
return "\\r";
8069 case '\t':
return "\\t";
8070 case '\f':
return "\\f";
8071 case '\013':
return "\\v";
8072 case '\010':
return "\\b";
8073 case '\007':
return "\\a";
8074 case '\033':
return "\\e";
8075 case '\x7f':
return "\\c?";
8081rb_str_escape(
VALUE str)
8085 const char *p = RSTRING_PTR(str);
8087 const char *prev = p;
8088 char buf[CHAR_ESC_LEN + 1];
8090 int unicode_p = rb_enc_unicode_p(enc);
8091 int asciicompat = rb_enc_asciicompat(enc);
8096 int n = rb_enc_precise_mbclen(p, pend, enc);
8098 if (p > prev) str_buf_cat(result, prev, p - prev);
8099 n = rb_enc_mbminlen(enc);
8101 n = (int)(pend - p);
8103 snprintf(buf, CHAR_ESC_LEN,
"\\x%02X", *p & 0377);
8104 str_buf_cat(result, buf, strlen(buf));
8110 c = rb_enc_mbc_to_codepoint(p, pend, enc);
8112 cc = ruby_escaped_char(c);
8114 if (p - n > prev) str_buf_cat(result, prev, p - n - prev);
8115 str_buf_cat(result, cc, strlen(cc));
8118 else if (asciicompat && rb_enc_isascii(c, enc) &&
ISPRINT(c)) {
8121 if (p - n > prev) str_buf_cat(result, prev, p - n - prev);
8122 rb_str_buf_cat_escaped_char(result, c, unicode_p);
8126 if (p > prev) str_buf_cat(result, prev, p - prev);
8136static const bool inspect_no_escape[256] = {
8137 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8138 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8139 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
8140 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
8141 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
8142 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1,
8143 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
8144 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,
8160 const char *p, *pend, *prev;
8161 char buf[CHAR_ESC_LEN + 1];
8163 rb_encoding *resenc = rb_default_internal_encoding();
8164 int unicode_p = rb_enc_unicode_p(enc);
8165 int asciicompat = rb_enc_asciicompat(enc);
8166 int cr = rb_enc_str_coderange(str);
8168 if (resenc == NULL) resenc = rb_default_external_encoding();
8169 if (!rb_enc_asciicompat(resenc)) resenc = rb_usascii_encoding();
8170 rb_enc_associate(result, resenc);
8171 str_buf_cat2(result,
"\"");
8184 while (p < pend && inspect_no_escape[(
unsigned char)*p]) p++;
8185 if (p >= pend)
break;
8188 n = rb_enc_precise_mbclen(p, pend, enc);
8190 if (p > prev) str_buf_cat(result, prev, p - prev);
8191 n = rb_enc_mbminlen(enc);
8193 n = (int)(pend - p);
8195 snprintf(buf, CHAR_ESC_LEN,
"\\x%02X", *p & 0377);
8196 str_buf_cat(result, buf, strlen(buf));
8202 c = rb_enc_mbc_to_codepoint(p, pend, enc);
8204 if ((asciicompat || unicode_p) &&
8205 (c ==
'"'|| c ==
'\\' ||
8210 (cc ==
'$' || cc ==
'@' || cc ==
'{'))))) {
8211 if (p - n > prev) str_buf_cat(result, prev, p - n - prev);
8212 str_buf_cat2(result,
"\\");
8213 if (asciicompat || enc == resenc) {
8219 case '\n': cc =
'n';
break;
8220 case '\r': cc =
'r';
break;
8221 case '\t': cc =
't';
break;
8222 case '\f': cc =
'f';
break;
8223 case '\013': cc =
'v';
break;
8224 case '\010': cc =
'b';
break;
8225 case '\007': cc =
'a';
break;
8226 case 033: cc =
'e';
break;
8227 default: cc = 0;
break;
8230 if (p - n > prev) str_buf_cat(result, prev, p - n - prev);
8233 str_buf_cat(result, buf, 2);
8246 (asciicompat && rb_enc_isascii(c, enc) &&
ISPRINT(c))) {
8250 if (p - n > prev) str_buf_cat(result, prev, p - n - prev);
8251 rb_str_buf_cat_escaped_char(result, c, unicode_p);
8256 if (p > prev) str_buf_cat(result, prev, p - prev);
8257 str_buf_cat2(result,
"\"");
8262#define IS_EVSTR(p,e) ((p) < (e) && (*(p) == '$' || *(p) == '@' || *(p) == '{'))
8275 int encidx = rb_enc_get_index(str);
8278 const char *p, *pend;
8281 int u8 = (encidx == rb_utf8_encindex());
8282 static const char nonascii_suffix[] =
".dup.force_encoding(\"%s\")";
8285 if (!rb_enc_asciicompat(enc)) {
8287 len += strlen(enc->name);
8290 p = RSTRING_PTR(str); pend = p + RSTRING_LEN(str);
8293 unsigned char c = *p++;
8296 case '"':
case '\\':
8297 case '\n':
case '\r':
8298 case '\t':
case '\f':
8299 case '\013':
case '\010':
case '\007':
case '\033':
8304 clen = IS_EVSTR(p, pend) ? 2 : 1;
8312 if (u8 && c > 0x7F) {
8313 int n = rb_enc_precise_mbclen(p-1, pend, enc);
8315 unsigned int cc = rb_enc_mbc_to_codepoint(p-1, pend, enc);
8318 else if (cc <= 0xFFFFF)
8338 p = RSTRING_PTR(str); pend = p + RSTRING_LEN(str);
8339 q = RSTRING_PTR(result); qend = q +
len + 1;
8343 unsigned char c = *p++;
8345 if (c ==
'"' || c ==
'\\') {
8349 else if (c ==
'#') {
8350 if (IS_EVSTR(p, pend)) *q++ =
'\\';
8353 else if (c ==
'\n') {
8357 else if (c ==
'\r') {
8361 else if (c ==
'\t') {
8365 else if (c ==
'\f') {
8369 else if (c ==
'\013') {
8373 else if (c ==
'\010') {
8377 else if (c ==
'\007') {
8381 else if (c ==
'\033') {
8391 int n = rb_enc_precise_mbclen(p-1, pend, enc) - 1;
8393 int cc = rb_enc_mbc_to_codepoint(p-1, pend, enc);
8396 snprintf(q, qend-q,
"u%04X", cc);
8398 snprintf(q, qend-q,
"u{%X}", cc);
8403 snprintf(q, qend-q,
"x%02X", c);
8409 if (!rb_enc_asciicompat(enc)) {
8410 snprintf(q, qend-q, nonascii_suffix, enc->name);
8411 encidx = rb_ascii8bit_encindex();
8414 rb_enc_associate_index(result, encidx);
8420unescape_ascii(
unsigned int c)
8444undump_after_backslash(
VALUE undumped,
const char **ss,
const char *s_end,
rb_encoding **penc,
bool *utf8,
bool *binary)
8446 const char *s = *ss;
8450 unsigned char buf[6];
8468 *buf = unescape_ascii(*s);
8480 if (enc_utf8 == NULL) enc_utf8 = rb_utf8_encoding();
8481 if (*penc != enc_utf8) {
8483 rb_enc_associate(undumped, enc_utf8);
8500 if (hexlen == 0 || hexlen > 6) {
8506 if (0xd800 <= c && c <= 0xdfff) {
8509 codelen = rb_enc_mbcput(c, (
char *)buf, *penc);
8519 if (0xd800 <= c && c <= 0xdfff) {
8522 codelen = rb_enc_mbcput(c, (
char *)buf, *penc);
8552static VALUE rb_str_is_ascii_only_p(
VALUE str);
8564str_undump(
VALUE str)
8566 const char *s = RSTRING_PTR(str);
8569 VALUE undumped = rb_enc_str_new(s, 0L, enc);
8571 bool binary =
false;
8575 if (rb_str_is_ascii_only_p(str) ==
Qfalse) {
8578 if (!str_null_check(str, &w)) {
8581 if (RSTRING_LEN(str) < 2)
goto invalid_format;
8582 if (*s !=
'"')
goto invalid_format;
8600 static const char force_encoding_suffix[] =
".force_encoding(\"";
8601 static const char dup_suffix[] =
".dup";
8602 const char *encname;
8607 size =
sizeof(dup_suffix) - 1;
8608 if (s_end - s > size && memcmp(s, dup_suffix, size) == 0) s += size;
8610 size =
sizeof(force_encoding_suffix) - 1;
8611 if (s_end - s <= size)
goto invalid_format;
8612 if (memcmp(s, force_encoding_suffix, size) != 0)
goto invalid_format;
8616 rb_raise(
rb_eRuntimeError,
"dumped string contained Unicode escape but used force_encoding");
8620 s = memchr(s,
'"', s_end-s);
8622 if (!s)
goto invalid_format;
8623 if (s_end - s != 2)
goto invalid_format;
8624 if (s[0] !=
'"' || s[1] !=
')')
goto invalid_format;
8626 encidx = rb_enc_find_index2(encname, (
rb_len_t)size);
8630 rb_enc_associate_index(undumped, encidx);
8640 undump_after_backslash(undumped, &s, s_end, &enc, &utf8, &binary);
8651 rb_raise(
rb_eRuntimeError,
"invalid dumped string; not wrapped with '\"' nor '\"...\".force_encoding(\"...\")' form");
8657 if (rb_enc_dummy_p(enc)) {
8664str_true_enc(
VALUE str)
8667 rb_str_check_dummy_enc(enc);
8671static OnigCaseFoldType
8672check_case_options(
int argc,
VALUE *argv, OnigCaseFoldType flags)
8677 rb_raise(rb_eArgError,
"too many options");
8678 if (argv[0]==sym_turkic) {
8679 flags |= ONIGENC_CASE_FOLD_TURKISH_AZERI;
8681 if (argv[1]==sym_lithuanian)
8682 flags |= ONIGENC_CASE_FOLD_LITHUANIAN;
8684 rb_raise(rb_eArgError,
"invalid second option");
8687 else if (argv[0]==sym_lithuanian) {
8688 flags |= ONIGENC_CASE_FOLD_LITHUANIAN;
8690 if (argv[1]==sym_turkic)
8691 flags |= ONIGENC_CASE_FOLD_TURKISH_AZERI;
8693 rb_raise(rb_eArgError,
"invalid second option");
8697 rb_raise(rb_eArgError,
"too many options");
8698 else if (argv[0]==sym_ascii)
8699 flags |= ONIGENC_CASE_ASCII_ONLY;
8700 else if (argv[0]==sym_fold) {
8701 if ((flags & (ONIGENC_CASE_UPCASE|ONIGENC_CASE_DOWNCASE)) == ONIGENC_CASE_DOWNCASE)
8702 flags ^= ONIGENC_CASE_FOLD|ONIGENC_CASE_DOWNCASE;
8704 rb_raise(rb_eArgError,
"option :fold only allowed for downcasing");
8707 rb_raise(rb_eArgError,
"invalid option");
8714 if ((flags & ONIGENC_CASE_ASCII_ONLY) && (enc==rb_utf8_encoding() ||
rb_enc_mbmaxlen(enc) == 1))
8716 return !(flags & ONIGENC_CASE_FOLD_TURKISH_AZERI) &&
8721#define CASE_MAPPING_ADDITIONAL_LENGTH 20
8722#ifndef CASEMAP_DEBUG
8723# define CASEMAP_DEBUG 0
8731 OnigUChar space[FLEX_ARY_LEN];
8735mapping_buffer_free(
void *p)
8739 while (current_buffer) {
8740 previous_buffer = current_buffer;
8741 current_buffer = current_buffer->next;
8742 ruby_xfree_sized(previous_buffer, offsetof(
mapping_buffer, space) + previous_buffer->capa);
8748 {0, mapping_buffer_free,},
8749 0, 0, RUBY_TYPED_THREAD_SAFE_FREE | RUBY_TYPED_WB_PROTECTED
8757 const OnigUChar *source_current, *source_end;
8758 int target_length = 0;
8759 VALUE buffer_anchor;
8762 size_t buffer_count = 0;
8763 int buffer_length_or_invalid;
8765 if (RSTRING_LEN(source) == 0)
return str_duplicate(
rb_cString, source);
8767 source_current = (OnigUChar*)RSTRING_PTR(source);
8772 while (source_current < source_end) {
8774 size_t capa = (size_t)(source_end-source_current)*++buffer_count + CASE_MAPPING_ADDITIONAL_LENGTH;
8775 if (CASEMAP_DEBUG) {
8776 fprintf(stderr,
"Buffer allocation, capa is %"PRIuSIZE
"\n",
capa);
8779 *pre_buffer = current_buffer;
8780 pre_buffer = ¤t_buffer->next;
8781 current_buffer->next = NULL;
8782 current_buffer->capa =
capa;
8783 buffer_length_or_invalid = enc->case_map(flags,
8784 &source_current, source_end,
8785 current_buffer->space,
8786 current_buffer->space+current_buffer->capa,
8788 if (buffer_length_or_invalid < 0) {
8789 current_buffer =
DATA_PTR(buffer_anchor);
8791 mapping_buffer_free(current_buffer);
8792 rb_raise(rb_eArgError,
"input string invalid");
8794 target_length += current_buffer->used = buffer_length_or_invalid;
8796 if (CASEMAP_DEBUG) {
8797 fprintf(stderr,
"Buffer count is %"PRIuSIZE
"\n", buffer_count);
8800 if (buffer_count==1) {
8801 target =
rb_str_new((
const char*)current_buffer->space, target_length);
8804 char *target_current;
8807 target_current = RSTRING_PTR(target);
8808 current_buffer =
DATA_PTR(buffer_anchor);
8809 while (current_buffer) {
8810 memcpy(target_current, current_buffer->space, current_buffer->used);
8811 target_current += current_buffer->used;
8812 current_buffer = current_buffer->next;
8815 current_buffer =
DATA_PTR(buffer_anchor);
8817 mapping_buffer_free(current_buffer);
8822 str_enc_copy_direct(target, source);
8831 const OnigUChar *source_current, *source_end;
8832 OnigUChar *target_current, *target_end;
8833 rb_len_t old_length = RSTRING_LEN(source);
8834 int length_or_invalid;
8836 if (old_length == 0)
return Qnil;
8838 source_current = (OnigUChar*)RSTRING_PTR(source);
8840 if (source == target) {
8841 target_current = (OnigUChar*)source_current;
8842 target_end = (OnigUChar*)source_end;
8845 target_current = (OnigUChar*)RSTRING_PTR(target);
8849 length_or_invalid = onigenc_ascii_only_case_map(flags,
8850 &source_current, source_end,
8851 target_current, target_end, enc);
8852 if (length_or_invalid < 0)
8853 rb_raise(rb_eArgError,
"input string invalid");
8854 if (CASEMAP_DEBUG && length_or_invalid != old_length) {
8855 fprintf(stderr,
"problem with rb_str_ascii_casemap"
8856 "; old_length=%"PRIdLEN
", new_length=%d\n", old_length, length_or_invalid);
8857 rb_raise(rb_eArgError,
"internal problem with rb_str_ascii_casemap"
8858 "; old_length=%"PRIdLEN
", new_length=%d\n", old_length, length_or_invalid);
8861 str_enc_copy(target, source);
8867upcase_single(
VALUE str)
8869 char *s = RSTRING_PTR(str), *send =
RSTRING_END(str);
8870 bool modified =
false;
8873 unsigned int c = *(
unsigned char*)s;
8875 if (
'a' <= c && c <=
'z') {
8876 *s =
'A' + (c -
'a');
8897rb_str_upcase_bang(
int argc,
VALUE *argv,
VALUE str)
8900 OnigCaseFoldType flags = ONIGENC_CASE_UPCASE;
8902 flags = check_case_options(argc, argv, flags);
8903 str_modify_keep_cr(str);
8904 enc = str_true_enc(str);
8905 if (case_option_single_p(flags, enc, str)) {
8906 if (upcase_single(str))
8907 flags |= ONIGENC_CASE_MODIFIED;
8909 else if (flags&ONIGENC_CASE_ASCII_ONLY)
8910 rb_str_ascii_casemap(str, str, &flags, enc);
8912 str_shared_replace(str, rb_str_casemap(str, &flags, enc));
8914 if (ONIGENC_CASE_MODIFIED&flags)
return str;
8927rb_str_upcase(
int argc,
VALUE *argv,
VALUE str)
8930 OnigCaseFoldType flags = ONIGENC_CASE_UPCASE;
8933 flags = check_case_options(argc, argv, flags);
8934 enc = str_true_enc(str);
8935 if (case_option_single_p(flags, enc, str)) {
8936 ret =
rb_str_new(RSTRING_PTR(str), RSTRING_LEN(str));
8937 str_enc_copy_direct(ret, str);
8940 else if (flags&ONIGENC_CASE_ASCII_ONLY) {
8942 rb_str_ascii_casemap(str, ret, &flags, enc);
8945 ret = rb_str_casemap(str, &flags, enc);
8952downcase_single(
VALUE str)
8954 char *s = RSTRING_PTR(str), *send =
RSTRING_END(str);
8955 bool modified =
false;
8958 unsigned int c = *(
unsigned char*)s;
8960 if (
'A' <= c && c <=
'Z') {
8961 *s =
'a' + (c -
'A');
8983rb_str_downcase_bang(
int argc,
VALUE *argv,
VALUE str)
8986 OnigCaseFoldType flags = ONIGENC_CASE_DOWNCASE;
8988 flags = check_case_options(argc, argv, flags);
8989 str_modify_keep_cr(str);
8990 enc = str_true_enc(str);
8991 if (case_option_single_p(flags, enc, str)) {
8992 if (downcase_single(str))
8993 flags |= ONIGENC_CASE_MODIFIED;
8995 else if (flags&ONIGENC_CASE_ASCII_ONLY)
8996 rb_str_ascii_casemap(str, str, &flags, enc);
8998 str_shared_replace(str, rb_str_casemap(str, &flags, enc));
9000 if (ONIGENC_CASE_MODIFIED&flags)
return str;
9014rb_str_downcase(
int argc,
VALUE *argv,
VALUE str)
9017 OnigCaseFoldType flags = ONIGENC_CASE_DOWNCASE;
9020 flags = check_case_options(argc, argv, flags);
9021 enc = str_true_enc(str);
9022 if (case_option_single_p(flags, enc, str)) {
9023 ret =
rb_str_new(RSTRING_PTR(str), RSTRING_LEN(str));
9024 str_enc_copy_direct(ret, str);
9025 downcase_single(ret);
9027 else if (flags&ONIGENC_CASE_ASCII_ONLY) {
9029 rb_str_ascii_casemap(str, ret, &flags, enc);
9032 ret = rb_str_casemap(str, &flags, enc);
9039capitalize_single(
VALUE str)
9041 char *s = RSTRING_PTR(str), *send =
RSTRING_END(str);
9042 bool modified =
false;
9045 unsigned int c = (
unsigned char)*s;
9047 if (
'a' <= c && c <=
'z') {
9048 *s =
'A' + (c -
'a');
9054 unsigned int c = (
unsigned char)*s;
9056 if (
'A' <= c && c <=
'Z') {
9057 *s =
'a' + (c -
'A');
9079rb_str_capitalize_bang(
int argc,
VALUE *argv,
VALUE str)
9082 OnigCaseFoldType flags = ONIGENC_CASE_UPCASE | ONIGENC_CASE_TITLECASE;
9084 flags = check_case_options(argc, argv, flags);
9085 str_modify_keep_cr(str);
9086 enc = str_true_enc(str);
9087 if (RSTRING_LEN(str) == 0 || !RSTRING_PTR(str))
return Qnil;
9088 if (case_option_single_p(flags, enc, str)) {
9089 if (capitalize_single(str))
9090 flags |= ONIGENC_CASE_MODIFIED;
9092 else if (flags&ONIGENC_CASE_ASCII_ONLY)
9093 rb_str_ascii_casemap(str, str, &flags, enc);
9095 str_shared_replace(str, rb_str_casemap(str, &flags, enc));
9097 if (ONIGENC_CASE_MODIFIED&flags)
return str;
9111rb_str_capitalize(
int argc,
VALUE *argv,
VALUE str)
9114 OnigCaseFoldType flags = ONIGENC_CASE_UPCASE | ONIGENC_CASE_TITLECASE;
9117 flags = check_case_options(argc, argv, flags);
9118 enc = str_true_enc(str);
9119 if (RSTRING_LEN(str) == 0 || !RSTRING_PTR(str))
return str;
9120 if (case_option_single_p(flags, enc, str)) {
9121 ret =
rb_str_new(RSTRING_PTR(str), RSTRING_LEN(str));
9122 str_enc_copy_direct(ret, str);
9123 capitalize_single(ret);
9125 else if (flags&ONIGENC_CASE_ASCII_ONLY) {
9127 rb_str_ascii_casemap(str, ret, &flags, enc);
9130 ret = rb_str_casemap(str, &flags, enc);
9149rb_str_swapcase_bang(
int argc,
VALUE *argv,
VALUE str)
9152 OnigCaseFoldType flags = ONIGENC_CASE_UPCASE | ONIGENC_CASE_DOWNCASE;
9154 flags = check_case_options(argc, argv, flags);
9155 str_modify_keep_cr(str);
9156 enc = str_true_enc(str);
9157 if (flags&ONIGENC_CASE_ASCII_ONLY)
9158 rb_str_ascii_casemap(str, str, &flags, enc);
9160 str_shared_replace(str, rb_str_casemap(str, &flags, enc));
9162 if (ONIGENC_CASE_MODIFIED&flags)
return str;
9176rb_str_swapcase(
int argc,
VALUE *argv,
VALUE str)
9179 OnigCaseFoldType flags = ONIGENC_CASE_UPCASE | ONIGENC_CASE_DOWNCASE;
9182 flags = check_case_options(argc, argv, flags);
9183 enc = str_true_enc(str);
9184 if (RSTRING_LEN(str) == 0 || !RSTRING_PTR(str))
return str_duplicate(
rb_cString, str);
9185 if (flags&ONIGENC_CASE_ASCII_ONLY) {
9187 rb_str_ascii_casemap(str, ret, &flags, enc);
9190 ret = rb_str_casemap(str, &flags, enc);
9195typedef unsigned char *USTR;
9199 unsigned int now, max;
9200 const char *p, *pend;
9211 if (t->p == t->pend)
return -1;
9212 if (rb_enc_ascget(t->p, t->pend, &n, enc) ==
'\\' && t->p + n < t->pend) {
9215 t->now = rb_enc_codepoint_len(t->p, t->pend, &n, enc);
9217 if (rb_enc_ascget(t->p, t->pend, &n, enc) ==
'-' && t->p + n < t->pend) {
9219 if (t->p < t->pend) {
9220 unsigned int c = rb_enc_codepoint_len(t->p, t->pend, &n, enc);
9223 if (t->now < 0x80 && c < 0x80) {
9224 rb_raise(rb_eArgError,
9225 "invalid range \"%c-%c\" in string transliteration",
9229 rb_raise(rb_eArgError,
"invalid range in string transliteration");
9233 else if (t->now < c) {
9242 while (ONIGENC_CODE_TO_MBCLEN(enc, ++t->now) <= 0) {
9243 if (t->now == t->max) {
9248 if (t->now < t->max) {
9264 const unsigned int errc = -1;
9265 unsigned int trans[256];
9267 struct tr trsrc, trrepl;
9269 unsigned int c, c0, last = 0;
9270 int modify = 0, i, l;
9271 unsigned char *s, *send;
9273 int singlebyte = single_byte_optimizable(str);
9277#define CHECK_IF_ASCII(c) \
9278 (void)((cr == ENC_CODERANGE_7BIT && !rb_isascii(c)) ? \
9279 (cr = ENC_CODERANGE_VALID) : 0)
9283 if (RSTRING_LEN(str) == 0 || !RSTRING_PTR(str))
return Qnil;
9284 if (RSTRING_LEN(repl) == 0) {
9285 return rb_str_delete_bang(1, &src, str);
9289 e1 = rb_enc_check(str, src);
9290 e2 = rb_enc_check(str, repl);
9295 enc = rb_enc_check(src, repl);
9297 trsrc.p = RSTRING_PTR(src); trsrc.pend = trsrc.p + RSTRING_LEN(src);
9298 if (RSTRING_LEN(src) > 1 &&
9299 rb_enc_ascget(trsrc.p, trsrc.pend, &l, enc) ==
'^' &&
9300 trsrc.p + l < trsrc.pend) {
9304 trrepl.p = RSTRING_PTR(repl);
9305 trrepl.pend = trrepl.p + RSTRING_LEN(repl);
9306 trsrc.gen = trrepl.gen = 0;
9307 trsrc.now = trrepl.now = 0;
9308 trsrc.max = trrepl.max = 0;
9311 for (i=0; i<256; i++) {
9314 while ((c = trnext(&trsrc, enc)) != errc) {
9319 if (!hash) hash = rb_hash_new();
9323 while ((c = trnext(&trrepl, enc)) != errc)
9326 for (i=0; i<256; i++) {
9327 if (trans[i] != errc) {
9335 for (i=0; i<256; i++) {
9338 while ((c = trnext(&trsrc, enc)) != errc) {
9339 r = trnext(&trrepl, enc);
9340 if (r == errc) r = trrepl.now;
9343 if (rb_enc_codelen(r, enc) != 1) singlebyte = 0;
9346 if (!hash) hash = rb_hash_new();
9354 str_modify_keep_cr(str);
9355 s = (
unsigned char *)RSTRING_PTR(str); send = (
unsigned char *)
RSTRING_END(str);
9356 termlen = rb_enc_mbminlen(enc);
9359 rb_len_t offset, max = RSTRING_LEN(str);
9360 unsigned int save = -1;
9361 unsigned char *buf =
ALLOC_N(
unsigned char, max + termlen), *t = buf;
9366 int r = rb_enc_precise_mbclen((
char *)s, (
char *)send, e1);
9368 SIZED_FREE_N(buf, max + termlen);
9369 rb_raise(rb_eArgError,
"invalid byte sequence in %s", rb_enc_name(e1));
9372 c0 = c = rb_enc_mbc_to_codepoint((
char *)s, (
char *)send, e1);
9374 tlen = enc == e1 ? clen : rb_enc_codelen(c, enc);
9383 if (cflag) c = last;
9386 else if (cflag) c = errc;
9392 if (c != (
unsigned int)-1) {
9398 tlen = rb_enc_codelen(c, enc);
9404 if (enc != e1) may_modify = 1;
9406 if ((offset = t - buf) + tlen > max) {
9407 size_t MAYBE_UNUSED(old) = max + termlen;
9408 max = offset + tlen + (send - s);
9409 SIZED_REALLOC_N(buf,
unsigned char, max + termlen, old);
9412 rb_enc_mbcput(c, t, enc);
9413 if (may_modify && memcmp(s, t, tlen) != 0) {
9419 if (!STR_EMBED_P(str)) {
9420 SIZED_FREE_N(STR_HEAP_PTR(str), STR_HEAP_SIZE(str));
9422 TERM_FILL((
char *)t, termlen);
9423 RSTRING(str)->as.heap.ptr = (
char *)buf;
9424 STR_SET_LEN(str, t - buf);
9425 STR_SET_NOEMBED(str);
9426 RSTRING(str)->as.heap.aux.capa = max;
9430 c = (
unsigned char)*s;
9431 if (trans[c] != errc) {
9449 unsigned char *buf =
ALLOC_N(
unsigned char, max + termlen), *t = buf;
9454 int r = rb_enc_precise_mbclen((
char *)s, (
char *)send, e1);
9456 SIZED_FREE_N(buf, max + termlen);
9457 rb_raise(rb_eArgError,
"invalid byte sequence in %s", rb_enc_name(e1));
9460 c0 = c = rb_enc_mbc_to_codepoint((
char *)s, (
char *)send, e1);
9462 tlen = enc == e1 ? clen : rb_enc_codelen(c, enc);
9470 if (cflag) c = last;
9473 else if (cflag) c = errc;
9477 c = cflag ? last : errc;
9480 tlen = rb_enc_codelen(c, enc);
9485 if (enc != e1) may_modify = 1;
9487 if ((offset = t - buf) + tlen > max) {
9488 size_t MAYBE_UNUSED(old) = max + termlen;
9489 max = offset + tlen + (
rb_len_t)((send - s) * 1.2);
9490 SIZED_REALLOC_N(buf,
unsigned char, max + termlen, old);
9494 rb_enc_mbcput(c, t, enc);
9495 if (may_modify && memcmp(s, t, tlen) != 0) {
9502 if (!STR_EMBED_P(str)) {
9503 SIZED_FREE_N(STR_HEAP_PTR(str), STR_HEAP_SIZE(str));
9505 TERM_FILL((
char *)t, termlen);
9506 RSTRING(str)->as.heap.ptr = (
char *)buf;
9507 STR_SET_LEN(str, t - buf);
9508 STR_SET_NOEMBED(str);
9509 RSTRING(str)->as.heap.aux.capa = max;
9515 rb_enc_associate(str, enc);
9525 size_t initial_capa;
9529tr_buffer_init(
struct tr_buffer *buffer,
size_t initial_capa)
9531 if (initial_capa < 32) {
9534 *buffer = (
struct tr_buffer){ .initial_capa = initial_capa };
9538tr_buffer_ensure_capa(
struct tr_buffer *buffer,
size_t extra_capa)
9540 size_t offset = buffer->ptr - buffer->buf;
9541 size_t required_capa = offset + extra_capa;
9542 if (UNLIKELY(buffer->capa < required_capa)) {
9543 size_t new_capa = buffer->capa ? buffer->capa : buffer->initial_capa;
9545 while (new_capa < required_capa) {
9546 new_capa = (size_t)(new_capa * 1.2);
9548 SIZED_REALLOC_N(buffer->buf,
unsigned char, new_capa, buffer->capa);
9549 buffer->ptr = buffer->buf + offset;
9550 buffer->capa = new_capa;
9555tr_buffer_append(
struct tr_buffer *buffer,
const unsigned char *ptr,
size_t len)
9558 tr_buffer_ensure_capa(buffer,
len);
9559 memcpy(buffer->ptr, ptr,
len);
9567 tr_buffer_append(buffer, (
unsigned char *)RSTRING_PTR(str), RSTRING_LEN(str));
9573 tr_buffer_ensure_capa(buffer, 4);
9574 buffer->ptr += rb_enc_mbcput(codepoint, buffer->ptr, enc);
9581 SIZED_FREE_N(buffer->buf, buffer->capa);
9598tr_trans_pairs_coerce_i(st_data_t key, st_data_t value, st_data_t _args)
9601 struct tr_pair *pair = &args->pairs[args->index];
9609 if (RSTRING_LEN(search) != 1 && str_strlen(search, NULL) != 1) {
9610 rb_raise(rb_eArgError,
"keys must be of size 1");
9613 args->enc = rb_enc_check_multi_str(args->enc, &args->cr, search);
9614 args->enc = rb_enc_check_multi_str(args->enc, &args->cr, replace);
9616 pair->search = search;
9617 pair->replace = replace;
9621#define TR_TRANS_PAIRS_SIMD_MAX_NEEDLES 16
9624 const unsigned char *s;
9625 const unsigned char *send;
9628 unsigned char needles[TR_TRANS_PAIRS_SIMD_MAX_NEEDLES];
9629 unsigned int needles_count;
9630#ifdef HAVE_SIMD_NEON
9631 uint64_t matches_bitmap;
9633#ifdef HAVE_SIMD_SSE2
9638 VALUE trans_table[256];
9644 while (search->s < search->send) {
9645 VALUE repl = search->trans_table[*search->s];
9646 if (UNLIKELY(repl)) {
9656#ifdef HAVE_SIMD_SSE2
9661 size_t trailing_zeros = (size_t)ntz_int32(search->matches_bitmap);
9663 RUBY_ASSERT(trailing_zeros < (
sizeof(search->matches_bitmap) * CHAR_BIT));
9664 search->matches_bitmap >>= trailing_zeros;
9665 search->s += trailing_zeros;
9668 return search->trans_table[*search->s];
9674 const unsigned int needles_count = search->needles_count;
9675 if (needles_count) {
9678 if (search->matches_bitmap) {
9679 return tr_trans_pairs_next_match_sse2(search);
9682 if ((
size_t)(search->send - search->s) >=
sizeof(__m128i)) {
9684 __m128i masks[TR_TRANS_PAIRS_SIMD_MAX_NEEDLES];
9685 for (i = 0; i < needles_count; i++) {
9686 masks[i] = _mm_set1_epi8(search->needles[i]);
9690 const __m128i bytes = _mm_loadu_si128((__m128i
const *)search->s);
9692 __m128i matches[TR_TRANS_PAIRS_SIMD_MAX_NEEDLES];
9693 for (i = 0; i < needles_count; i++) {
9694 matches[i] = _mm_cmpeq_epi8(bytes, masks[i]);
9697 for (i = 1; i < needles_count; i++) {
9698 matches[0] = _mm_or_si128(matches[0], matches[i]);
9701 const int bitmap = _mm_movemask_epi8(matches[0]);
9704 search->matches_bitmap = bitmap;
9705 return tr_trans_pairs_next_match_sse2(search);
9707 search->s +=
sizeof(__m128i);
9708 }
while ((
size_t)(search->send - search->s) >=
sizeof(__m128i));
9711 return tr_trans_pairs_search_basic(search);
9714#define tr_trans_pairs_search_impl tr_trans_pairs_search_sse2
9717#ifdef HAVE_SIMD_NEON
9722 size_t trailing_zeros = (size_t)ntz_int64(search->matches_bitmap);
9725 RUBY_ASSERT(trailing_zeros < (
sizeof(search->matches_bitmap) * CHAR_BIT));
9726 search->matches_bitmap >>= trailing_zeros;
9727 search->s += trailing_zeros / 4;
9730 return search->trans_table[*search->s];
9736 const unsigned int needles_count = search->needles_count;
9737 if (needles_count) {
9740 if (search->matches_bitmap) {
9741 return tr_trans_pairs_next_match_neon(search);
9744 if ((
size_t)(search->send - search->s) >=
sizeof(uint8x16_t)) {
9746 uint8x16_t masks[TR_TRANS_PAIRS_SIMD_MAX_NEEDLES];
9747 for (i = 0; i < needles_count; i++) {
9748 masks[i] = vdupq_n_u8(search->needles[i]);
9752 const uint8x16_t bytes = vld1q_u8(search->s);
9754 uint8x16_t matches[TR_TRANS_PAIRS_SIMD_MAX_NEEDLES];
9755 for (i = 0; i < needles_count; i++) {
9756 matches[i] = vceqq_u8(bytes, masks[i]);
9759 for (i = 1; i < needles_count; i++) {
9760 matches[0] = vorrq_u8(matches[0], matches[i]);
9763 const uint8x8_t res = vshrn_n_u16(vreinterpretq_u16_u8(matches[0]), 4);
9764 const uint64_t bitmap = vget_lane_u64(vreinterpret_u64_u8(res), 0);
9767 search->matches_bitmap = bitmap & 0x8888888888888888ull;
9768 return tr_trans_pairs_next_match_neon(search);
9770 search->s +=
sizeof(uint8x16_t);
9771 }
while ((
size_t)(search->send - search->s) >=
sizeof(uint8x16_t));
9774 return tr_trans_pairs_search_basic(search);
9777#define tr_trans_pairs_search_impl tr_trans_pairs_search_neon
9780#ifndef tr_trans_pairs_search_impl
9781#define tr_trans_pairs_search_impl tr_trans_pairs_search_basic
9789 search->matches_bitmap >>= 1;
9798 mustnot_broken(str);
9801 if (RSTRING_LEN(str) == 0 || !RSTRING_PTR(str) || pairs_count == 0)
return Qnil;
9806 int cr = rb_enc_str_coderange(str);
9820 pairs_count = coerce_args.index;
9824 const unsigned char *sstart = (
unsigned char *)RSTRING_PTR(str);
9825 rb_len_t str_len = RSTRING_LEN(str);
9826 int termlen = rb_enc_mbminlen(e1);
9829 tr_buffer_init(&buffer, str_len);
9830 bool modify =
false;
9832 if (RB_LIKELY(rb_str_encindex_fastpath(rb_enc_to_index(e1)))) {
9836 .send = sstart + str_len,
9839 for (
size_t index = 0; index < pairs_count; index++) {
9840 struct tr_pair *pair = &pairs[index];
9842 char *ptr = RSTRING_PTR(pair->search);
9843 unsigned int codepoint = rb_enc_mbc_to_codepoint(ptr,
RSTRING_END(pair->search), e1);
9845 const unsigned char first_byte = (
unsigned char)*ptr;
9848 if (pairs_count <= TR_TRANS_PAIRS_SIMD_MAX_NEEDLES) {
9849 search.needles[index] = first_byte;
9850 search.needles_count++;
9854 if (rb_enc_codelen(codepoint, e1) == 1) {
9855 search.trans_table[first_byte] = pair->replace;
9858 search.trans_table[first_byte] =
Qundef;
9860 hash =
rb_obj_hide(rb_hash_new_capa(pairs_count));
9862 rb_hash_aset(hash,
UINT2NUM(codepoint), pair->replace);
9866 const unsigned char *checkpoint = search.s;
9868 while ((repl = tr_trans_pairs_search_impl(&search))) {
9871 if (UNLIKELY(repl ==
Qundef)) {
9872 unsigned int c = rb_enc_mbc_to_codepoint((
char *)search.s, (
char *)search.send, e1);
9873 clen = rb_enc_codelen(c, e1);
9874 repl = rb_hash_lookup2(hash,
UINT2NUM(c), 0);
9876 tr_trans_pairs_consume_match(&search);
9884 if (checkpoint < search.s) {
9885 tr_buffer_append(&buffer, checkpoint, search.s - checkpoint);
9887 tr_buffer_append_str(&buffer, repl);
9888 checkpoint = search.s + clen;
9889 tr_trans_pairs_consume_match(&search);
9896 if (modify && checkpoint < search.s) {
9897 tr_buffer_append(&buffer, checkpoint, search.s - checkpoint);
9901 const unsigned char *s = sstart;
9902 const unsigned char *send = sstart + str_len;
9904 hash =
rb_obj_hide(rb_hash_new_capa(pairs_count));
9906 for (
size_t index = 0; index < pairs_count; index++) {
9907 struct tr_pair *pair = &pairs[index];
9909 unsigned int codepoint = rb_enc_mbc_to_codepoint(RSTRING_PTR(pair->search),
RSTRING_END(pair->search), e1);
9910 rb_hash_aset(hash,
UINT2NUM(codepoint), pair->replace);
9914 bool may_modify =
false;
9916 int r = rb_enc_precise_mbclen((
char *)s, (
char *)send, e1);
9918 tr_buffer_free(&buffer);
9919 rb_raise(rb_eArgError,
"invalid byte sequence in %s", rb_enc_name(e1));
9922 unsigned int c = rb_enc_mbc_to_codepoint((
char *)s, (
char *)send, e1);
9923 unsigned int c0 = c;
9925 rb_len_t tlen = enc == e1 ? clen : rb_enc_codelen(c, e1);
9928 if (
NIL_P(replacement)) {
9929 tlen = enc == e1 ? clen : rb_enc_codelen(c, enc);
9931 if (enc != e1) may_modify =
true;
9934 tlen = RSTRING_LEN(replacement);
9938 if (
NIL_P(replacement)) {
9939 tr_buffer_mbcput(&buffer, c, enc);
9942 tr_buffer_append_str(&buffer, replacement);
9945 if (may_modify && memcmp(s, buffer.ptr - tlen, tlen) != 0) {
9963 if (!STR_EMBED_P(str)) {
9964 SIZED_FREE_N(STR_HEAP_PTR(str), STR_HEAP_SIZE(str));
9966 tr_buffer_ensure_capa(&buffer, termlen);
9967 TERM_FILL((
char *)buffer.ptr, termlen);
9968 RSTRING(str)->as.heap.ptr = (
char *)buffer.buf;
9969 STR_SET_LEN(str, buffer.ptr - buffer.buf);
9970 STR_SET_NOEMBED(str);
9971 RSTRING(str)->as.heap.aux.capa = buffer.capa - termlen;
9977 rb_enc_associate(str, e1);
9995rb_str_tr_bang(
int argc,
VALUE *argv,
VALUE str)
10000 VALUE pairs = argv[0];
10001 return tr_trans_pairs(str, pairs);
10004 VALUE src = argv[0], repl = argv[1];
10005 return tr_trans(str, src, repl, 0);
10069 VALUE pairs = argv[0];
10070 VALUE result = tr_trans_pairs(str, pairs);
10071 if (
NIL_P(result)) result = str;
10075 VALUE src = argv[0], repl = argv[1];
10076 tr_trans(str, src, repl, 0);
10080#define TR_TABLE_MAX (UCHAR_MAX+1)
10081#define TR_TABLE_SIZE (TR_TABLE_MAX+1)
10083tr_setup_table(
VALUE str,
char stable[TR_TABLE_SIZE],
int first,
10086 const unsigned int errc = -1;
10087 char buf[TR_TABLE_MAX];
10090 VALUE table = 0, ptable = 0;
10091 int i, l, cflag = 0;
10093 tr.p = RSTRING_PTR(str);
tr.pend =
tr.p + RSTRING_LEN(str);
10094 tr.gen =
tr.now =
tr.max = 0;
10096 if (RSTRING_LEN(str) > 1 && rb_enc_ascget(
tr.p,
tr.pend, &l, enc) ==
'^') {
10101 for (i=0; i<TR_TABLE_MAX; i++) {
10104 stable[TR_TABLE_MAX] = cflag;
10106 else if (stable[TR_TABLE_MAX] && !cflag) {
10107 stable[TR_TABLE_MAX] = 0;
10109 for (i=0; i<TR_TABLE_MAX; i++) {
10113 while ((c = trnext(&
tr, enc)) != errc) {
10114 if (c < TR_TABLE_MAX) {
10115 buf[(
unsigned char)c] = !cflag;
10120 if (!table && (first || *tablep || stable[TR_TABLE_MAX])) {
10123 table = ptable ? ptable : rb_hash_new();
10127 table = rb_hash_new();
10132 if (table && (!ptable || (cflag ^ !
NIL_P(rb_hash_aref(ptable, key))))) {
10133 rb_hash_aset(table, key,
Qtrue);
10137 for (i=0; i<TR_TABLE_MAX; i++) {
10138 stable[i] = stable[i] && buf[i];
10140 if (!table && !cflag) {
10147tr_find(
unsigned int c,
const char table[TR_TABLE_SIZE],
VALUE del,
VALUE nodel)
10149 if (c < TR_TABLE_MAX) {
10150 return table[c] != 0;
10156 if (!
NIL_P(rb_hash_lookup(del, v)) &&
10157 (!nodel ||
NIL_P(rb_hash_lookup(nodel, v)))) {
10161 else if (nodel && !
NIL_P(rb_hash_lookup(nodel, v))) {
10164 return table[TR_TABLE_MAX] ? TRUE : FALSE;
10179rb_str_delete_bang(
int argc,
VALUE *argv,
VALUE str)
10181 char squeez[TR_TABLE_SIZE];
10183 char *s, *send, *t;
10184 VALUE del = 0, nodel = 0;
10186 int i, ascompat, cr;
10188 if (RSTRING_LEN(str) == 0 || !RSTRING_PTR(str))
return Qnil;
10190 for (i=0; i<argc; i++) {
10194 enc = rb_enc_check(str, s);
10195 tr_setup_table(s, squeez, i==0, &del, &nodel, enc);
10198 str_modify_keep_cr(str);
10199 ascompat = rb_enc_asciicompat(enc);
10200 s = t = RSTRING_PTR(str);
10207 if (ascompat && (c = *(
unsigned char*)s) < 0x80) {
10212 if (t != s) *t = c;
10218 c = rb_enc_codepoint_len(s, send, &clen, enc);
10220 if (tr_find(c, squeez, del, nodel)) {
10224 if (t != s) rb_enc_mbcput(c, t, enc);
10231 TERM_FILL(t, TERM_LEN(str));
10232 STR_SET_LEN(str, t - RSTRING_PTR(str));
10235 if (modify)
return str;
10249rb_str_delete(
int argc,
VALUE *argv,
VALUE str)
10252 rb_str_delete_bang(argc, argv, str);
10270rb_str_squeeze_bang(
int argc,
VALUE *argv,
VALUE str)
10272 char squeez[TR_TABLE_SIZE];
10274 VALUE del = 0, nodel = 0;
10275 unsigned char *s, *send, *t;
10277 int ascompat, singlebyte = single_byte_optimizable(str);
10281 enc = STR_ENC_GET(str);
10284 for (i=0; i<argc; i++) {
10288 enc = rb_enc_check(str, s);
10289 if (singlebyte && !single_byte_optimizable(s))
10291 tr_setup_table(s, squeez, i==0, &del, &nodel, enc);
10295 str_modify_keep_cr(str);
10296 s = t = (
unsigned char *)RSTRING_PTR(str);
10297 if (!s || RSTRING_LEN(str) == 0)
return Qnil;
10300 ascompat = rb_enc_asciicompat(enc);
10304 unsigned int c = *s++;
10305 if (c != save || (argc > 0 && !squeez[c])) {
10315 if (ascompat && (c = *s) < 0x80) {
10316 if (c != save || (argc > 0 && !squeez[c])) {
10322 c = rb_enc_codepoint_len((
char *)s, (
char *)send, &clen, enc);
10324 if (c != save || (argc > 0 && !tr_find(c, squeez, del, nodel))) {
10325 if (t != s) rb_enc_mbcput(c, t, enc);
10334 TERM_FILL((
char *)t, TERM_LEN(str));
10335 if ((
char *)t - RSTRING_PTR(str) != RSTRING_LEN(str)) {
10336 STR_SET_LEN(str, (
char *)t - RSTRING_PTR(str));
10340 if (modify)
return str;
10354rb_str_squeeze(
int argc,
VALUE *argv,
VALUE str)
10357 rb_str_squeeze_bang(argc, argv, str);
10377 return tr_trans(str, src, repl, 1);
10405 tr_trans(str, src, repl, 1);
10418rb_str_count(
int argc,
VALUE *argv,
VALUE str)
10420 char table[TR_TABLE_SIZE];
10422 VALUE del = 0, nodel = 0, tstr;
10423 const char *s, *send;
10432 enc = rb_enc_check(str, tstr);
10435 if (RSTRING_LEN(tstr) == 1 && rb_enc_asciicompat(enc) &&
10436 (ptstr = RSTRING_PTR(tstr),
10437 ONIGENC_IS_ALLOWED_REVERSE_MATCH(enc, (
const unsigned char *)ptstr, (
const unsigned char *)ptstr+1)) &&
10438 !is_broken_string(str)) {
10440 unsigned char c = rb_enc_codepoint_len(ptstr, ptstr+1, &clen, enc);
10442 s = RSTRING_PTR(str);
10443 if (!s || RSTRING_LEN(str) == 0)
return INT2FIX(0);
10446 if (*(
unsigned char*)s++ == c) n++;
10452 tr_setup_table(tstr, table, TRUE, &del, &nodel, enc);
10453 for (i=1; i<argc; i++) {
10456 enc = rb_enc_check(str, tstr);
10457 tr_setup_table(tstr, table, FALSE, &del, &nodel, enc);
10460 s = RSTRING_PTR(str);
10461 if (!s || RSTRING_LEN(str) == 0)
return INT2FIX(0);
10463 ascompat = rb_enc_asciicompat(enc);
10467 if (ascompat && (c = *(
unsigned char*)s) < 0x80) {
10475 c = rb_enc_codepoint_len(s, send, &clen, enc);
10476 if (tr_find(c, table, del, nodel)) {
10487rb_fs_check(
VALUE val)
10491 if (
NIL_P(val))
return 0;
10496static const char isspacetable[256] = {
10497 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0,
10498 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
10499 1, 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,
10508 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
10509 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
10510 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
10511 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
10512 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
10515#define ascii_isspace(c) isspacetable[(unsigned char)(c)]
10520 if (empty_count >= 0 &&
len == 0) {
10521 return empty_count + 1;
10523 if (empty_count > 0) {
10528 }
while (--empty_count > 0);
10532 rb_yield(str_new_empty_String(str));
10533 }
while (--empty_count > 0);
10543 return empty_count;
10547 SPLIT_TYPE_AWK, SPLIT_TYPE_STRING, SPLIT_TYPE_REGEXP, SPLIT_TYPE_CHARS
10551literal_split_pattern(
VALUE spat, split_type_t default_type)
10559 return SPLIT_TYPE_CHARS;
10561 else if (rb_enc_asciicompat(enc)) {
10562 if (
len == 1 && ptr[0] ==
' ') {
10563 return SPLIT_TYPE_AWK;
10568 if (rb_enc_ascget(ptr, ptr +
len, &l, enc) ==
' ' &&
len == l) {
10569 return SPLIT_TYPE_AWK;
10572 return default_type;
10585rb_str_split_m(
int argc,
VALUE *argv,
VALUE str)
10590 split_type_t split_type;
10591 rb_len_t beg, end, i = 0, empty_count = -1;
10596 if (
rb_scan_args(argc, argv,
"02", &spat, &limit) == 2) {
10598 if (lim <= 0) limit =
Qnil;
10599 else if (lim == 1) {
10600 if (RSTRING_LEN(str) == 0)
10611 if (
NIL_P(limit) && !lim) empty_count = 0;
10613 enc = STR_ENC_GET(str);
10614 split_type = SPLIT_TYPE_REGEXP;
10615 if (!
NIL_P(spat)) {
10616 spat = get_pat_quoted(spat, 0);
10618 else if (
NIL_P(spat = rb_fs)) {
10619 split_type = SPLIT_TYPE_AWK;
10621 else if (!(spat = rb_fs_check(spat))) {
10622 rb_raise(
rb_eTypeError,
"value of $; must be String or Regexp");
10627 if (split_type != SPLIT_TYPE_AWK) {
10632 split_type = literal_split_pattern(tmp, SPLIT_TYPE_REGEXP);
10633 if (split_type == SPLIT_TYPE_AWK) {
10635 split_type = SPLIT_TYPE_STRING;
10640 mustnot_broken(spat);
10641 split_type = literal_split_pattern(spat, SPLIT_TYPE_STRING);
10649#define SPLIT_STR(beg, len) ( \
10650 empty_count = split_string(result, str, beg, len, empty_count), \
10651 str_mod_check(str, str_start, str_len))
10654 const char *ptr = RSTRING_PTR(str);
10655 const char *
const str_start = ptr;
10656 const rb_len_t str_len = RSTRING_LEN(str);
10657 const char *
const eptr = str_start + str_len;
10658 if (split_type == SPLIT_TYPE_AWK) {
10659 const char *bptr = ptr;
10665 if (is_ascii_string(str)) {
10666 while (ptr < eptr) {
10667 c = (
unsigned char)*ptr++;
10669 if (ascii_isspace(c)) {
10675 if (!
NIL_P(limit) && lim <= i)
break;
10678 else if (ascii_isspace(c)) {
10679 SPLIT_STR(beg, end-beg);
10682 if (!
NIL_P(limit)) ++i;
10690 while (ptr < eptr) {
10693 c = rb_enc_codepoint_len(ptr, eptr, &n, enc);
10702 if (!
NIL_P(limit) && lim <= i)
break;
10706 SPLIT_STR(beg, end-beg);
10709 if (!
NIL_P(limit)) ++i;
10717 else if (split_type == SPLIT_TYPE_STRING) {
10718 const char *substr_start = ptr;
10719 const char *sptr = RSTRING_PTR(spat);
10720 rb_len_t slen = RSTRING_LEN(spat);
10723 mustnot_broken(str);
10724 enc = rb_enc_check(str, spat);
10725 while (ptr < eptr &&
10726 (end =
rb_memsearch(sptr, slen, ptr, eptr - ptr, enc)) >= 0) {
10729 if (t != ptr + end) {
10733 SPLIT_STR(substr_start - str_start, (ptr+end) - substr_start);
10734 str_mod_check(spat, sptr, slen);
10736 substr_start = ptr;
10737 if (!
NIL_P(limit) && lim <= ++i)
break;
10739 beg = ptr - str_start;
10741 else if (split_type == SPLIT_TYPE_CHARS) {
10745 mustnot_broken(str);
10746 enc = rb_enc_get(str);
10747 while (ptr < eptr &&
10748 (n = rb_enc_precise_mbclen(ptr, eptr, enc)) > 0) {
10749 SPLIT_STR(ptr - str_start, n);
10751 if (!
NIL_P(limit) && lim <= ++i)
break;
10753 beg = ptr - str_start;
10764 (match ? (rb_match_unbusy(match),
rb_backref_set(match)) : (void)0)) {
10767 end = RMATCH_BEG(match, 0);
10768 if (start == end && RMATCH_BEG(match, 0) == RMATCH_END(match, 0)) {
10773 else if (last_null == 1) {
10774 SPLIT_STR(beg, rb_enc_fast_mbclen(ptr+beg, eptr, enc));
10781 start += rb_enc_fast_mbclen(ptr+start,eptr,enc);
10787 SPLIT_STR(beg, end-beg);
10788 beg = start = RMATCH_END(match, 0);
10792 for (idx = 1; idx < RMATCH_NREGS(match); idx++) {
10793 if (RMATCH_BEG(match, idx) == -1)
continue;
10794 SPLIT_STR(RMATCH_BEG(match, idx), RMATCH_END(match, idx) - RMATCH_BEG(match, idx));
10796 if (!
NIL_P(limit) && lim <= ++i)
break;
10798 if (match) rb_match_unbusy(match);
10800 if (RSTRING_LEN(str) > 0 && (!
NIL_P(limit) || RSTRING_LEN(str) > beg || lim < 0)) {
10801 SPLIT_STR(beg, RSTRING_LEN(str)-beg);
10804 return result ? result : str;
10814 return rb_str_split_m(1, &sep, str);
10817#define WANTARRAY(m, size) (!rb_block_given_p() ? rb_ary_new_capa(size) : 0)
10832#define ENUM_ELEM(ary, e) enumerator_element(ary, e)
10835chomp_newline(
const char *p,
const char *e,
rb_encoding *enc)
10837 const char *prev = rb_enc_prev_char(p, e, e, enc);
10840 prev = rb_enc_prev_char(p, e, e, enc);
10841 if (prev && rb_enc_ascget(prev, e, NULL, enc) ==
'\r')
10853 RSTRING_LEN(rs) != 1 ||
10854 RSTRING_PTR(rs)[0] !=
'\n')) {
10860#define rb_rs get_rs()
10867 const char *pend, *subptr, *subend, *rsptr, *hit, *adjusted;
10873 if (!
NIL_P(opts)) {
10874 static ID keywords[1];
10875 if (!keywords[0]) {
10879 chomp = (!UNDEF_P(chomp) &&
RTEST(chomp));
10883 if (!ENUM_ELEM(ary, str)) {
10891 if (!RSTRING_LEN(str))
goto end;
10893 const char *
const ptr = subptr = RSTRING_PTR(str);
10897 rslen = RSTRING_LEN(rs);
10900 enc = rb_enc_get(str);
10902 enc = rb_enc_check(str, rs);
10907 const char *eol = NULL;
10909 while (subend < pend) {
10912 if (rb_enc_ascget(subend, pend, &n, enc) !=
'\r')
10914 rslen = n + rb_enc_mbclen(subend + n, pend, enc);
10916 if (eol == subend)
break;
10920 chomp_rslen = -rslen;
10924 if (!subptr) subptr = subend;
10928 }
while (subend < pend);
10929 if (!subptr)
break;
10930 if (rslen == 0) chomp_rslen = 0;
10932 subend - subptr + (chomp ? chomp_rslen : rslen));
10933 if (ENUM_ELEM(ary, line)) {
10934 str_mod_check(str, ptr,
len);
10936 subptr = eol = NULL;
10941 rsptr = RSTRING_PTR(rs);
10942 if (RSTRING_LEN(rs) == rb_enc_mbminlen(enc) &&
10951 rsptr = RSTRING_PTR(rs);
10952 rslen = RSTRING_LEN(rs);
10955 while (subptr < pend) {
10956 pos =
rb_memsearch(rsptr, rslen, subptr, pend - subptr, enc);
10957 if (pos < 0)
break;
10958 hit = subptr + pos;
10960 if (hit != adjusted) {
10964 subend = hit += rslen;
10967 subend = chomp_newline(subptr, subend, enc);
10974 if (ENUM_ELEM(ary, line)) {
10975 str_mod_check(str, ptr,
len);
10976 str_mod_check(rs, rsptr, rslen);
10981 if (subptr < pend) {
10984 pend = chomp_newline(subptr, pend, enc);
10986 else if (pend - subptr >= rslen &&
10987 memcmp(pend - rslen, rsptr, rslen) == 0) {
10992 ENUM_ELEM(ary, line);
11013rb_str_each_line(
int argc,
VALUE *argv,
VALUE str)
11016 return rb_str_enumerate_lines(argc, argv, str, 0);
11071rb_str_lines(
int argc,
VALUE *argv,
VALUE str)
11073 VALUE ary = WANTARRAY(
"lines", 0);
11074 return rb_str_enumerate_lines(argc, argv, str, ary);
11080 return LEN2NUM(RSTRING_LEN(str));
11088 for (i=0; i<RSTRING_LEN(str); i++) {
11089 ENUM_ELEM(ary,
INT2FIX((
unsigned char)RSTRING_PTR(str)[i]));
11107rb_str_each_byte(
VALUE str)
11110 return rb_str_enumerate_bytes(str, 0);
11122rb_str_bytes(
VALUE str)
11124 VALUE ary = WANTARRAY(
"bytes", RSTRING_LEN(str));
11125 return rb_str_enumerate_bytes(str, ary);
11143 ptr = RSTRING_PTR(str);
11144 len = RSTRING_LEN(str);
11145 enc = rb_enc_get(str);
11148 for (i = 0; i <
len; i += n) {
11149 n = rb_enc_fast_mbclen(ptr + i, ptr +
len, enc);
11154 for (i = 0; i <
len; i += n) {
11155 n = rb_enc_mbclen(ptr + i, ptr +
len, enc);
11176rb_str_each_char(
VALUE str)
11179 return rb_str_enumerate_chars(str, 0);
11191rb_str_chars(
VALUE str)
11194 return rb_str_enumerate_chars(str, ary);
11198rb_str_enumerate_codepoints(
VALUE str,
VALUE ary)
11203 const char *ptr, *end;
11205 int enc_asciicompat;
11207 if (single_byte_optimizable(str))
11208 return rb_str_enumerate_bytes(str, ary);
11211 ptr = RSTRING_PTR(str);
11213 enc = STR_ENC_GET(str);
11214 enc_asciicompat = rb_enc_asciicompat(enc);
11216 while (ptr < end) {
11221 c = (enc_asciicompat &&
ISASCII(*ptr)) ?
11222 (
unsigned char)*ptr : rb_enc_codepoint_len(ptr, end, &n, enc);
11243rb_str_each_codepoint(
VALUE str)
11246 return rb_str_enumerate_codepoints(str, 0);
11258rb_str_codepoints(
VALUE str)
11261 return rb_str_enumerate_codepoints(str, ary);
11267 int encidx = rb_enc_to_index(enc);
11269 const OnigUChar source_ascii[] =
"\\X";
11270 const OnigUChar *source = source_ascii;
11271 size_t source_len =
sizeof(source_ascii) - 1;
11274#define CHARS_16BE(x) (OnigUChar)((x)>>8), (OnigUChar)(x)
11275#define CHARS_16LE(x) (OnigUChar)(x), (OnigUChar)((x)>>8)
11276#define CHARS_32BE(x) CHARS_16BE((x)>>16), CHARS_16BE(x)
11277#define CHARS_32LE(x) CHARS_16LE(x), CHARS_16LE((x)>>16)
11278#define CASE_UTF(e) \
11279 case ENCINDEX_UTF_##e: { \
11280 static const OnigUChar source_UTF_##e[] = {CHARS_##e('\\'), CHARS_##e('X')}; \
11281 source = source_UTF_##e; \
11282 source_len = sizeof(source_UTF_##e); \
11285 CASE_UTF(16BE); CASE_UTF(16LE); CASE_UTF(32BE); CASE_UTF(32LE);
11293 regex_t *reg_grapheme_cluster;
11295 int r = onig_new(®_grapheme_cluster, source, source + source_len,
11296 ONIG_OPTION_DEFAULT, enc, OnigDefaultSyntax, &einfo);
11298 UChar message[ONIG_MAX_ERROR_MESSAGE_LEN];
11299 onig_error_code_to_str(message, r, &einfo);
11300 rb_fatal(
"cannot compile grapheme cluster regexp: %s", (
char *)message);
11303 return reg_grapheme_cluster;
11309 int encidx = rb_enc_to_index(enc);
11310 static regex_t *reg_grapheme_cluster_utf8 = NULL;
11312 if (encidx == rb_utf8_encindex()) {
11313 if (!reg_grapheme_cluster_utf8) {
11314 reg_grapheme_cluster_utf8 = get_reg_grapheme_cluster(enc);
11317 return reg_grapheme_cluster_utf8;
11326 size_t grapheme_cluster_count = 0;
11328 const char *ptr, *end;
11330 if (!rb_enc_unicode_p(enc)) {
11334 bool cached_reg_grapheme_cluster =
true;
11335 regex_t *reg_grapheme_cluster = get_cached_reg_grapheme_cluster(enc);
11336 if (!reg_grapheme_cluster) {
11337 reg_grapheme_cluster = get_reg_grapheme_cluster(enc);
11338 cached_reg_grapheme_cluster =
false;
11341 ptr = RSTRING_PTR(str);
11344 while (ptr < end) {
11345 OnigPosition
len = onig_match(reg_grapheme_cluster,
11346 (
const OnigUChar *)ptr, (
const OnigUChar *)end,
11347 (
const OnigUChar *)ptr, NULL, 0);
11348 if (
len <= 0)
break;
11349 grapheme_cluster_count++;
11353 if (!cached_reg_grapheme_cluster) {
11354 onig_free(reg_grapheme_cluster);
11357 return SIZET2NUM(grapheme_cluster_count);
11361rb_str_enumerate_grapheme_clusters(
VALUE str,
VALUE ary)
11365 const char *ptr0, *ptr, *end;
11367 if (!rb_enc_unicode_p(enc)) {
11368 return rb_str_enumerate_chars(str, ary);
11373 bool cached_reg_grapheme_cluster =
true;
11374 regex_t *reg_grapheme_cluster = get_cached_reg_grapheme_cluster(enc);
11375 if (!reg_grapheme_cluster) {
11376 reg_grapheme_cluster = get_reg_grapheme_cluster(enc);
11377 cached_reg_grapheme_cluster =
false;
11380 ptr0 = ptr = RSTRING_PTR(str);
11383 while (ptr < end) {
11384 OnigPosition
len = onig_match(reg_grapheme_cluster,
11385 (
const OnigUChar *)ptr, (
const OnigUChar *)end,
11386 (
const OnigUChar *)ptr, NULL, 0);
11387 if (
len <= 0)
break;
11392 if (!cached_reg_grapheme_cluster) {
11393 onig_free(reg_grapheme_cluster);
11413rb_str_each_grapheme_cluster(
VALUE str)
11416 return rb_str_enumerate_grapheme_clusters(str, 0);
11428rb_str_grapheme_clusters(
VALUE str)
11431 return rb_str_enumerate_grapheme_clusters(str, ary);
11435chopped_length(
VALUE str)
11438 const char *p, *p2, *beg, *end;
11440 beg = RSTRING_PTR(str);
11441 end = beg + RSTRING_LEN(str);
11442 if (beg >= end)
return 0;
11443 p = rb_enc_prev_char(beg, end, end, enc);
11445 if (p > beg && rb_enc_ascget(p, end, 0, enc) ==
'\n') {
11446 p2 = rb_enc_prev_char(beg, p, end, enc);
11447 if (p2 && rb_enc_ascget(p2, end, 0, enc) ==
'\r') p = p2;
11465rb_str_chop_bang(
VALUE str)
11467 str_modify_keep_cr(str);
11468 if (RSTRING_LEN(str) > 0) {
11470 len = chopped_length(str);
11471 STR_SET_LEN(str,
len);
11472 TERM_FILL(&RSTRING_PTR(str)[
len], TERM_LEN(str));
11491rb_str_chop(
VALUE str)
11497smart_chomp(
VALUE str,
const char *e,
const char *p)
11500 if (rb_enc_mbminlen(enc) > 1) {
11502 if (e - p < rb_enc_mbminlen(enc))
return e - p;
11507 pp = e - rb_enc_mbminlen(enc);
11510 if (rb_enc_ascget(pp, e, 0, enc) ==
'\r') {
11518 if (--e > p && *(e-1) ==
'\r') {
11535 const char *pp, *e, *rsptr;
11537 const char *
const p = RSTRING_PTR(str);
11540 if (
len == 0)
return 0;
11543 return smart_chomp(str, e, p);
11546 enc = rb_enc_get(str);
11549 if (rb_enc_mbminlen(enc) > 1) {
11550 while (e - p >= rb_enc_mbminlen(enc)) {
11554 pp -= rb_enc_mbminlen(enc);
11557 if (rb_enc_ascget(pp, e, 0, enc) ==
'\r') {
11564 while (e > p && *(e-1) ==
'\n') {
11566 if (e > p && *(e-1) ==
'\r')
11572 if (rslen >
len)
return len;
11574 enc = rb_enc_get(rs);
11575 newline = rsptr[rslen-1];
11576 if (rslen == rb_enc_mbminlen(enc)) {
11578 if (newline ==
'\n')
11579 return smart_chomp(str, e, p);
11583 return smart_chomp(str, e, p);
11587 enc = rb_enc_check(str, rs);
11588 if (is_broken_string(rs)) {
11592 if (p[
len-1] == newline &&
11594 memcmp(rsptr, pp, rslen) == 0)) {
11595 if (at_char_boundary(p, pp, e, enc))
11596 return len - rslen;
11608chomp_rs(
int argc,
const VALUE *argv)
11612 VALUE rs = argv[0];
11624 str_modify_keep_cr(str);
11625 STR_SET_LEN(str,
len);
11626 TERM_FILL(&RSTRING_PTR(str)[
len], TERM_LEN(str));
11638 if (
len >= olen)
return Qnil;
11639 return str_shrink(str,
len);
11655rb_str_chomp_bang(
int argc,
VALUE *argv,
VALUE str)
11658 str_modifiable(str);
11659 if (RSTRING_LEN(str) == 0 && argc < 2)
return Qnil;
11660 rs = chomp_rs(argc, argv);
11662 return rb_str_chomp_string(str, rs);
11675rb_str_chomp(
int argc,
VALUE *argv,
VALUE str)
11677 VALUE rs = chomp_rs(argc, argv);
11683tr_setup_table_multi(
char table[TR_TABLE_SIZE],
VALUE *tablep,
VALUE *ctablep,
11684 VALUE str,
int num_selectors,
VALUE *selectors)
11688 for (i=0; i<num_selectors; i++) {
11689 VALUE selector = selectors[i];
11693 enc = rb_enc_check(str, selector);
11694 tr_setup_table(selector, table, i==0, tablep, ctablep, enc);
11701 const char *
const start = s;
11703 if (!s || s >= e)
return 0;
11706 if (single_byte_optimizable(str)) {
11707 while (s < e && (*s ==
'\0' || ascii_isspace(*s))) s++;
11712 unsigned int cc = rb_enc_codepoint_len(s, e, &n, enc);
11722lstrip_offset_table(
VALUE str,
const char *s,
const char *e,
rb_encoding *enc,
11723 char table[TR_TABLE_SIZE],
VALUE del,
VALUE nodel)
11725 const char *
const start = s;
11727 if (!s || s >= e)
return 0;
11732 unsigned int cc = rb_enc_codepoint_len(s, e, &n, enc);
11734 if (!tr_find(cc, table, del, nodel))
break;
11753rb_str_lstrip_bang(
int argc,
VALUE *argv,
VALUE str)
11759 str_modify_keep_cr(str);
11760 enc = STR_ENC_GET(str);
11763 char table[TR_TABLE_SIZE];
11764 VALUE del = 0, nodel = 0;
11766 tr_setup_table_multi(table, &del, &nodel, str, argc, argv);
11769 str_modify_keep_cr(str);
11770 enc = STR_ENC_GET(str);
11773 loffset = lstrip_offset_table(str, start, start+olen, enc, table, del, nodel);
11776 loffset = lstrip_offset(str, start, start+olen, enc);
11781 memmove(start, start + loffset,
len);
11782 STR_SET_LEN(str,
len);
11783 TERM_FILL(start+
len, rb_enc_mbminlen(enc));
11818rb_str_lstrip(
int argc,
VALUE *argv,
VALUE str)
11825 char table[TR_TABLE_SIZE];
11826 VALUE del = 0, nodel = 0;
11828 tr_setup_table_multi(table, &del, &nodel, str, argc, argv);
11833 loffset = lstrip_offset_table(str, start, start+
len, STR_ENC_GET(str), table, del, nodel);
11836 loffset = lstrip_offset(str, start, start+
len, STR_ENC_GET(str));
11838 if (loffset <= 0)
return str_duplicate(
rb_cString, str);
11847 rb_str_check_dummy_enc(enc);
11851 if (!s || s >= e)
return 0;
11855 if (single_byte_optimizable(str)) {
11857 while (s < t && ((c = *(t-1)) ==
'\0' || ascii_isspace(c))) t--;
11862 while ((tp = rb_enc_prev_char(s, t, e, enc)) != NULL) {
11872rstrip_offset_table(
VALUE str,
const char *s,
const char *e,
rb_encoding *enc,
11873 char table[TR_TABLE_SIZE],
VALUE del,
VALUE nodel)
11875 const char *t, *tp;
11877 rb_str_check_dummy_enc(enc);
11881 if (!s || s >= e)
return 0;
11885 while ((tp = rb_enc_prev_char(s, t, e, enc)) != NULL) {
11887 if (!tr_find(c, table, del, nodel))
break;
11907rb_str_rstrip_bang(
int argc,
VALUE *argv,
VALUE str)
11913 str_modify_keep_cr(str);
11914 enc = STR_ENC_GET(str);
11917 char table[TR_TABLE_SIZE];
11918 VALUE del = 0, nodel = 0;
11920 tr_setup_table_multi(table, &del, &nodel, str, argc, argv);
11923 str_modify_keep_cr(str);
11924 enc = STR_ENC_GET(str);
11927 roffset = rstrip_offset_table(str, start, start+olen, enc, table, del, nodel);
11930 roffset = rstrip_offset(str, start, start+olen, enc);
11935 STR_SET_LEN(str,
len);
11936 TERM_FILL(start+
len, rb_enc_mbminlen(enc));
11970rb_str_rstrip(
int argc,
VALUE *argv,
VALUE str)
11976 enc = STR_ENC_GET(str);
11979 char table[TR_TABLE_SIZE];
11980 VALUE del = 0, nodel = 0;
11982 tr_setup_table_multi(table, &del, &nodel, str, argc, argv);
11985 enc = STR_ENC_GET(str);
11988 roffset = rstrip_offset_table(str, start, start+olen, enc, table, del, nodel);
11991 roffset = rstrip_offset(str, start, start+olen, enc);
11993 if (roffset <= 0)
return str_duplicate(
rb_cString, str);
12011rb_str_strip_bang(
int argc,
VALUE *argv,
VALUE str)
12017 str_modify_keep_cr(str);
12018 enc = STR_ENC_GET(str);
12022 char table[TR_TABLE_SIZE];
12023 VALUE del = 0, nodel = 0;
12025 tr_setup_table_multi(table, &del, &nodel, str, argc, argv);
12028 str_modify_keep_cr(str);
12029 enc = STR_ENC_GET(str);
12032 loffset = lstrip_offset_table(str, start, start+olen, enc, table, del, nodel);
12033 roffset = rstrip_offset_table(str, start+loffset, start+olen, enc, table, del, nodel);
12036 loffset = lstrip_offset(str, start, start+olen, enc);
12037 roffset = rstrip_offset(str, start+loffset, start+olen, enc);
12040 if (loffset > 0 || roffset > 0) {
12044 memmove(start, start + loffset,
len);
12046 STR_SET_LEN(str,
len);
12047 TERM_FILL(start+
len, rb_enc_mbminlen(enc));
12082rb_str_strip(
int argc,
VALUE *argv,
VALUE str)
12091 char table[TR_TABLE_SIZE];
12092 VALUE del = 0, nodel = 0;
12094 tr_setup_table_multi(table, &del, &nodel, str, argc, argv);
12097 enc = STR_ENC_GET(str);
12100 loffset = lstrip_offset_table(str, start, start+olen, enc, table, del, nodel);
12101 roffset = rstrip_offset_table(str, start+loffset, start+olen, enc, table, del, nodel);
12104 loffset = lstrip_offset(str, start, start+olen, enc);
12105 roffset = rstrip_offset(str, start+loffset, start+olen, enc);
12108 if (loffset <= 0 && roffset <= 0)
return str_duplicate(
rb_cString, str);
12116 rb_len_t end, pos = rb_pat_search(pat, str, *start, set_backref_str);
12120 end = pos + RSTRING_LEN(pat);
12124 pos = RMATCH_BEG(match, 0);
12125 end = RMATCH_END(match, 0);
12133 if (RSTRING_LEN(str) > end)
12134 *start = end + rb_enc_fast_mbclen(RSTRING_PTR(str) + end,
12143 if (
NIL_P(match) || RMATCH_NREGS(match) == 1) {
12148 int num_regs = RMATCH_NREGS(match);
12150 for (
int i = 1; i < num_regs; i++) {
12152 if (RMATCH_BEG(match, i) >= 0) {
12153 s =
rb_str_subseq(str, RMATCH_BEG(match, i), RMATCH_END(match, i) - RMATCH_BEG(match, i));
12182 const char *p = RSTRING_PTR(str);
12185 pat = get_pat_quoted(pat, 1);
12186 mustnot_broken(str);
12190 while (!
NIL_P(result = scan_once(str, pat, &start, 0))) {
12195 if (last >= 0) rb_pat_search(pat, str, last, 1);
12200 while (!
NIL_P(result = scan_once(str, pat, &start, 1))) {
12204 str_mod_check(str, p,
len);
12206 if (last >= 0) rb_pat_search(pat, str, last, 1);
12258rb_str_hex(
VALUE str)
12260 return rb_str_to_inum(str, 16, FALSE);
12344rb_str_oct(
VALUE str)
12346 return rb_str_to_inum(str, -8, FALSE);
12349#ifndef HAVE_CRYPT_R
12354 rb_nativethread_lock_t lock;
12355} crypt_mutex = {PTHREAD_MUTEX_INITIALIZER};
12424# define CRYPT_END() ALLOCV_END(databuf)
12427 extern char *crypt(
const char *,
const char *);
12428# define CRYPT_END() rb_nativethread_lock_unlock(&crypt_mutex.lock)
12431 const char *s, *saltp, *res;
12433 char salt_8bit_clean[3];
12437 mustnot_wchar(str);
12438 mustnot_wchar(salt);
12440 saltp = RSTRING_PTR(salt);
12441 if (RSTRING_LEN(salt) < 2 || !saltp[0] || !saltp[1]) {
12442 rb_raise(rb_eArgError,
"salt too short (need >=2 bytes)");
12446 if (!
ISASCII((
unsigned char)saltp[0]) || !
ISASCII((
unsigned char)saltp[1])) {
12447 salt_8bit_clean[0] = saltp[0] & 0x7f;
12448 salt_8bit_clean[1] = saltp[1] & 0x7f;
12449 salt_8bit_clean[2] =
'\0';
12450 saltp = salt_8bit_clean;
12455# ifdef HAVE_STRUCT_CRYPT_DATA_INITIALIZED
12456 data->initialized = 0;
12458 res = crypt_r(s, saltp, data);
12461 res = crypt(s, saltp);
12476 size_t res_size = strlen(res);
12477 tmp_buf =
ALLOCA_N(
char, res_size);
12478 memcpy(tmp_buf, res, res_size);
12514 char *ptr, *p, *pend;
12517 unsigned long sum0 = 0;
12522 ptr = p = RSTRING_PTR(str);
12523 len = RSTRING_LEN(str);
12529 str_mod_check(str, ptr,
len);
12532 sum0 += (
unsigned char)*p;
12543 if (bits < (
int)
sizeof(
long)*CHAR_BIT) {
12544 sum0 &= (((
unsigned long)1)<<bits)-1;
12564rb_str_justify(
int argc,
VALUE *argv,
VALUE str,
char jflag)
12571 const char *f =
" ";
12572 rb_len_t n, size, llen, rlen, llen2 = 0, rlen2 = 0;
12574 int singlebyte = 1, cr;
12578 enc = STR_ENC_GET(str);
12582 enc = rb_enc_check(str, pad);
12583 f = RSTRING_PTR(pad);
12584 flen = RSTRING_LEN(pad);
12585 fclen = str_strlen(pad, enc);
12586 singlebyte = single_byte_optimizable(pad);
12587 if (flen == 0 || fclen == 0) {
12588 rb_raise(rb_eArgError,
"zero width padding");
12591 termlen = rb_enc_mbminlen(enc);
12592 len = str_strlen(str, enc);
12593 if (width < 0 || len >= width)
return str_duplicate(
rb_cString, str);
12595 llen = (jflag ==
'l') ? 0 : ((jflag ==
'r') ? n : n/2);
12599 llen2 = str_offset(f, f + flen, llen % fclen, enc, singlebyte);
12600 rlen2 = str_offset(f, f + flen, rlen % fclen, enc, singlebyte);
12602 size = RSTRING_LEN(str);
12603 if ((
len = llen / fclen + rlen / fclen) >=
RB_LEN_MAX / flen ||
12606 rb_raise(rb_eArgError,
"argument too big");
12610 p = RSTRING_PTR(res);
12612 memset(p, *f, llen);
12616 while (llen >= fclen) {
12622 memcpy(p, f, llen2);
12626 memcpy(p, RSTRING_PTR(str), size);
12629 memset(p, *f, rlen);
12633 while (rlen >= fclen) {
12639 memcpy(p, f, rlen2);
12643 TERM_FILL(p, termlen);
12644 STR_SET_LEN(res, p-RSTRING_PTR(res));
12665rb_str_ljust(
int argc,
VALUE *argv,
VALUE str)
12667 return rb_str_justify(argc, argv, str,
'l');
12679rb_str_rjust(
int argc,
VALUE *argv,
VALUE str)
12681 return rb_str_justify(argc, argv, str,
'r');
12694rb_str_center(
int argc,
VALUE *argv,
VALUE str)
12696 return rb_str_justify(argc, argv, str,
'c');
12712 sep = get_pat_quoted(sep, 0);
12719 pos = RMATCH_BEG(match, 0);
12723 pos = rb_str_index(str, sep, 0);
12724 if (pos < 0)
goto failed;
12727 rb_len_t rpos = pos + RSTRING_LEN(sep);
12728 if (rpos > RSTRING_LEN(str))
goto failed;
12734 return rb_ary_new3(3, str_duplicate(
rb_cString, str), str_new_empty_String(str), str_new_empty_String(str));
12750 sep = get_pat_quoted(sep, 0);
12752 pos = RSTRING_LEN(str);
12758 pos = RMATCH_BEG(match, 0);
12764 pos = rb_str_rindex(str, sep, pos);
12770 rb_len_t rpos = pos + RSTRING_LEN(sep);
12771 if (rpos > RSTRING_LEN(str))
goto failed;
12776 return rb_ary_new3(3, str_new_empty_String(str), str_new_empty_String(str), str_duplicate(
rb_cString, str));
12788rb_str_start_with(
int argc,
VALUE *argv,
VALUE str)
12792 for (i=0; i<argc; i++) {
12793 VALUE tmp = argv[i];
12795 if (rb_reg_start_with_p(tmp, str))
12799 const char *p, *s, *e;
12804 enc = rb_enc_check(str, tmp);
12805 if ((tlen = RSTRING_LEN(tmp)) == 0)
return Qtrue;
12806 if ((slen = RSTRING_LEN(str)) < tlen)
continue;
12807 p = RSTRING_PTR(str);
12810 if (!at_char_right_boundary(p, s, e, enc))
12812 if (memcmp(p, RSTRING_PTR(tmp), tlen) == 0)
12828rb_str_end_with(
int argc,
VALUE *argv,
VALUE str)
12832 for (i=0; i<argc; i++) {
12833 VALUE tmp = argv[i];
12834 const char *p, *s, *e;
12839 enc = rb_enc_check(str, tmp);
12840 if ((tlen = RSTRING_LEN(tmp)) == 0)
return Qtrue;
12841 if ((slen = RSTRING_LEN(str)) < tlen)
continue;
12842 p = RSTRING_PTR(str);
12845 if (!at_char_boundary(p, s, e, enc))
12847 if (memcmp(s, RSTRING_PTR(tmp), tlen) == 0)
12863deleted_prefix_length(
VALUE str,
VALUE prefix)
12865 const char *strptr, *prefixptr;
12871 if (!is_broken_string(prefix) ||
12872 !rb_enc_asciicompat(enc) ||
12873 !rb_enc_asciicompat(rb_enc_get(prefix))) {
12874 enc = rb_enc_check(str, prefix);
12878 prefixlen = RSTRING_LEN(prefix);
12879 if (prefixlen <= 0)
return 0;
12880 olen = RSTRING_LEN(str);
12881 if (olen < prefixlen)
return 0;
12882 strptr = RSTRING_PTR(str);
12883 prefixptr = RSTRING_PTR(prefix);
12884 if (memcmp(strptr, prefixptr, prefixlen) != 0)
return 0;
12885 if (is_broken_string(prefix)) {
12886 if (!is_broken_string(str)) {
12890 const char *strend = strptr + olen;
12891 const char *after_prefix = strptr + prefixlen;
12892 if (!at_char_right_boundary(strptr, after_prefix, strend, enc)) {
12913rb_str_delete_prefix_bang(
VALUE str,
VALUE prefix)
12916 str_modify_keep_cr(str);
12918 prefixlen = deleted_prefix_length(str, prefix);
12919 if (prefixlen <= 0)
return Qnil;
12933rb_str_delete_prefix(
VALUE str,
VALUE prefix)
12937 prefixlen = deleted_prefix_length(str, prefix);
12938 if (prefixlen <= 0)
return str_duplicate(
rb_cString, str);
12940 return rb_str_subseq(str, prefixlen, RSTRING_LEN(str) - prefixlen);
12953deleted_suffix_length(
VALUE str,
VALUE suffix)
12955 const char *strptr, *suffixptr;
12960 if (is_broken_string(suffix))
return 0;
12961 enc = rb_enc_check(str, suffix);
12964 suffixlen = RSTRING_LEN(suffix);
12965 if (suffixlen <= 0)
return 0;
12966 olen = RSTRING_LEN(str);
12967 if (olen < suffixlen)
return 0;
12968 strptr = RSTRING_PTR(str);
12969 suffixptr = RSTRING_PTR(suffix);
12970 const char *strend = strptr + olen;
12971 const char *before_suffix = strend - suffixlen;
12972 if (memcmp(before_suffix, suffixptr, suffixlen) != 0)
return 0;
12973 if (!at_char_boundary(strptr, before_suffix, strend, enc))
return 0;
12989rb_str_delete_suffix_bang(
VALUE str,
VALUE suffix)
12992 str_modifiable(str);
12994 suffixlen = deleted_suffix_length(str, suffix);
12995 if (suffixlen <= 0)
return Qnil;
12997 return str_shrink(str, RSTRING_LEN(str) - suffixlen);
13009rb_str_delete_suffix(
VALUE str,
VALUE suffix)
13013 suffixlen = deleted_suffix_length(str, suffix);
13014 if (suffixlen <= 0)
return str_duplicate(
rb_cString, str);
13016 return rb_str_subseq(str, 0, RSTRING_LEN(str) - suffixlen);
13023 rb_raise(
rb_eTypeError,
"value of %"PRIsVALUE
" must be String", rb_id2str(
id));
13029nil_setter_warning(
ID id)
13031 rb_warn_deprecated(
"non-nil '%"PRIsVALUE
"'", NULL, rb_id2str(
id));
13038 if (!
NIL_P(*var)) {
13039 nil_setter_warning(
id);
13046 val = rb_fs_check(val);
13049 "value of %"PRIsVALUE
" must be String or Regexp",
13053 nil_setter_warning(
id);
13070 str_modifiable(str);
13073 int idx = rb_enc_to_index(encoding);
13080 rb_enc_associate_index(str, idx);
13104 if (STR_EMBED_P(str)) {
13105 str2 = str_alloc_embed(
rb_cString, RSTRING_LEN(str) + TERM_LEN(str));
13110 str_replace_shared_without_enc(str2, str);
13112 if (rb_enc_asciicompat(STR_ENC_GET(str))) {
13135rb_str_valid_encoding_p(
VALUE str)
13137 int cr = rb_enc_str_coderange(str);
13144rb_str_is_ascii_only_p(
VALUE str)
13146 int cr = rb_enc_str_coderange(str);
13154 static const char ellipsis[] =
"...";
13155 const rb_len_t ellipsislen =
sizeof(ellipsis) - 1;
13157 const rb_len_t blen = RSTRING_LEN(str);
13158 const char *
const p = RSTRING_PTR(str), *e = p + blen;
13159 VALUE estr, ret = 0;
13162 if (
len * rb_enc_mbminlen(enc) >= blen ||
13166 else if (
len <= ellipsislen ||
13168 if (rb_enc_asciicompat(enc)) {
13170 rb_enc_associate(ret, enc);
13177 else if (ret =
rb_str_subseq(str, 0, e - p), rb_enc_asciicompat(enc)) {
13182 rb_enc_from_encoding(enc), 0,
Qnil);
13193 cr = rb_enc_str_coderange(str);
13195 rb_raise(rb_eArgError,
"replacement must be valid byte sequence '%+"PRIsVALUE
"'", str);
13201 rb_enc_inspect_name(enc), rb_enc_inspect_name(e));
13220 if (enc == STR_ENC_GET(str)) {
13225 return enc_str_scrub(enc, str, repl, cr);
13233 const char *rep, *p, *e, *p1, *sp;
13239 rb_raise(rb_eArgError,
"both of block and replacement given");
13246 if (!
NIL_P(repl)) {
13247 repl = str_compat_and_valid(repl, enc);
13250 if (rb_enc_dummy_p(enc)) {
13253 encidx = rb_enc_to_index(enc);
13255#define DEFAULT_REPLACE_CHAR(str) do { \
13256 RBIMPL_ATTR_NONSTRING() static const char replace[sizeof(str)-1] = str; \
13257 rep = replace; replen = (int)sizeof(replace); \
13260 slen = RSTRING_LEN(str);
13261 p = RSTRING_PTR(str);
13266 if (rb_enc_asciicompat(enc)) {
13272 else if (!
NIL_P(repl)) {
13273 rep = RSTRING_PTR(repl);
13274 replen = RSTRING_LEN(repl);
13277 else if (encidx == rb_utf8_encindex()) {
13278 DEFAULT_REPLACE_CHAR(
"\xEF\xBF\xBD");
13282 DEFAULT_REPLACE_CHAR(
"?");
13287 p = search_nonascii(p, e);
13292 int ret = rb_enc_precise_mbclen(p, e, enc);
13300 p = search_nonascii(p, e);
13317 if (e - p < clen) clen = e - p;
13324 for (; clen > 1; clen--) {
13325 ret = rb_enc_precise_mbclen(q, q + clen, enc);
13336 repl =
rb_yield(rb_enc_str_new(p, clen, enc));
13337 str_mod_check(str, sp, slen);
13338 repl = str_compat_and_valid(repl, enc);
13345 p = search_nonascii(p, e);
13371 repl =
rb_yield(rb_enc_str_new(p, e-p, enc));
13372 str_mod_check(str, sp, slen);
13373 repl = str_compat_and_valid(repl, enc);
13382 rb_len_t mbminlen = rb_enc_mbminlen(enc);
13386 else if (!
NIL_P(repl)) {
13387 rep = RSTRING_PTR(repl);
13388 replen = RSTRING_LEN(repl);
13390 else if (encidx == ENCINDEX_UTF_16BE) {
13391 DEFAULT_REPLACE_CHAR(
"\xFF\xFD");
13393 else if (encidx == ENCINDEX_UTF_16LE) {
13394 DEFAULT_REPLACE_CHAR(
"\xFD\xFF");
13396 else if (encidx == ENCINDEX_UTF_32BE) {
13397 DEFAULT_REPLACE_CHAR(
"\x00\x00\xFF\xFD");
13399 else if (encidx == ENCINDEX_UTF_32LE) {
13400 DEFAULT_REPLACE_CHAR(
"\xFD\xFF\x00\x00");
13403 DEFAULT_REPLACE_CHAR(
"?");
13407 int ret = rb_enc_precise_mbclen(p, e, enc);
13420 if (e - p < clen) clen = e - p;
13421 if (clen <= mbminlen * 2) {
13426 for (; clen > mbminlen; clen-=mbminlen) {
13427 ret = rb_enc_precise_mbclen(q, q + clen, enc);
13437 repl =
rb_yield(rb_enc_str_new(p, clen, enc));
13438 str_mod_check(str, sp, slen);
13439 repl = str_compat_and_valid(repl, enc);
13464 repl =
rb_yield(rb_enc_str_new(p, e-p, enc));
13465 str_mod_check(str, sp, slen);
13466 repl = str_compat_and_valid(repl, enc);
13506str_scrub_bang(
int argc,
VALUE *argv,
VALUE str)
13514static ID id_normalize;
13515static ID id_normalized_p;
13516static VALUE mUnicodeNormalize;
13519unicode_normalize_common(
int argc,
VALUE *argv,
VALUE str,
ID id)
13521 static int UnicodeNormalizeRequired = 0;
13524 if (!UnicodeNormalizeRequired) {
13525 rb_require(
"unicode_normalize/normalize.rb");
13526 UnicodeNormalizeRequired = 1;
13530 return rb_funcallv(mUnicodeNormalize,
id, argc+1, argv2);
13541rb_str_unicode_normalize(
int argc,
VALUE *argv,
VALUE str)
13543 return unicode_normalize_common(argc, argv, str, id_normalize);
13557rb_str_unicode_normalize_bang(
int argc,
VALUE *argv,
VALUE str)
13559 return rb_str_replace(str, unicode_normalize_common(argc, argv, str, id_normalize));
13586rb_str_unicode_normalized_p(
int argc,
VALUE *argv,
VALUE str)
13588 return unicode_normalize_common(argc, argv, str, id_normalized_p);
13720#define sym_equal rb_obj_equal
13723sym_printable(
const char *s,
const char *send,
rb_encoding *enc)
13727 int c = rb_enc_precise_mbclen(s, send, enc);
13731 c = rb_enc_mbc_to_codepoint(s, send, enc);
13739rb_str_symname_p(
VALUE sym)
13744 rb_encoding *resenc = rb_default_internal_encoding();
13746 if (resenc == NULL) resenc = rb_default_external_encoding();
13747 enc = STR_ENC_GET(sym);
13748 ptr = RSTRING_PTR(sym);
13749 len = RSTRING_LEN(sym);
13750 if ((resenc != enc && !rb_str_is_ascii_only_p(sym)) ||
len != (
rb_len_t)strlen(ptr) ||
13758rb_str_quote_unprintable(
VALUE str)
13766 resenc = rb_default_internal_encoding();
13767 if (resenc == NULL) resenc = rb_default_external_encoding();
13768 enc = STR_ENC_GET(str);
13769 ptr = RSTRING_PTR(str);
13770 len = RSTRING_LEN(str);
13771 if ((resenc != enc && !rb_str_is_ascii_only_p(str)) ||
13772 !sym_printable(ptr, ptr +
len, enc)) {
13773 return rb_str_escape(str);
13779rb_id_quote_unprintable(
ID id)
13781 VALUE str = rb_id2str(
id);
13782 if (!rb_str_symname_p(str)) {
13783 return rb_str_escape(str);
13801sym_inspect(
VALUE sym)
13808 if (!rb_str_symname_p(str)) {
13810 len = RSTRING_LEN(str);
13811 rb_str_resize(str,
len + 1);
13812 dest = RSTRING_PTR(str);
13813 memmove(dest + 1, dest,
len);
13817 VALUE orig_str = str;
13819 len = RSTRING_LEN(orig_str);
13820 str = rb_enc_str_new(0,
len + 1, enc);
13823 ptr = RSTRING_PTR(orig_str);
13824 dest = RSTRING_PTR(str);
13825 memcpy(dest + 1, ptr,
len);
13843rb_sym_proc_call(
ID mid,
int argc,
const VALUE *argv,
int kw_splat,
VALUE passed_proc)
13848 rb_raise(rb_eArgError,
"no receiver given");
13951 return rb_str_match(
rb_sym2str(sym), other);
13966sym_match_m(
int argc,
VALUE *argv,
VALUE sym)
13968 return rb_str_match_m(argc, argv,
rb_sym2str(sym));
13981sym_match_m_p(
int argc,
VALUE *argv,
VALUE sym)
13983 return rb_str_match_m_p(argc, argv, sym);
14001 return rb_str_aref_m(argc, argv,
rb_sym2str(sym));
14012sym_length(
VALUE sym)
14046sym_downcase(
int argc,
VALUE *argv,
VALUE sym)
14062sym_capitalize(
int argc,
VALUE *argv,
VALUE sym)
14078sym_swapcase(
int argc,
VALUE *argv,
VALUE sym)
14092sym_start_with(
int argc,
VALUE *argv,
VALUE sym)
14094 return rb_str_start_with(argc, argv,
rb_sym2str(sym));
14107sym_end_with(
int argc,
VALUE *argv,
VALUE sym)
14109 return rb_str_end_with(argc, argv,
rb_sym2str(sym));
14121sym_encoding(
VALUE sym)
14127string_for_symbol(
VALUE name)
14132 rb_raise(
rb_eTypeError,
"%+"PRIsVALUE
" is not a symbol nor a string",
14146 name = string_for_symbol(name);
14147 return rb_intern_str(name);
14156 name = string_for_symbol(name);
14180 return rb_fstring(str);
14186 struct RString fake_str = {RBASIC_INIT};
14187 int encidx = ENCINDEX_US_ASCII;
14190 encidx = ENCINDEX_ASCII_8BIT;
14193 VALUE str = setup_fake_str(&fake_str,
ptr,
len, encidx);
14195 return register_fstring(str,
true,
false);
14207 if (enc != NULL && UNLIKELY(rb_enc_autoload_p(enc))) {
14208 rb_enc_autoload(enc);
14211 struct RString fake_str = {RBASIC_INIT};
14212 return register_fstring(rb_setup_fake_str(&fake_str,
ptr,
len, enc),
true,
false);
14218 if (enc != NULL && UNLIKELY(rb_enc_autoload_p(enc))) {
14219 rb_enc_autoload(enc);
14222 struct RString fake_str = {RBASIC_INIT};
14223 VALUE str = register_fstring(rb_setup_fake_str(&fake_str,
ptr,
len, enc),
true,
true);
14234#if USE_YJIT || USE_ZJIT
14236rb_jit_str_concat_codepoint(
VALUE str,
VALUE codepoint)
14241 if (RB_LIKELY(code >= 0 && code < 0xff)) {
14242 rb_str_buf_cat_byte(str, (
char) code);
14252fstring_set_class_i(
VALUE *str,
void *data)
14256 return ST_CONTINUE;
14264 rb_concurrent_set_foreach_with_replace(fstring_table_obj, fstring_set_class_i, NULL);
14432 mUnicodeNormalize = rb_define_module(
"UnicodeNormalize");
14443 rb_gc_register_address(&
rb_fs);
14481#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 LEN2NUM
Old name of RB_LEN2NUM.
#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 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 NUM2LEN
Old name of RB_NUM2LEN.
#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.
rb_len_t 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_str_conv_enc(VALUE str, rb_encoding *from, rb_encoding *to)
Encoding conversion main routine.
rb_len_t rb_memsearch(const void *x, rb_len_t m, const void *y, rb_len_t n, rb_encoding *enc)
Looks for the passed string in the passed buffer.
VALUE rb_enc_str_new_static(const char *ptr, rb_len_t len, rb_encoding *enc)
Identical to rb_enc_str_new(), except it takes a C string literal.
rb_len_t 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.
VALUE rb_external_str_new_with_enc(const char *ptr, rb_len_t len, rb_encoding *enc)
Identical to rb_external_str_new(), except it additionally takes an encoding.
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_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_enc_str_buf_cat(VALUE str, const char *ptr, rb_len_t len, rb_encoding *enc)
Identical to rb_str_cat(), 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(const char *ptr, rb_len_t len, rb_encoding *enc)
Identical to rb_enc_str_new(), except it returns a "f"string.
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.
char * rb_enc_nth(const char *head, const char *tail, rb_len_t nth, rb_encoding *enc)
Queries the n-th character.
int rb_enc_symname2_p(const char *name, rb_len_t 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_ary_new_capa(rb_len_t capa)
Identical to rb_ary_new(), except it additionally specifies how many rooms of objects it should alloc...
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_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, rb_len_t *begp, rb_len_t *lenp, rb_len_t 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.
VALUE rb_filesystem_str_new(const char *ptr, rb_len_t len)
Identical to rb_str_new(), except it generates a string of "filesystem" encoding.
void rb_str_modify_expand(VALUE str, rb_len_t capa)
Identical to rb_str_modify(), except it additionally expands the capacity of the receiver.
void rb_str_free(VALUE str)
Destroys the given string for no reason.
rb_len_t rb_str_offset(VALUE str, rb_len_t pos)
"Inverse" of rb_str_sublen().
VALUE rb_str_subseq(VALUE str, rb_len_t beg, rb_len_t len)
Identical to rb_str_substr(), except the numbers are interpreted as byte offsets instead of character...
rb_len_t rb_str_strlen(VALUE str)
Counts the number of characters (not bytes) that are stored inside of the given string.
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_str_tmp_new(rb_len_t len)
Allocates a "temporary" string.
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_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_utf8_str_new_static(const char *ptr, rb_len_t len)
Identical to rb_str_new_static(), except it generates a string of "UTF-8" encoding instead of "binary...
#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.
#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.
rb_len_t rb_str_sublen(VALUE str, rb_len_t pos)
Byte offset to character offset conversion.
VALUE rb_external_str_new(const char *ptr, rb_len_t len)
Identical to rb_str_new(), except it generates a string of "default external" encoding.
VALUE rb_str_new_frozen(VALUE str)
Creates a frozen copy of the string, if necessary.
void rb_str_set_len(VALUE str, rb_len_t len)
Overwrites the length of the string.
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_ellipsize(VALUE str, rb_len_t len)
Shortens str and adds three dots, an ellipsis, if it is longer than len characters.
VALUE rb_str_cat(VALUE dst, const char *src, rb_len_t srclen)
Destructively appends the passed contents to the string.
VALUE rb_str_locktmp(VALUE str)
Obtains a "temporary lock" of the 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.
VALUE rb_str_new_static(const char *ptr, rb_len_t len)
Identical to rb_str_new(), except it takes a C string literal.
#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_new_with_class(VALUE obj, const char *ptr, rb_len_t len)
Identical to rb_str_new(), except it takes the class of the allocating object.
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...
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...
VALUE rb_str_drop_bytes(VALUE str, rb_len_t len)
Shrinks the given string for the given number of bytes.
#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.
st_index_t rb_memhash(const void *ptr, rb_len_t len)
This is a universal hash function.
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_update(VALUE dst, rb_len_t beg, rb_len_t len, VALUE src)
Replaces some (or all) of the contents of the given 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_str_substr(VALUE str, rb_len_t beg, rb_len_t len)
This is the implementation of two-argumented String#slice.
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.
VALUE rb_usascii_str_new_static(const char *ptr, rb_len_t len)
Identical to rb_str_new_static(), except it generates a string of "US ASCII" encoding instead of "bin...
#define rb_strlen_lit(str)
Length of a string literal.
VALUE rb_interned_str(const char *ptr, rb_len_t len)
Identical to rb_str_new(), except it returns an infamous "f"string.
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.
char * rb_str_subpos(VALUE str, rb_len_t beg, rb_len_t *len)
Identical to rb_str_substr(), except it returns a C's string instead of Ruby's.
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_buf_new(rb_len_t capa)
Allocates a "string buffer".
#define rb_str_dup_frozen
Just another name of rb_str_new_frozen.
VALUE rb_locale_str_new(const char *ptr, rb_len_t len)
Identical to rb_str_new(), except it generates a string of "locale" encoding.
VALUE rb_check_string_type(VALUE obj)
Try converting an object to its stringised representation using its to_str method,...
#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().
#define rb_utf8_str_new(str, len)
Identical to rb_str_new, except it generates a string of "UTF-8" encoding.
VALUE rb_str_dump(VALUE str)
"Inverse" of rb_eval_string().
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_split(VALUE str, const char *delim)
Divides the given string based on the given delimiter.
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.
rb_len_t rb_reg_search(VALUE re, VALUE str, rb_len_t 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.
rb_len_t len
Length of the string, not including terminating NUL character.
struct RString::@59::@60 heap
Strings that use separated memory region for contents use this pattern.
struct RBasic basic
Basic part, including flags and class.
union RString::@59::@60::@62 aux
Auxiliary info.
struct RString::@59::@61 embed
Embedded contents.
VALUE shared
Parent of the string.
char * ptr
Pointer to the contents of the string.
rb_len_t capa
Capacity of *ptr.
union RString::@59 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.
long rb_len_t
A signed integer type for lengths and indices of objects such as String and Array.
#define RB_LEN_MAX
Maximum possible value that a rb_len_t can take.
unsigned long rb_ulen_t
An unsigned integer type that has the same width with rb_len_t.
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.