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);
343rb_str_make_heap(
VALUE str)
345 if (STR_EMBED_P(str)) {
346 const int termlen = TERM_LEN(str);
353rb_debug_rstring_null_ptr(
const char *func)
355 fprintf(stderr,
"%s is returning NULL!! "
356 "SIGSEGV is highly expected to follow immediately.\n"
357 "If you could reproduce, attach your debugger here, "
358 "and look at the passed string.\n",
363static VALUE sym_ascii, sym_turkic, sym_lithuanian, sym_fold;
366get_encoding(
VALUE str)
372mustnot_broken(
VALUE str)
374 if (is_broken_string(str)) {
375 rb_raise(rb_eArgError,
"invalid byte sequence in %s", rb_enc_name(STR_ENC_GET(str)));
380mustnot_wchar(
VALUE str)
383 if (rb_enc_mbminlen(enc) > 1) {
384 rb_raise(rb_eArgError,
"wide char encoding: %s", rb_enc_name(enc));
388static VALUE register_fstring(
VALUE str,
bool copy,
bool force_precompute_hash);
390#if SIZEOF_RB_LEN_T == SIZEOF_VOIDP
391#define PRECOMPUTED_FAKESTR_HASH 1
396BARE_STRING_P(
VALUE str)
401static inline st_index_t
402str_do_hash(
VALUE str)
404 st_index_t h =
rb_memhash((
const void *)RSTRING_PTR(str), RSTRING_LEN(str));
406 if (e && !is_ascii_string(str)) {
413str_store_precomputed_hash(
VALUE str, st_index_t hash)
419 size_t used_bytes = (RSTRING_LEN(str) + TERM_LEN(str));
420 size_t free_bytes = str_embed_capa(str) - used_bytes;
424 memcpy(
RSTRING_END(str) + TERM_LEN(str), &hash,
sizeof(hash));
426 FL_SET(str, STR_PRECOMPUTED_HASH);
439 if (
FL_TEST(str, RSTRING_FSTR))
442 bare = BARE_STRING_P(str);
444 if (STR_EMBED_P(str)) {
449 if (
FL_TEST_RAW(str, STR_SHARED_ROOT | STR_SHARED) == STR_SHARED_ROOT) {
456 rb_str_resize(str, RSTRING_LEN(str));
458 fstr = register_fstring(str,
false,
false);
461 str_replace_shared_without_enc(str, fstr);
468static VALUE fstring_table_obj;
471fstring_concurrent_set_hash(
VALUE str)
473#ifdef PRECOMPUTED_FAKESTR_HASH
477 h = (st_index_t)
RSTRING(str)->as.heap.aux.capa;
494 const char *aptr, *bptr;
501 return (alen == blen &&
503 memcmp(aptr, bptr, alen) == 0);
508 bool force_precompute_hash;
512fstring_concurrent_set_create(
VALUE str,
void *data)
524 int term_len = TERM_LEN(str);
526 if (arg->force_precompute_hash && STR_EMBEDDABLE_P(
capa, term_len)) {
528 memcpy(RSTRING_PTR(new_str), RSTRING_PTR(str),
len);
529 STR_SET_LEN(new_str, RSTRING_LEN(str));
531 rb_enc_copy(new_str, str);
532 str_store_precomputed_hash(new_str, str_do_hash(str));
536 rb_enc_copy(new_str, str);
537#ifdef PRECOMPUTED_FAKESTR_HASH
538 if (
rb_str_capacity(new_str) >= RSTRING_LEN(str) + term_len +
sizeof(st_index_t)) {
539 str_store_precomputed_hash(new_str, (st_index_t)
RSTRING(str)->as.heap.aux.capa);
553 if (!
OBJ_FROZEN(str) || CHILLED_STRING_P(str)) {
556 if (STR_SHARED_P(str)) {
558 str_make_independent(str);
561 if (!BARE_STRING_P(str)) {
567 RBASIC(str)->flags |= RSTRING_FSTR;
583 .hash = fstring_concurrent_set_hash,
584 .cmp = fstring_concurrent_set_cmp,
585 .create = fstring_concurrent_set_create,
590Init_fstring_table(
void)
592 fstring_table_obj = rb_concurrent_set_new(&fstring_concurrent_set_funcs, 8192);
593 rb_gc_register_address(&fstring_table_obj);
597register_fstring(
VALUE str,
bool copy,
bool force_precompute_hash)
601 .force_precompute_hash = force_precompute_hash
604#ifdef PRECOMPUTED_FAKESTR_HASH
612 VALUE result = rb_concurrent_set_find_or_insert(&fstring_table_obj, str, &args);
614 RUBY_ASSERT(!rb_objspace_garbage_object_p(result));
626rb_obj_is_fstring_table(
VALUE obj)
630 return obj == fstring_table_obj;
634rb_gc_free_fstring(
VALUE obj)
636 ASSERT_vm_locking_with_barrier();
642 rb_concurrent_set_delete_by_identity(fstring_table_obj, obj);
644 RB_DEBUG_COUNTER_INC(obj_str_fstr);
650rb_fstring_foreach_with_replace(
int (*callback)(
VALUE *str,
void *data),
void *data)
652 if (fstring_table_obj) {
653 rb_concurrent_set_foreach_with_replace(fstring_table_obj, callback, data);
661 RBASIC_SET_FULL_SHAPE_ID((
VALUE)fake_str, ROOT_SHAPE_ID | SHAPE_ID_LAYOUT_OTHER);
674 return (
VALUE)fake_str;
683 return setup_fake_str(fake_str, name,
len, rb_enc_to_index(enc));
694 struct RString fake_str = {RBASIC_INIT};
695 return register_fstring(setup_fake_str(&fake_str,
ptr,
len, ENCINDEX_US_ASCII),
false,
false);
701 struct RString fake_str = {RBASIC_INIT};
702 return register_fstring(rb_setup_fake_str(&fake_str,
ptr,
len, enc),
false,
false);
706rb_fstring_cstr(
const char *
ptr)
708 return rb_fstring_new(
ptr, strlen(
ptr));
712single_byte_optimizable(
VALUE str)
716 case ENCINDEX_ASCII_8BIT:
717 case ENCINDEX_US_ASCII:
739static inline const char *
740search_nonascii(
const char *p,
const char *e)
748#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
749# if SIZEOF_UINTPTR_T == 8
750# define NONASCII_MASK UINT64_C(0x8080808080808080)
751# elif SIZEOF_UINTPTR_T == 4
752# define NONASCII_MASK UINT32_C(0x80808080)
754# error "don't know what to do."
757# if SIZEOF_UINTPTR_T == 8
758# define NONASCII_MASK ((uintptr_t)0x80808080UL << 32 | (uintptr_t)0x80808080UL)
759# elif SIZEOF_UINTPTR_T == 4
760# define NONASCII_MASK 0x80808080UL
762# error "don't know what to do."
766 if (UNALIGNED_WORD_ACCESS || e - p >= SIZEOF_VOIDP) {
767#if !UNALIGNED_WORD_ACCESS
768 if ((uintptr_t)p % SIZEOF_VOIDP) {
769 int l = SIZEOF_VOIDP - (uintptr_t)p % SIZEOF_VOIDP;
774 case 7:
if (p[-7]&0x80)
return p-7;
775 case 6:
if (p[-6]&0x80)
return p-6;
776 case 5:
if (p[-5]&0x80)
return p-5;
777 case 4:
if (p[-4]&0x80)
return p-4;
779 case 3:
if (p[-3]&0x80)
return p-3;
780 case 2:
if (p[-2]&0x80)
return p-2;
781 case 1:
if (p[-1]&0x80)
return p-1;
786#if defined(HAVE_BUILTIN___BUILTIN_ASSUME_ALIGNED) &&! UNALIGNED_WORD_ACCESS
787#define aligned_ptr(value) \
788 __builtin_assume_aligned((value), sizeof(uintptr_t))
790#define aligned_ptr(value) (value)
793 t = (e - (SIZEOF_VOIDP-1));
795 for (;s < t; s +=
sizeof(uintptr_t)) {
797 memcpy(&word, s,
sizeof(word));
798 if (word & NONASCII_MASK) {
799#ifdef WORDS_BIGENDIAN
800 return (
const char *)s + (nlz_intptr(word&NONASCII_MASK)>>3);
802 return (
const char *)s + (ntz_intptr(word&NONASCII_MASK)>>3);
812 case 7:
if (e[-7]&0x80)
return e-7;
813 case 6:
if (e[-6]&0x80)
return e-6;
814 case 5:
if (e[-5]&0x80)
return e-5;
815 case 4:
if (e[-4]&0x80)
return e-4;
817 case 3:
if (e[-3]&0x80)
return e-3;
818 case 2:
if (e[-2]&0x80)
return e-2;
819 case 1:
if (e[-1]&0x80)
return e-1;
827 const char *e = p +
len;
829 if (rb_enc_to_index(enc) == rb_ascii8bit_encindex()) {
831 p = search_nonascii(p, e);
835 if (rb_enc_asciicompat(enc)) {
836 p = search_nonascii(p, e);
839 int ret = rb_enc_precise_mbclen(p, e, enc);
843 p = search_nonascii(p, e);
849 int ret = rb_enc_precise_mbclen(p, e, enc);
865 if (rb_enc_to_index(enc) == rb_ascii8bit_encindex()) {
868 p = search_nonascii(p, e);
872 else if (rb_enc_asciicompat(enc)) {
873 p = search_nonascii(p, e);
879 int ret = rb_enc_precise_mbclen(p, e, enc);
886 p = search_nonascii(p, e);
892 int ret = rb_enc_precise_mbclen(p, e, enc);
917 rb_enc_set_index(str1, rb_enc_get_index(str2));
925rb_enc_cr_str_copy_for_substr(
VALUE dest,
VALUE src)
930 str_enc_copy(dest, src);
931 if (RSTRING_LEN(dest) == 0) {
932 if (!rb_enc_asciicompat(STR_ENC_GET(src)))
943 if (!rb_enc_asciicompat(STR_ENC_GET(src)) ||
944 search_nonascii(RSTRING_PTR(dest),
RSTRING_END(dest)))
955rb_enc_cr_str_exact_copy(
VALUE dest,
VALUE src)
957 str_enc_copy(dest, src);
964 return coderange_scan(RSTRING_PTR(str), RSTRING_LEN(str), enc);
970 return enc_coderange_scan(str, enc);
974rbimpl_enc_str_coderange_scan(
VALUE str)
976 int cr = enc_coderange_scan(str, get_encoding(str));
981#undef rb_enc_str_coderange
988 cr = rbimpl_enc_str_coderange_scan(str);
992#define rb_enc_str_coderange rb_enc_str_coderange_inline
995rb_enc_str_asciicompat(
VALUE str)
998 return rb_str_encindex_fastpath(encindex) || rb_enc_asciicompat(rb_enc_get_from_index(encindex));
1006 return rb_enc_str_asciicompat(str) && is_ascii_string(str);
1017 if (RSTRING_PTR(s) != p || RSTRING_LEN(s) !=
len){
1023str_capacity(
VALUE str,
const int termlen)
1025 if (STR_EMBED_P(str)) {
1026 return str_embed_capa(str) - termlen;
1028 else if (
FL_ANY_RAW(str, STR_SHARED|STR_NOFREE)) {
1032 return RSTRING(str)->as.heap.aux.capa;
1039 return str_capacity(str, TERM_LEN(str));
1043must_not_null(
const char *
ptr)
1046 rb_raise(rb_eArgError,
"NULL pointer given");
1051str_alloc_embed(
VALUE klass,
size_t capa)
1053 size_t size = rb_str_embed_size(
capa, 0);
1060 str->as.embed.ary[0] = 0;
1066str_alloc_heap(
VALUE klass)
1071 str->as.heap.aux.capa = 0;
1072 str->as.heap.ptr = NULL;
1078empty_str_alloc(
VALUE klass)
1080 RUBY_DTRACE_CREATE_HOOK(STRING, 0);
1081 VALUE str = str_alloc_embed(klass, 0);
1082 memset(
RSTRING(str)->
as.embed.ary, 0, str_embed_capa(str));
1093 rb_raise(rb_eArgError,
"negative string size (or size too big)");
1097 enc = rb_ascii8bit_encoding();
1100 RUBY_DTRACE_CREATE_HOOK(STRING,
len);
1102 int termlen = rb_enc_mbminlen(enc);
1104 if (STR_EMBEDDABLE_P(
len, termlen)) {
1105 str = str_alloc_embed(klass,
len + termlen);
1111 str = str_alloc_heap(klass);
1117 rb_xmalloc_mul_add_mul(
sizeof(
char),
len,
sizeof(
char), termlen);
1120 rb_enc_raw_set(str, enc);
1123 memcpy(RSTRING_PTR(str),
ptr,
len);
1126 memset(RSTRING_PTR(str), 0,
len);
1129 STR_SET_LEN(str,
len);
1130 TERM_FILL(RSTRING_PTR(str) +
len, termlen);
1137 return str_enc_new(klass,
ptr,
len, rb_ascii8bit_encoding());
1172 __msan_unpoison_string(
ptr);
1192 if (rb_enc_mbminlen(enc) != 1) {
1193 rb_raise(rb_eArgError,
"wchar encoding given");
1195 return rb_enc_str_new(
ptr, strlen(
ptr), enc);
1204 rb_raise(rb_eArgError,
"negative string size (or size too big)");
1208 str = str_enc_new(klass,
ptr,
len, rb_enc_from_index(encindex));
1211 RUBY_DTRACE_CREATE_HOOK(STRING,
len);
1212 str = str_alloc_heap(klass);
1216 RBASIC(str)->flags |= STR_NOFREE;
1217 rb_enc_associate_index(str, encindex);
1234 RUBY_DTRACE_CREATE_HOOK(STRING,
len);
1241 rb_enc_associate_index(str, encindex);
1265 int ecflags,
VALUE ecopts);
1270 int encidx = rb_enc_to_index(enc);
1271 if (rb_enc_get_index(str) == encidx)
1272 return is_ascii_string(str);
1283 if (!to)
return str;
1284 if (!from) from = rb_enc_get(str);
1285 if (from == to)
return str;
1286 if ((rb_enc_asciicompat(to) && is_enc_ascii_string(str, from)) ||
1287 rb_is_ascii8bit_enc(to)) {
1288 if (STR_ENC_GET(str) != to) {
1290 rb_enc_associate(str, to);
1297 from, to, ecflags, ecopts);
1298 if (
NIL_P(newstr)) {
1311 olen = RSTRING_LEN(newstr);
1312 if (ofs < -olen || olen < ofs)
1314 if (ofs < 0) ofs += olen;
1316 STR_SET_LEN(newstr, ofs);
1320 rb_str_modify(newstr);
1321 return str_cat_conv_enc_opts(newstr, ofs,
ptr,
len, from,
1329 STR_SET_LEN(str, 0);
1330 rb_enc_associate(str, enc);
1338 int ecflags,
VALUE ecopts)
1343 VALUE econv_wrapper;
1344 const unsigned char *start, *sp;
1345 unsigned char *dest, *dp;
1346 size_t converted_output = (size_t)ofs;
1351 RBASIC_CLEAR_CLASS(econv_wrapper);
1353 if (!ec)
return Qnil;
1356 sp = (
unsigned char*)
ptr;
1358 while ((dest = (
unsigned char*)RSTRING_PTR(newstr)),
1359 (dp = dest + converted_output),
1363 size_t converted_input = sp - start;
1364 size_t rest =
len - converted_input;
1365 converted_output = dp - dest;
1367 if (converted_input && converted_output &&
1369 rest = (rest * converted_output) / converted_input;
1374 olen += rest < 2 ? 2 : rest;
1375 rb_str_resize(newstr, olen);
1382 len = dp - (
unsigned char*)RSTRING_PTR(newstr);
1384 rb_enc_associate(newstr, to);
1403 const int eidx = rb_enc_to_index(eenc);
1406 return rb_enc_str_new(
ptr,
len, eenc);
1410 if ((eidx == rb_ascii8bit_encindex()) ||
1411 (eidx == rb_usascii_encindex() && search_nonascii(
ptr,
ptr +
len))) {
1415 ienc = rb_default_internal_encoding();
1416 if (!ienc || eenc == ienc) {
1417 return rb_enc_str_new(
ptr,
len, eenc);
1421 if ((eidx == rb_ascii8bit_encindex()) ||
1422 (eidx == rb_usascii_encindex()) ||
1423 (rb_enc_asciicompat(eenc) && !search_nonascii(
ptr,
ptr +
len))) {
1424 return rb_enc_str_new(
ptr,
len, ienc);
1427 str = rb_enc_str_new(NULL, 0, ienc);
1430 if (
NIL_P(rb_str_cat_conv_enc_opts(str, 0,
ptr,
len, eenc, 0,
Qnil))) {
1431 rb_str_initialize(str,
ptr,
len, eenc);
1439 int eidx = rb_enc_to_index(eenc);
1440 if (eidx == rb_usascii_encindex() &&
1441 !is_ascii_string(str)) {
1442 rb_enc_associate_index(str, rb_ascii8bit_encindex());
1445 rb_enc_associate_index(str, eidx);
1504str_replace_shared_without_enc(
VALUE str2,
VALUE str)
1506 const int termlen = TERM_LEN(str);
1511 if (str_embed_capa(str2) >=
len + termlen) {
1512 char *ptr2 =
RSTRING(str2)->as.embed.ary;
1513 STR_SET_EMBED(str2);
1514 memcpy(ptr2, RSTRING_PTR(str),
len);
1515 TERM_FILL(ptr2+
len, termlen);
1519 if (STR_SHARED_P(str)) {
1520 root =
RSTRING(str)->as.heap.aux.shared;
1529 if (!STR_EMBED_P(str2) && !
FL_TEST_RAW(str2, STR_SHARED|STR_NOFREE)) {
1531 rb_fatal(
"about to free a possible shared root");
1533 char *ptr2 = STR_HEAP_PTR(str2);
1535 SIZED_FREE_N(ptr2, STR_HEAP_SIZE(str2));
1538 FL_SET(str2, STR_NOEMBED);
1540 STR_SET_SHARED(str2, root);
1543 STR_SET_LEN(str2,
len);
1551 str_replace_shared_without_enc(str2, str);
1552 rb_enc_cr_str_exact_copy(str2, str);
1559 return str_replace_shared(str_alloc_heap(klass), str);
1576rb_str_new_frozen_String(
VALUE orig)
1584rb_str_frozen_bare_string(
VALUE orig)
1586 if (RB_LIKELY(BARE_STRING_P(orig) &&
OBJ_FROZEN_RAW(orig)))
return orig;
1591rb_str_tmp_frozen_acquire(
VALUE orig)
1594 return str_new_frozen_buffer(0, orig, FALSE);
1601 if (STR_SHARED_P(orig) && !STR_EMBED_P(
RSTRING(orig)->
as.heap.aux.shared))
return rb_str_tmp_frozen_acquire(orig);
1603 VALUE str = str_alloc_heap(0);
1606 FL_SET(str, STR_SHARED_ROOT);
1608 size_t capa = str_capacity(orig, TERM_LEN(orig));
1614 if (STR_EMBED_P(orig) ||
FL_TEST_RAW(orig, STR_SHARED | STR_SHARED_ROOT | RSTRING_FSTR)) {
1615 RSTRING(str)->as.heap.ptr = rb_xmalloc_mul_add_mul(
sizeof(
char),
capa,
sizeof(
char), TERM_LEN(orig));
1622 RBASIC(str)->flags |=
RBASIC(orig)->flags & STR_NOFREE;
1623 RBASIC(orig)->flags &= ~STR_NOFREE;
1624 STR_SET_SHARED(orig, str);
1635 RSTRING(str)->as.heap.aux.capa =
capa + (TERM_LEN(orig) - TERM_LEN(str));
1643 rb_str_tmp_frozen_release(orig, tmp);
1647rb_str_tmp_frozen_release(
VALUE orig,
VALUE tmp)
1652 if (STR_EMBED_P(tmp)) {
1655 else if (
FL_TEST_RAW(orig, STR_SHARED | STR_TMPLOCK) == STR_SHARED &&
1661 RUBY_ASSERT(RSTRING_LEN(orig) == RSTRING_LEN(tmp));
1665 RSTRING(orig)->as.heap.aux.capa =
RSTRING(tmp)->as.heap.aux.capa + TERM_LEN(tmp) - TERM_LEN(orig);
1666 RBASIC(orig)->flags |=
RBASIC(tmp)->flags & STR_NOFREE;
1671 STR_SET_LEN(tmp, 0);
1679 return str_new_frozen_buffer(klass, orig, TRUE);
1688heap_str_make_shared(
VALUE klass,
VALUE orig,
int termlen)
1694 VALUE str = str_alloc_heap(klass);
1695 STR_SET_LEN(str, RSTRING_LEN(orig));
1696 RSTRING(str)->as.heap.ptr = RSTRING_PTR(orig);
1697 RSTRING(str)->as.heap.aux.capa =
RSTRING(orig)->as.heap.aux.capa + TERM_LEN(orig) - termlen;
1698 RBASIC(str)->flags |=
RBASIC(orig)->flags & STR_NOFREE;
1699 RBASIC(orig)->flags &= ~STR_NOFREE;
1700 STR_SET_SHARED(orig, str);
1707str_new_frozen_buffer(
VALUE klass,
VALUE orig,
int copy_encoding)
1712 rb_encoding *enc = copy_encoding ? STR_ENC_GET(orig) : rb_ascii8bit_encoding();
1713 int termlen = copy_encoding ? TERM_LEN(orig) : 1;
1715 if (STR_EMBED_P(orig) || STR_EMBEDDABLE_P(
len, termlen)) {
1716 str = str_enc_new(klass, RSTRING_PTR(orig),
len, enc);
1729 if ((ofs > 0) || (rest > 0) ||
1732 str = str_new_shared(klass,
shared);
1734 RSTRING(str)->as.heap.ptr += ofs;
1735 STR_SET_LEN(str, RSTRING_LEN(str) - (ofs + rest));
1743 else if (STR_EMBEDDABLE_P(RSTRING_LEN(orig), TERM_LEN(orig))) {
1744 str = str_alloc_embed(klass, RSTRING_LEN(orig) + TERM_LEN(orig));
1746 memcpy(RSTRING_PTR(str), RSTRING_PTR(orig), RSTRING_LEN(orig));
1747 STR_SET_LEN(str, RSTRING_LEN(orig));
1753 str = str_new(klass, RSTRING_PTR(orig), RSTRING_LEN(orig));
1756 str = heap_str_make_shared(klass, orig, termlen);
1761 if (copy_encoding) rb_enc_cr_str_exact_copy(str, orig);
1773str_new_empty_String(
VALUE str)
1776 rb_enc_copy(v, str);
1780#define STR_BUF_MIN_SIZE 63
1785 if (STR_EMBEDDABLE_P(
capa, 1)) {
1793 RSTRING(str)->as.heap.ptr[0] =
'\0';
1813 return str_new(0, 0,
len);
1819 if (STR_EMBED_P(str)) {
1820 RB_DEBUG_COUNTER_INC(obj_str_embed);
1822 else if (
FL_TEST(str, STR_SHARED | STR_NOFREE)) {
1823 (void)RB_DEBUG_COUNTER_INC_IF(obj_str_shared,
FL_TEST(str, STR_SHARED));
1824 (void)RB_DEBUG_COUNTER_INC_IF(obj_str_shared,
FL_TEST(str, STR_NOFREE));
1827 RB_DEBUG_COUNTER_INC(obj_str_ptr);
1828 SIZED_FREE_N(STR_HEAP_PTR(str), STR_HEAP_SIZE(str));
1833rb_str_memsize(
VALUE str)
1835 if (
FL_TEST(str, STR_NOEMBED|STR_SHARED|STR_NOFREE) == STR_NOEMBED) {
1836 return STR_HEAP_SIZE(str);
1846 return rb_convert_type_with_id(str,
T_STRING,
"String", idTo_str);
1849static inline void str_discard(
VALUE str);
1850static void str_shared_replace(
VALUE str,
VALUE str2);
1855 if (str != str2) str_shared_replace(str, str2);
1866 enc = STR_ENC_GET(str2);
1869 termlen = rb_enc_mbminlen(enc);
1871 STR_SET_LEN(str, RSTRING_LEN(str2));
1873 if (str_embed_capa(str) >= RSTRING_LEN(str2) + termlen) {
1875 memcpy(RSTRING_PTR(str), RSTRING_PTR(str2), (
size_t)RSTRING_LEN(str2) + termlen);
1878 if (STR_EMBED_P(str2)) {
1883 char *new_ptr =
ALLOC_N(
char,
len + termlen);
1884 memcpy(new_ptr,
RSTRING(str2)->
as.embed.ary,
len + termlen);
1885 RSTRING(str2)->as.heap.ptr = new_ptr;
1886 STR_SET_LEN(str2,
len);
1888 STR_SET_NOEMBED(str2);
1891 STR_SET_NOEMBED(str);
1893 RSTRING(str)->as.heap.ptr = RSTRING_PTR(str2);
1895 if (
FL_TEST(str2, STR_SHARED)) {
1897 STR_SET_SHARED(str,
shared);
1900 RSTRING(str)->as.heap.aux.capa =
RSTRING(str2)->as.heap.aux.capa;
1904 STR_SET_EMBED(str2);
1905 RSTRING_PTR(str2)[0] = 0;
1906 STR_SET_LEN(str2, 0);
1911 rb_enc_raw_set(str, enc);
1924 return rb_obj_as_string_result(str, obj);
1940 len = RSTRING_LEN(str2);
1941 if (STR_SHARED_P(str2)) {
1944 STR_SET_NOEMBED(str);
1945 STR_SET_LEN(str,
len);
1946 RSTRING(str)->as.heap.ptr = RSTRING_PTR(str2);
1947 STR_SET_SHARED(str,
shared);
1948 rb_enc_cr_str_exact_copy(str, str2);
1951 str_replace_shared(str, str2);
1960 size_t size = rb_str_embed_size(
capa, 0);
1976 str->as.heap.aux.capa = 0;
1977 str->as.heap.ptr = NULL;
1987 encidx = rb_enc_get_index(str);
1988 flags &= ~ENCODING_MASK;
1991 if (encidx) rb_enc_associate_index(dup, encidx);
2005 STR_SET_LEN(dup, RSTRING_LEN(str));
2006 str_duplicate_setup_encoding(str, dup, flags);
2015 root =
RSTRING(str)->as.heap.aux.shared;
2018 root = str = str_new_frozen(klass, str);
2024 RSTRING(dup)->as.heap.ptr = RSTRING_PTR(str);
2026 STR_SET_SHARED(dup, root);
2027 flags |= RSTRING_NOEMBED | STR_SHARED;
2029 STR_SET_LEN(dup, RSTRING_LEN(str));
2030 str_duplicate_setup_encoding(str, dup, flags);
2037 if (STR_EMBED_P(str) && rb_str_embed_size(RSTRING_LEN(str), 1) <= STR_COPY_MAX_EMBED_SIZE) {
2038 dup = str_alloc_embed(klass, RSTRING_LEN(str) + TERM_LEN(str));
2040 str_duplicate_setup_embed(klass, str, dup);
2043 dup = str_alloc_heap(klass);
2045 str_duplicate_setup_heap(klass, str, dup);
2059rb_str_dup_m(
VALUE str)
2061 if (LIKELY(BARE_STRING_P(str))) {
2072 RUBY_DTRACE_CREATE_HOOK(STRING, RSTRING_LEN(str));
2079 RUBY_DTRACE_CREATE_HOOK(STRING, RSTRING_LEN(str));
2083 new_str = ec_str_alloc_embed(ec, klass, RSTRING_LEN(str) + TERM_LEN(str));
2084 str_duplicate_setup_embed(klass, str, new_str);
2087 new_str = ec_str_alloc_heap(ec, klass);
2088 str_duplicate_setup_heap(klass, str, new_str);
2098rb_zjit_str_resurrect_fastpath(
VALUE str,
bool chilled,
size_t *size_out,
2100 rb_len_t *len_out,
size_t *byte_size_out)
2104 if (!STR_EMBED_P(str))
return false;
2108 size_t size = rb_str_embed_size(
len + termlen, 0);
2109 if (!rb_gc_size_allocatable_p(size))
return false;
2117 flags &= ~FL_FREEZE;
2119 if (chilled) flags |= STR_CHILLED;
2124 *byte_size_out = (size_t)(
len + termlen);
2130rb_str_with_debug_created_info(
VALUE str,
VALUE path,
int line)
2132 VALUE debug_info = rb_ary_new_from_args(2, path,
INT2FIX(line));
2156 static ID keyword_ids[2];
2157 VALUE orig, opt, venc, vcapa;
2162 if (!keyword_ids[0]) {
2163 keyword_ids[0] = rb_id_encoding();
2164 CONST_ID(keyword_ids[1],
"capacity");
2172 if (!NIL_OR_UNDEF_P(venc)) {
2173 enc = rb_to_encoding(venc);
2175 if (!NIL_OR_UNDEF_P(vcapa)) {
2180 if (
capa < STR_BUF_MIN_SIZE) {
2181 capa = STR_BUF_MIN_SIZE;
2185 len = RSTRING_LEN(orig);
2189 if (orig == str) n = 0;
2191 termlen = enc ? rb_enc_mbminlen(enc) : TERM_LEN(n == 1 ? orig : str);
2192 str_modifiable(str);
2193 if (STR_EMBED_P(str) ||
FL_TEST(str, STR_SHARED|STR_NOFREE)) {
2195 const size_t size = (size_t)
capa + termlen;
2196 const char *
const old_ptr = RSTRING_PTR(str);
2197 const size_t osize = RSTRING_LEN(str) + TERM_LEN(str);
2198 char *new_ptr =
ALLOC_N(
char, size);
2200 memcpy(new_ptr, old_ptr, osize < size ? osize : size);
2202 RSTRING(str)->as.heap.ptr = new_ptr;
2204 else if (STR_HEAP_SIZE(str) != (
size_t)
capa + termlen) {
2205 SIZED_REALLOC_N(
RSTRING(str)->
as.heap.ptr,
char,
2206 (
size_t)
capa + termlen, STR_HEAP_SIZE(str));
2208 STR_SET_LEN(str,
len);
2211 memcpy(
RSTRING(str)->
as.heap.ptr, RSTRING_PTR(orig),
len);
2212 if (!enc || rb_enc_get(orig) == enc) {
2213 rb_enc_cr_str_exact_copy(str, orig);
2217 FL_SET(str, STR_NOEMBED);
2224 str_modifiable(str);
2225 if (NIL_OR_UNDEF_P(vcapa)) {
2226 rb_enc_associate(str, enc);
2230 rb_enc_raw_set(str, enc);
2243rb_str_s_new(
int argc,
VALUE *argv,
VALUE klass)
2249 static ID keyword_ids[2];
2259 keyword_ids[0] = rb_id_encoding();
2260 CONST_ID(keyword_ids[1],
"capacity");
2262 encoding = kwargs[0];
2263 capacity = kwargs[1];
2272 if (UNDEF_P(encoding)) {
2274 encoding = rb_obj_encoding(orig);
2278 if (!UNDEF_P(encoding)) {
2279 enc = rb_to_encoding(encoding);
2283 if (UNDEF_P(capacity)) {
2285 VALUE empty_str = str_new(klass,
"", 0);
2287 rb_enc_associate(empty_str, enc);
2291 VALUE copy = str_duplicate(klass, orig);
2292 rb_enc_associate(copy, enc);
2305 if (orig_capa >
capa) {
2310 VALUE str = str_enc_new(klass, NULL,
capa, enc);
2311 STR_SET_LEN(str, 0);
2322#define is_utf8_lead_byte(c) (((c)&0xC0) != 0x80)
2337static inline uintptr_t
2338count_utf8_lead_bytes_with_word(
const uintptr_t *s)
2343 d = (d>>6) | (~d>>7);
2344 d &= NONASCII_MASK >> 7;
2347#if defined(HAVE_BUILTIN___BUILTIN_POPCOUNT) && defined(__POPCNT__)
2349 return rb_popcount_intptr(d);
2353# if SIZEOF_VOIDP == 8
2362enc_strlen(
const char *p,
const char *e,
rb_encoding *enc,
int cr)
2369 return diff / rb_enc_mbminlen(enc) + !!(diff % rb_enc_mbminlen(enc));
2374 if ((
int)
sizeof(uintptr_t) * 2 < e - p) {
2375 const uintptr_t *s, *t;
2376 const uintptr_t lowbits =
sizeof(uintptr_t) - 1;
2377 s = (
const uintptr_t*)(~lowbits & ((uintptr_t)p + lowbits));
2378 t = (
const uintptr_t*)(~lowbits & (uintptr_t)e);
2379 while (p < (
const char *)s) {
2380 if (is_utf8_lead_byte(*p))
len++;
2384 len += count_utf8_lead_bytes_with_word(s);
2387 p = (
const char *)s;
2390 if (is_utf8_lead_byte(*p))
len++;
2396 else if (rb_enc_asciicompat(enc)) {
2400 q = search_nonascii(p, e);
2405 p += rb_enc_fast_mbclen(p, e, enc);
2411 q = search_nonascii(p, e);
2416 p += rb_enc_mbclen(p, e, enc);
2423 for (c=0; p<e; c++) {
2424 p += rb_enc_mbclen(p, e, enc);
2439rb_enc_strlen_cr(
const char *p,
const char *e,
rb_encoding *enc,
int *cr)
2448 return diff / rb_enc_mbminlen(enc) + !!(diff % rb_enc_mbminlen(enc));
2450 else if (rb_enc_asciicompat(enc)) {
2453 q = search_nonascii(p, e);
2460 ret = rb_enc_precise_mbclen(p, e, enc);
2475 for (c=0; p<e; c++) {
2476 ret = rb_enc_precise_mbclen(p, e, enc);
2483 if (p + rb_enc_mbminlen(enc) <= e)
2484 p += rb_enc_mbminlen(enc);
2500 if (single_byte_optimizable(str))
return RSTRING_LEN(str);
2501 if (!enc) enc = STR_ENC_GET(str);
2502 p = RSTRING_PTR(str);
2507 rb_len_t n = rb_enc_strlen_cr(p, e, enc, &cr);
2512 return enc_strlen(p, e, enc, cr);
2519 return str_strlen(str, NULL);
2533 return LEN2NUM(str_strlen(str, NULL));
2545rb_str_bytesize(
VALUE str)
2547 return LEN2NUM(RSTRING_LEN(str));
2564rb_str_empty(
VALUE str)
2566 return RBOOL(RSTRING_LEN(str) == 0);
2585 const char *ptr1, *ptr2;
2591 enc = rb_enc_check_str(str1, str2);
2594 termlen = rb_enc_mbminlen(enc);
2596 rb_raise(rb_eArgError,
"string size too big");
2598 str3 = str_enc_new(
rb_cString, 0, len1+len2, enc);
2599 ptr3 = RSTRING_PTR(str3);
2600 memcpy(ptr3, ptr1, len1);
2601 memcpy(ptr3+len1, ptr2, len2);
2602 TERM_FILL(&ptr3[len1+len2], termlen);
2618 MAYBE_UNUSED(
char) *ptr1, *ptr2;
2621 int enc1 = rb_enc_get_index(str1);
2622 int enc2 = rb_enc_get_index(str2);
2627 else if (enc2 < 0) {
2630 else if (enc1 != enc2) {
2667 rb_enc_copy(str2, str);
2672 rb_raise(rb_eArgError,
"negative argument");
2674 if (RSTRING_LEN(str) == 1 && RSTRING_PTR(str)[0] == 0) {
2675 if (STR_EMBEDDABLE_P(
len, 1)) {
2677 memset(RSTRING_PTR(str2), 0,
len + 1);
2684 STR_SET_LEN(str2,
len);
2685 rb_enc_copy(str2, str);
2689 rb_raise(rb_eArgError,
"argument too big");
2692 len *= RSTRING_LEN(str);
2693 termlen = TERM_LEN(str);
2695 ptr2 = RSTRING_PTR(str2);
2697 n = RSTRING_LEN(str);
2698 memcpy(ptr2, RSTRING_PTR(str), n);
2699 while (n <=
len/2) {
2700 memcpy(ptr2 + n, ptr2, n);
2703 memcpy(ptr2 + n, ptr2,
len-n);
2705 STR_SET_LEN(str2,
len);
2706 TERM_FILL(&ptr2[
len], termlen);
2707 rb_enc_cr_str_copy_for_substr(str2, str);
2746rb_check_lockedtmp(
VALUE str)
2748 if (
FL_TEST(str, STR_TMPLOCK)) {
2755#define STR_UNMODIFIABLE_MASK (FL_FREEZE | STR_TMPLOCK | STR_CHILLED)
2757str_modifiable(
VALUE str)
2761 if (RB_UNLIKELY(
FL_ANY_RAW(str, STR_UNMODIFIABLE_MASK))) {
2762 if (CHILLED_STRING_P(str)) {
2763 CHILLED_STRING_MUTATED(str);
2765 rb_check_lockedtmp(str);
2766 rb_check_frozen(str);
2771str_dependent_p(
VALUE str)
2773 if (STR_EMBED_P(str) || !
FL_TEST(str, STR_SHARED|STR_NOFREE)) {
2783#define STR_DEPENDANT_MASK (STR_UNMODIFIABLE_MASK | STR_SHARED | STR_NOFREE)
2785str_independent(
VALUE str)
2789 if (RB_UNLIKELY(
FL_ANY_RAW(str, STR_DEPENDANT_MASK))) {
2790 str_modifiable(str);
2791 return !str_dependent_p(str);
2807 if (!STR_EMBED_P(str) && str_embed_capa(str) >=
capa + termlen) {
2812 STR_SET_LEN(str,
len);
2817 oldptr = RSTRING_PTR(str);
2819 memcpy(
ptr, oldptr,
len);
2821 if (
FL_TEST_RAW(str, STR_NOEMBED|STR_NOFREE|STR_SHARED) == STR_NOEMBED) {
2822 SIZED_FREE_N(oldptr, STR_HEAP_SIZE(str));
2824 STR_SET_NOEMBED(str);
2825 FL_UNSET(str, STR_SHARED|STR_NOFREE);
2826 TERM_FILL(
ptr +
len, termlen);
2828 STR_SET_LEN(str,
len);
2835 if (!str_independent(str))
2836 str_make_independent(str);
2845 int termlen = TERM_LEN(str);
2849 rb_raise(rb_eArgError,
"negative expanding string size");
2852 rb_raise(rb_eArgError,
"string size too big");
2855 if (!str_independent(str)) {
2856 str_make_independent_expand(str,
len, expand, termlen);
2858 else if (expand > 0) {
2859 RESIZE_CAPA_TERM(str,
len + expand, termlen);
2866str_modify_keep_cr(
VALUE str)
2868 if (!str_independent(str))
2869 str_make_independent(str);
2876str_discard(
VALUE str)
2878 str_modifiable(str);
2879 if (!STR_EMBED_P(str) && !
FL_TEST(str, STR_SHARED|STR_NOFREE)) {
2880 SIZED_FREE_N(STR_HEAP_PTR(str), STR_HEAP_SIZE(str));
2881 RSTRING(str)->as.heap.ptr = 0;
2882 STR_SET_LEN(str, 0);
2889 int encindex = rb_enc_get_index(str);
2891 if (RB_UNLIKELY(encindex == -1)) {
2895 if (RB_LIKELY(rb_str_encindex_fastpath(encindex))) {
2900 if (!rb_enc_asciicompat(enc)) {
2922 return RSTRING_PTR(str);
2928 const char *e = s +
len;
2930 for (; s + minlen <= e; s += rb_enc_mbclen(s, e, enc)) {
2931 if (zero_filled(s, minlen))
return s;
2942 if (str_dependent_p(str)) {
2943 if (!zero_filled(s +
len, termlen))
2944 str_make_independent_expand(str,
len, 0L, termlen);
2947 TERM_FILL(s +
len, termlen);
2950 return RSTRING_PTR(str);
2954rb_str_change_terminator_length(
VALUE str,
const int oldtermlen,
const int termlen)
2956 rb_len_t capa = str_capacity(str, oldtermlen) + oldtermlen;
2961 rb_check_lockedtmp(str);
2962 str_make_independent_expand(str,
len, 0L, termlen);
2964 else if (str_dependent_p(str)) {
2965 if (termlen > oldtermlen)
2966 str_make_independent_expand(str,
len, 0L, termlen);
2969 if (!STR_EMBED_P(str)) {
2974 if (termlen > oldtermlen) {
2975 TERM_FILL(RSTRING_PTR(str) +
len, termlen);
2983str_null_check(
VALUE str,
int *w)
2985 char *s = RSTRING_PTR(str);
2989 if (RB_UNLIKELY(!rb_str_enc_fastpath(str))) {
2991 minlen = rb_enc_mbminlen(enc);
2995 if (str_null_char(s,
len, minlen, enc)) {
2998 return str_fill_term(str, s,
len, minlen);
3003 if (!s || memchr(s, 0,
len)) {
3007 s = str_fill_term(str, s,
len, minlen);
3012static char *str_to_cstr(
VALUE str);
3015rb_str_null_check(
VALUE str)
3023 if (RB_LIKELY(rb_str_enc_fastpath(str))) {
3024 if (!s || memchr(s, 0,
len)) {
3025 rb_raise(rb_eArgError,
"string contains null byte");
3036rb_str_to_cstr(
VALUE str)
3039 return str_null_check(str, &w);
3046 return str_to_cstr(str);
3050str_to_cstr(
VALUE str)
3053 char *s = str_null_check(str, &w);
3056 rb_raise(rb_eArgError,
"string contains null char");
3058 rb_raise(rb_eArgError,
"string contains null byte");
3064rb_str_fill_terminator(
VALUE str,
const int newminlen)
3066 char *s = RSTRING_PTR(str);
3068 return str_fill_term(str, s,
len, newminlen);
3074 str = rb_check_convert_type_with_id(str,
T_STRING,
"String", idTo_str);
3109 else if (rb_enc_asciicompat(enc)) {
3110 const char *p2, *e2;
3113 while (p < e && 0 < nth) {
3119 p2 = search_nonascii(p, e2);
3127 n = rb_enc_mbclen(p, e, enc);
3138 while (p < e && nth--) {
3139 p += rb_enc_mbclen(p, e, enc);
3150 return str_nth_len(p, e, &nth, enc);
3159 p = str_nth_len(p, e, &nth, enc);
3170 const char *pp = str_nth(p, e, nth, enc, singlebyte);
3171 if (!pp)
return e - p;
3178 return str_offset(RSTRING_PTR(str),
RSTRING_END(str), pos,
3179 STR_ENC_GET(str), single_byte_optimizable(str));
3184str_utf8_nth(
const char *p,
const char *e,
rb_len_t *nthp)
3187 if ((
int)SIZEOF_VOIDP * 2 < e - p && (
int)SIZEOF_VOIDP * 2 < nth) {
3188 const uintptr_t *s, *t;
3189 const uintptr_t lowbits = SIZEOF_VOIDP - 1;
3190 s = (
const uintptr_t*)(~lowbits & ((uintptr_t)p + lowbits));
3191 t = (
const uintptr_t*)(~lowbits & (uintptr_t)e);
3192 while (p < (
const char *)s) {
3193 if (is_utf8_lead_byte(*p)) nth--;
3197 nth -= count_utf8_lead_bytes_with_word(s);
3199 }
while (s < t && (
int)SIZEOF_VOIDP <= nth);
3203 if (is_utf8_lead_byte(*p)) {
3204 if (nth == 0)
break;
3214str_utf8_offset(
const char *p,
const char *e,
rb_len_t nth)
3216 const char *pp = str_utf8_nth(p, e, &nth);
3225 if (single_byte_optimizable(str) || pos < 0)
3228 const char *p = RSTRING_PTR(str);
3229 return enc_strlen(p, p + pos, STR_ENC_GET(str),
ENC_CODERANGE(str));
3242 const int termlen = TERM_LEN(str);
3243 if (!SHARABLE_SUBSTRING_P(str, beg,
len)) {
3244 str2 = rb_enc_str_new(RSTRING_PTR(str) + beg,
len, rb_str_enc_get(str));
3254 const bool root_available = STR_SHARED_P(str) ||
3256 const size_t max_embed_size = root_available ?
3257 rb_gc_size_slot_size(
sizeof(
struct RString)) : STR_COPY_MAX_EMBED_SIZE;
3258 const size_t embed_size = rb_str_embed_size(
len, termlen);
3260 if (embed_size <= max_embed_size && rb_gc_size_allocatable_p(embed_size)) {
3262 char *ptr2 =
RSTRING(str2)->as.embed.ary;
3263 memcpy(ptr2, RSTRING_PTR(str) + beg,
len);
3264 TERM_FILL(ptr2 +
len, termlen);
3266 STR_SET_LEN(str2,
len);
3275 str_replace_shared(str2, str);
3281 RSTRING(str2)->as.heap.ptr += beg;
3282 if (RSTRING_LEN(str2) >
len) {
3283 STR_SET_LEN(str2,
len);
3293 VALUE str2 = str_subseq(str, beg,
len);
3294 rb_enc_cr_str_copy_for_substr(str2, str);
3303 const rb_len_t blen = RSTRING_LEN(str);
3305 const char *p, *s = RSTRING_PTR(str), *e = s + blen;
3307 if (
len < 0)
return 0;
3312 if (single_byte_optimizable(str)) {
3313 if (beg > blen)
return 0;
3316 if (beg < 0)
return 0;
3318 if (
len > blen - beg)
3320 if (
len < 0)
return 0;
3325 if (
len > -beg)
len = -beg;
3329 while (beg-- >
len && (e = rb_enc_prev_char(s, e, e, enc)) != 0);
3332 while (
len-- > 0 && (p = rb_enc_prev_char(s, p, e, enc)) != 0);
3338 slen = str_strlen(str, enc);
3340 if (beg < 0)
return 0;
3342 if (
len == 0)
goto end;
3345 else if (beg > 0 && beg > blen) {
3349 if (beg > str_strlen(str, enc))
return 0;
3354 enc == rb_utf8_encoding()) {
3355 p = str_utf8_nth(s, e, &beg);
3356 if (beg > 0)
return 0;
3357 len = str_utf8_offset(p, e,
len);
3363 p = s + beg * char_sz;
3367 else if (
len * char_sz > e - p)
3372 else if ((p = str_nth_len(s, e, &beg, enc)) == e) {
3373 if (beg > 0)
return 0;
3377 len = str_offset(p, e,
len, enc, 0);
3390 return str_substr(str, beg,
len, TRUE);
3404 if (!p)
return Qnil;
3405 if (!
len && !empty)
return Qnil;
3407 beg = p - RSTRING_PTR(str);
3409 VALUE str2 = str_subseq(str, beg,
len);
3410 rb_enc_cr_str_copy_for_substr(str2, str);
3418 if (CHILLED_STRING_P(str)) {
3423 rb_str_resize(str, RSTRING_LEN(str));
3441 if (
OBJ_FROZEN(str) || CHILLED_STRING_P(str)) {
3484str_uminus(
VALUE str)
3489 return rb_fstring(str);
3493#define rb_str_dup_frozen rb_str_new_frozen
3498 rb_check_frozen(str);
3499 if (
FL_TEST(str, STR_TMPLOCK)) {
3502 FL_SET(str, STR_TMPLOCK);
3509 rb_check_frozen(str);
3510 if (!
FL_TEST(str, STR_TMPLOCK)) {
3530 const int termlen = TERM_LEN(str);
3532 str_modifiable(str);
3533 if (STR_SHARED_P(str)) {
3537 rb_bug(
"probable buffer overflow: %"PRIdLEN
" for %"PRIdLEN,
len,
capa);
3548 else if (
len > RSTRING_LEN(str)) {
3552 const char *
const new_end = RSTRING_PTR(str) +
len;
3562 else if (
len < RSTRING_LEN(str)) {
3570 STR_SET_LEN(str,
len);
3571 TERM_FILL(&RSTRING_PTR(str)[
len], termlen);
3578 rb_raise(rb_eArgError,
"negative string size (or size too big)");
3581 int independent = str_independent(str);
3583 const int termlen = TERM_LEN(str);
3585 if (slen >
len || (termlen != 1 && slen <
len)) {
3591 if (STR_EMBED_P(str)) {
3592 if (
len == slen)
return str;
3593 if (str_embed_capa(str) >=
len + termlen) {
3594 STR_SET_LEN(str,
len);
3598 str_make_independent_expand(str, slen,
len - slen, termlen);
3600 else if (str_embed_capa(str) >=
len + termlen) {
3602 char *
ptr = STR_HEAP_PTR(str);
3604 if (slen >
len) slen =
len;
3607 STR_SET_LEN(str,
len);
3609 SIZED_FREE_N(
ptr,
capa + termlen);
3613 else if (!independent) {
3614 if (
len == slen)
return str;
3615 str_make_independent_expand(str, slen,
len - slen, termlen);
3619 SIZED_REALLOC_N(
RSTRING(str)->
as.heap.ptr,
char,
3620 (
size_t)
len + termlen, STR_HEAP_SIZE(str));
3623 else if (
len == slen)
return str;
3624 STR_SET_LEN(str,
len);
3633 str_modify_keep_cr(str);
3635 const int termlen = TERM_LEN(str);
3639 rb_raise(rb_eArgError,
"string sizes too big");
3649 while (total >
capa) {
3652 RESIZE_CAPA_TERM(str,
capa, termlen);
3660 str_modify_keep_cr(str);
3665 if (
len == 0)
return 0;
3669 const int termlen = TERM_LEN(str);
3672 if (
ptr >= sptr &&
ptr <= sptr + olen) {
3679 rb_raise(rb_eArgError,
"string sizes too big");
3686 while (total >
capa) {
3689 RESIZE_CAPA_TERM(str,
capa, termlen);
3690 sptr = RSTRING_PTR(str);
3695 memcpy(sptr + olen,
ptr,
len);
3696 STR_SET_LEN(str, total);
3697 TERM_FILL(sptr + total, termlen);
3702#define str_buf_cat(str, ptr, len) str_buf_cat4((str), (ptr), len, false)
3703#define str_buf_cat2(str, ptr) str_buf_cat4((str), (ptr), rb_strlen_lit(ptr), false)
3708 if (
len == 0)
return str;
3710 rb_raise(rb_eArgError,
"negative string size (or size too big)");
3712 return str_buf_cat(str,
ptr,
len);
3723rb_str_buf_cat_byte(
VALUE str,
unsigned char byte)
3728 if (UNLIKELY(!str_independent(str))) {
3729 str_make_independent(str);
3733 const int null_terminator_length = 1;
3738 if (UNLIKELY(string_length >
RB_LEN_MAX - 1)) {
3739 rb_raise(rb_eArgError,
"string sizes too big");
3742 rb_len_t string_capacity = str_capacity(str, null_terminator_length);
3748 if (LIKELY(string_capacity >= string_length + 1)) {
3750 sptr[string_length] = byte;
3751 STR_SET_LEN(str, string_length + 1);
3752 TERM_FILL(sptr + string_length + 1, null_terminator_length);
3756 str_buf_cat(str, (
char *)&
byte, 1);
3772 rb_enc_associate_index(str, ENCINDEX_ASCII_8BIT);
3784 int ptr_encindex,
int ptr_cr,
int *ptr_cr_ret)
3793 if (str_encindex == ptr_encindex) {
3795 ptr_cr = coderange_scan(
ptr,
len, rb_enc_from_index(ptr_encindex));
3799 str_enc = rb_enc_from_index(str_encindex);
3800 ptr_enc = rb_enc_from_index(ptr_encindex);
3801 if (!rb_enc_asciicompat(str_enc) || !rb_enc_asciicompat(ptr_enc)) {
3804 if (RSTRING_LEN(str) == 0) {
3807 rb_str_change_terminator_length(str, rb_enc_mbminlen(str_enc), rb_enc_mbminlen(ptr_enc));
3813 ptr_cr = coderange_scan(
ptr,
len, ptr_enc);
3817 str_cr = rb_enc_str_coderange(str);
3822 *ptr_cr_ret = ptr_cr;
3824 if (str_encindex != ptr_encindex &&
3827 str_enc = rb_enc_from_index(str_encindex);
3828 ptr_enc = rb_enc_from_index(ptr_encindex);
3833 res_encindex = str_encindex;
3838 res_encindex = str_encindex;
3842 res_encindex = ptr_encindex;
3847 res_encindex = str_encindex;
3854 res_encindex = str_encindex;
3860 rb_raise(rb_eArgError,
"negative string size (or size too big)");
3862 str_buf_cat(str,
ptr,
len);
3868 rb_enc_inspect_name(str_enc), rb_enc_inspect_name(ptr_enc));
3875 return rb_enc_cr_str_buf_cat(str,
ptr,
len,
3885 if (rb_enc_asciicompat(enc)) {
3886 return rb_enc_cr_str_buf_cat(str,
ptr, strlen(
ptr),
3892 unsigned int c = (
unsigned char)*
ptr;
3893 int len = rb_enc_codelen(c, enc);
3894 rb_enc_mbcput(c, buf, enc);
3895 rb_enc_cr_str_buf_cat(str, buf,
len,
3906 int str2_cr = rb_enc_str_coderange(str2);
3908 if (rb_str_enc_fastpath(str)) {
3912 str_buf_cat4(str, RSTRING_PTR(str2), RSTRING_LEN(str2),
true);
3918 str_buf_cat4(str, RSTRING_PTR(str2), RSTRING_LEN(str2),
true);
3930 rb_enc_cr_str_buf_cat(str, RSTRING_PTR(str2), RSTRING_LEN(str2),
3945rb_str_concat_literals(
size_t num,
const VALUE *strary)
3954 for (i = 0; i < num; ++i) {
len += RSTRING_LEN(strary[i]); }
3956 str_enc_copy_direct(str, strary[0]);
3958 for (i = s; i < num; ++i) {
3959 const VALUE v = strary[i];
3963 if (encidx != ENCINDEX_US_ASCII) {
3965 rb_enc_set_index(str, encidx);
3978rb_str_concat_multi(
int argc,
VALUE *argv,
VALUE str)
3980 str_modifiable(str);
3985 else if (argc > 1) {
3988 rb_enc_copy(arg_str, str);
3989 for (i = 0; i < argc; i++) {
4024rb_str_append_as_bytes(
int argc,
VALUE *argv,
VALUE str)
4030 for (
int index = 0; index < argc; index++) {
4031 VALUE obj = argv[index];
4039 needed_capacity += RSTRING_LEN(obj);
4044 "wrong argument type %"PRIsVALUE
" (expected String or Integer)",
4051 str_ensure_available_capa(str, needed_capacity);
4054 for (
int index = 0; index < argc; index++) {
4055 VALUE obj = argv[index];
4060 argv[index] = obj = rb_int_and(obj,
INT2FIX(0xff));
4061 char byte = (char)(
NUM2INT(obj) & 0xFF);
4075 rb_bug(
"append_as_bytes arguments should have been validated");
4079 STR_SET_LEN(str, RSTRING_LEN(str) + needed_capacity);
4080 TERM_FILL(sptr, TERM_LEN(str));
4085 for (
int index = 0; index < argc; index++) {
4086 VALUE obj = argv[index];
4103 rb_bug(
"append_as_bytes arguments should have been validated");
4181 if (rb_num_to_uint(str2, &code) == 0) {
4194 encidx = rb_ascii8bit_appendable_encoding_index(enc, code);
4197 rb_str_buf_cat_byte(str1, (
unsigned char)code);
4205 switch (
len = rb_enc_codelen(code, enc)) {
4206 case ONIGERR_INVALID_CODE_POINT_VALUE:
4207 rb_raise(
rb_eRangeError,
"invalid codepoint 0x%X in %s", code, rb_enc_name(enc));
4209 case ONIGERR_TOO_BIG_WIDE_CHAR_VALUE:
4215 rb_enc_mbcput(code, buf, enc);
4216 if (rb_enc_precise_mbclen(buf, buf +
len + 1, enc) !=
len) {
4217 rb_raise(
rb_eRangeError,
"invalid codepoint 0x%X in %s", code, rb_enc_name(enc));
4219 rb_str_resize(str1, pos+
len);
4220 memcpy(RSTRING_PTR(str1) + pos, buf,
len);
4233rb_ascii8bit_appendable_encoding_index(
rb_encoding *enc,
unsigned int code)
4235 int encidx = rb_enc_to_index(enc);
4237 if (encidx == ENCINDEX_ASCII_8BIT || encidx == ENCINDEX_US_ASCII) {
4242 if (encidx == ENCINDEX_US_ASCII && code > 127) {
4243 return ENCINDEX_ASCII_8BIT;
4265rb_str_prepend_multi(
int argc,
VALUE *argv,
VALUE str)
4267 str_modifiable(str);
4272 else if (argc > 1) {
4275 rb_enc_copy(arg_str, str);
4276 for (i = 0; i < argc; i++) {
4289 st_index_t precomputed_hash;
4290 memcpy(&precomputed_hash,
RSTRING_END(str) + TERM_LEN(str),
sizeof(precomputed_hash));
4292 RUBY_ASSERT(precomputed_hash == str_do_hash(str));
4293 return precomputed_hash;
4296 return str_do_hash(str);
4303 const char *ptr1, *ptr2;
4306 return (len1 != len2 ||
4308 memcmp(ptr1, ptr2, len1) != 0);
4320rb_str_hash_m(
VALUE str)
4326#define lesser(a,b) (((a)>(b))?(b):(a))
4334 if (RSTRING_LEN(str1) == 0)
return TRUE;
4335 if (RSTRING_LEN(str2) == 0)
return TRUE;
4338 if (idx1 == idx2)
return TRUE;
4339 rc1 = rb_enc_str_coderange(str1);
4340 rc2 = rb_enc_str_coderange(str2);
4343 if (rb_enc_asciicompat(rb_enc_from_index(idx2)))
4347 if (rb_enc_asciicompat(rb_enc_from_index(idx1)))
4357 const char *ptr1, *ptr2;
4360 if (str1 == str2)
return 0;
4363 if (ptr1 == ptr2 || (retval = memcmp(ptr1, ptr2, lesser(len1, len2))) == 0) {
4372 if (len1 > len2)
return 1;
4375 if (retval > 0)
return 1;
4409 if (str1 == str2)
return Qtrue;
4416 return rb_str_eql_internal(str1, str2);
4430 if (str1 == str2)
return Qtrue;
4432 return rb_str_eql_internal(str1, str2);
4470 return rb_invcmp(str1, str2);
4512 return str_casecmp(str1, s);
4520 const char *p1, *p1end, *p2, *p2end;
4522 enc = rb_enc_compatible(str1, str2);
4527 p1 = RSTRING_PTR(str1); p1end =
RSTRING_END(str1);
4528 p2 = RSTRING_PTR(str2); p2end =
RSTRING_END(str2);
4529 if (single_byte_optimizable(str1) && single_byte_optimizable(str2)) {
4530 while (p1 < p1end && p2 < p2end) {
4532 unsigned int c1 =
TOLOWER(*p1 & 0xff);
4533 unsigned int c2 =
TOLOWER(*p2 & 0xff);
4535 return INT2FIX(c1 < c2 ? -1 : 1);
4542 while (p1 < p1end && p2 < p2end) {
4543 int l1, c1 = rb_enc_ascget(p1, p1end, &l1, enc);
4544 int l2, c2 = rb_enc_ascget(p2, p2end, &l2, enc);
4546 if (0 <= c1 && 0 <= c2) {
4550 return INT2FIX(c1 < c2 ? -1 : 1);
4554 l1 = rb_enc_mbclen(p1, p1end, enc);
4555 l2 = rb_enc_mbclen(p2, p2end, enc);
4556 len = l1 < l2 ? l1 : l2;
4557 r = memcmp(p1, p2,
len);
4559 return INT2FIX(r < 0 ? -1 : 1);
4561 return INT2FIX(l1 < l2 ? -1 : 1);
4567 if (p1 == p1end && p2 == p2end)
return INT2FIX(0);
4568 if (p1 == p1end)
return INT2FIX(-1);
4601 return str_casecmp_p(str1, s);
4608 VALUE folded_str1, folded_str2;
4609 VALUE fold_opt = sym_fold;
4611 enc = rb_enc_compatible(str1, str2);
4616 if (is_ascii_string(str1) && is_ascii_string(str2)) {
4617 if (RSTRING_LEN(str1) != RSTRING_LEN(str2))
return Qfalse;
4618 const char *p1 = RSTRING_PTR(str1), *p1end =
RSTRING_END(str1);
4619 const char *p2 = RSTRING_PTR(str2);
4620 while (p1 < p1end) {
4621 if (*p1 != *p2 &&
TOLOWER((
unsigned char)*p1) !=
TOLOWER((
unsigned char)*p2)) {
4630 folded_str1 = rb_str_downcase(1, &fold_opt, str1);
4631 folded_str2 = rb_str_downcase(1, &fold_opt, str2);
4633 return rb_str_eql(folded_str1, folded_str2);
4637strseq_core(
const char *str_ptr,
const char *str_ptr_end,
rb_len_t str_len,
4640 const char *search_start = str_ptr;
4641 rb_len_t pos, search_len = str_len - offset;
4645 pos =
rb_memsearch(sub_ptr, sub_len, search_start, search_len, enc);
4646 if (pos < 0)
return pos;
4648 if (t == search_start + pos)
break;
4649 search_len -= t - search_start;
4650 if (search_len <= 0)
return -1;
4651 offset += t - search_start;
4654 return pos + offset;
4658#define rb_str_index(str, sub, offset) rb_strseq_index(str, sub, offset, 0)
4659#define rb_str_byteindex(str, sub, offset) rb_strseq_index(str, sub, offset, 1)
4664 const char *str_ptr, *str_ptr_end, *sub_ptr;
4668 enc = rb_enc_check(str, sub);
4669 if (is_broken_string(sub))
return -1;
4671 str_ptr = RSTRING_PTR(str);
4673 str_len = RSTRING_LEN(str);
4674 sub_ptr = RSTRING_PTR(sub);
4675 sub_len = RSTRING_LEN(sub);
4677 if (str_len < sub_len)
return -1;
4680 rb_len_t str_len_char, sub_len_char;
4681 int single_byte = single_byte_optimizable(str);
4682 str_len_char = (in_byte || single_byte) ? str_len : str_strlen(str, enc);
4683 sub_len_char = in_byte ? sub_len : str_strlen(sub, enc);
4685 offset += str_len_char;
4686 if (offset < 0)
return -1;
4688 if (str_len_char - offset < sub_len_char)
return -1;
4689 if (!in_byte) offset = str_offset(str_ptr, str_ptr_end, offset, enc, single_byte);
4692 if (sub_len == 0)
return offset;
4695 return strseq_core(str_ptr, str_ptr_end, str_len, sub_ptr, sub_len, offset, enc);
4708rb_str_index_m(
int argc,
VALUE *argv,
VALUE str)
4715 if (
rb_scan_args(argc, argv,
"11", &sub, &initpos) == 2) {
4716 rb_len_t slen = str_strlen(str, enc);
4718 if (pos < 0 ? (pos += slen) < 0 : pos > slen) {
4730 pos = str_offset(RSTRING_PTR(str),
RSTRING_END(str), pos,
4731 enc, single_byte_optimizable(str));
4741 pos = rb_str_index(str, sub, pos);
4757 if (!single_byte_optimizable(str)) {
4758 const char *s = RSTRING_PTR(str);
4760 const char *p = s + pos;
4761 if (!at_char_boundary(s, p, e, rb_enc_get(str))) {
4763 "offset %"PRIdLEN
" does not land on character boundary", pos);
4836rb_str_byteindex_m(
int argc,
VALUE *argv,
VALUE str)
4842 if (
rb_scan_args(argc, argv,
"11", &sub, &initpos) == 2) {
4845 if (pos < 0 ? (pos += slen) < 0 : pos > slen) {
4856 str_ensure_byte_pos(str, pos);
4861 pos = RMATCH_BEG(match, 0);
4867 pos = rb_str_byteindex(str, sub, pos);
4868 if (pos >= 0)
return LEN2NUM(pos);
4876 const char *hit, *adjusted, *sbeg, *e, *t;
4880 sbeg = RSTRING_PTR(str);
4881 slen = RSTRING_LEN(sub);
4882 if (slen == 0)
return s - sbeg;
4884 t = RSTRING_PTR(sub);
4886 searchlen = s - sbeg + 1;
4888 if (s + slen <= e && memcmp(s, t, slen) == 0) {
4893 hit = memrchr(sbeg, c, searchlen);
4896 if (hit != adjusted) {
4897 searchlen = adjusted - sbeg;
4900 if (hit + slen <= e && memcmp(hit, t, slen) == 0)
4902 searchlen = adjusted - sbeg;
4903 }
while (searchlen > 0);
4913 const char *sbeg, *s;
4917 enc = rb_enc_check(str, sub);
4918 if (is_broken_string(sub))
return -1;
4919 singlebyte = single_byte_optimizable(str);
4920 len = singlebyte ? RSTRING_LEN(str) : str_strlen(str, enc);
4921 slen = str_strlen(sub, enc);
4924 if (
len < slen)
return -1;
4926 if (
len - pos < slen) pos =
len - slen;
4927 if (
len == 0)
return pos;
4929 sbeg = RSTRING_PTR(str);
4932 if (RSTRING_LEN(sub) <= RSTRING_LEN(str) &&
4933 memcmp(sbeg, RSTRING_PTR(sub), RSTRING_LEN(sub)) == 0) {
4941 s = str_nth(sbeg,
RSTRING_END(str), pos, enc, singlebyte);
4942 return str_rindex(str, sub, s, enc);
4954rb_str_rindex_m(
int argc,
VALUE *argv,
VALUE str)
4961 if (
rb_scan_args(argc, argv,
"11", &sub, &initpos) == 2) {
4963 if (pos < 0 && (pos +=
len) < 0) {
4969 if (pos >
len) pos =
len;
4977 pos = str_offset(RSTRING_PTR(str),
RSTRING_END(str), pos,
4978 enc, single_byte_optimizable(str));
4988 pos = rb_str_rindex(str, sub, pos);
5001 const char *sbeg, *s;
5004 enc = rb_enc_check(str, sub);
5005 if (is_broken_string(sub))
return -1;
5006 len = RSTRING_LEN(str);
5007 slen = RSTRING_LEN(sub);
5010 if (
len < slen)
return -1;
5011 if (
len - pos < slen) pos =
len - slen;
5012 if (
len == 0)
return pos;
5014 sbeg = RSTRING_PTR(str);
5017 if (memcmp(sbeg, RSTRING_PTR(sub), RSTRING_LEN(sub)) == 0)
5024 return str_rindex(str, sub, s, enc);
5114rb_str_byterindex_m(
int argc,
VALUE *argv,
VALUE str)
5120 if (
rb_scan_args(argc, argv,
"11", &sub, &initpos) == 2) {
5123 if (pos < 0 && (pos +=
len) < 0) {
5129 if (pos >
len) pos =
len;
5132 pos = RSTRING_LEN(str);
5135 str_ensure_byte_pos(str, pos);
5140 pos = RMATCH_BEG(match, 0);
5146 pos = rb_str_byterindex(str, sub, pos);
5147 if (pos >= 0)
return LEN2NUM(pos);
5189 switch (OBJ_BUILTIN_TYPE(y)) {
5241rb_str_match_m(
int argc,
VALUE *argv,
VALUE str)
5248 result =
rb_funcallv(get_pat(re), rb_intern(
"match"), argc, argv);
5279rb_str_match_m_p(
int argc,
VALUE *argv,
VALUE str)
5283 re = get_pat(argv[0]);
5284 return rb_reg_match_p(re, str, argc > 1 ?
NUM2LEN(argv[1]) : 0);
5293static enum neighbor_char
5299 if (rb_enc_mbminlen(enc) > 1) {
5301 int r = rb_enc_precise_mbclen(p, p +
len, enc), c;
5303 return NEIGHBOR_NOT_CHAR;
5305 c = rb_enc_mbc_to_codepoint(p, p +
len, enc) + 1;
5307 if (!l)
return NEIGHBOR_NOT_CHAR;
5308 if (l !=
len)
return NEIGHBOR_WRAPPED;
5309 rb_enc_mbcput(c, p, enc);
5310 r = rb_enc_precise_mbclen(p, p +
len, enc);
5312 return NEIGHBOR_NOT_CHAR;
5314 return NEIGHBOR_FOUND;
5317 for (i =
len-1; 0 <= i && (
unsigned char)p[i] == 0xff; i--)
5320 return NEIGHBOR_WRAPPED;
5321 ++((
unsigned char*)p)[i];
5322 l = rb_enc_precise_mbclen(p, p+
len, enc);
5326 return NEIGHBOR_FOUND;
5329 memset(p+l, 0xff,
len-l);
5335 for (len2 =
len-1; 0 < len2; len2--) {
5336 l2 = rb_enc_precise_mbclen(p, p+len2, enc);
5340 memset(p+len2+1, 0xff,
len-(len2+1));
5345static enum neighbor_char
5350 if (rb_enc_mbminlen(enc) > 1) {
5352 int r = rb_enc_precise_mbclen(p, p +
len, enc), c;
5354 return NEIGHBOR_NOT_CHAR;
5356 c = rb_enc_mbc_to_codepoint(p, p +
len, enc);
5357 if (!c)
return NEIGHBOR_NOT_CHAR;
5360 if (!l)
return NEIGHBOR_NOT_CHAR;
5361 if (l !=
len)
return NEIGHBOR_WRAPPED;
5362 rb_enc_mbcput(c, p, enc);
5363 r = rb_enc_precise_mbclen(p, p +
len, enc);
5365 return NEIGHBOR_NOT_CHAR;
5367 return NEIGHBOR_FOUND;
5370 for (i =
len-1; 0 <= i && (
unsigned char)p[i] == 0; i--)
5373 return NEIGHBOR_WRAPPED;
5374 --((
unsigned char*)p)[i];
5375 l = rb_enc_precise_mbclen(p, p+
len, enc);
5379 return NEIGHBOR_FOUND;
5382 memset(p+l, 0,
len-l);
5388 for (len2 =
len-1; 0 < len2; len2--) {
5389 l2 = rb_enc_precise_mbclen(p, p+len2, enc);
5393 memset(p+len2+1, 0,
len-(len2+1));
5407static enum neighbor_char
5410 enum neighbor_char ret;
5414 char save[ONIGENC_CODE_TO_MBC_MAXLEN];
5418 const int max_gaps = 1;
5420 c = rb_enc_mbc_to_codepoint(p, p+
len, enc);
5422 ctype = ONIGENC_CTYPE_DIGIT;
5424 ctype = ONIGENC_CTYPE_ALPHA;
5426 return NEIGHBOR_NOT_CHAR;
5429 for (
try = 0;
try <= max_gaps; ++
try) {
5430 ret = enc_succ_char(p,
len, enc);
5431 if (ret == NEIGHBOR_FOUND) {
5432 c = rb_enc_mbc_to_codepoint(p, p+
len, enc);
5434 return NEIGHBOR_FOUND;
5441 ret = enc_pred_char(p,
len, enc);
5442 if (ret == NEIGHBOR_FOUND) {
5443 c = rb_enc_mbc_to_codepoint(p, p+
len, enc);
5456 return NEIGHBOR_NOT_CHAR;
5459 if (ctype != ONIGENC_CTYPE_DIGIT) {
5461 return NEIGHBOR_WRAPPED;
5465 enc_succ_char(carry,
len, enc);
5466 return NEIGHBOR_WRAPPED;
5484 str =
rb_str_new(RSTRING_PTR(orig), RSTRING_LEN(orig));
5485 rb_enc_cr_str_copy_for_substr(str, orig);
5486 return str_succ(str);
5493 char *sbeg, *s, *e, *last_alnum = 0;
5494 int found_alnum = 0;
5496 char carry[ONIGENC_CODE_TO_MBC_MAXLEN] =
"\1";
5497 rb_len_t carry_pos = 0, carry_len = 1;
5498 enum neighbor_char neighbor = NEIGHBOR_FOUND;
5500 slen = RSTRING_LEN(str);
5501 if (slen == 0)
return str;
5503 enc = STR_ENC_GET(str);
5504 sbeg = RSTRING_PTR(str);
5505 s = e = sbeg + slen;
5507 while ((s = rb_enc_prev_char(sbeg, s, e, enc)) != 0) {
5508 if (neighbor == NEIGHBOR_NOT_CHAR && last_alnum) {
5514 l = rb_enc_precise_mbclen(s, e, enc);
5515 if (!ONIGENC_MBCLEN_CHARFOUND_P(l))
continue;
5516 l = ONIGENC_MBCLEN_CHARFOUND_LEN(l);
5517 neighbor = enc_succ_alnum_char(s, l, enc, carry);
5519 case NEIGHBOR_NOT_CHAR:
5521 case NEIGHBOR_FOUND:
5523 case NEIGHBOR_WRAPPED:
5528 carry_pos = s - sbeg;
5533 while ((s = rb_enc_prev_char(sbeg, s, e, enc)) != 0) {
5534 enum neighbor_char neighbor;
5535 char tmp[ONIGENC_CODE_TO_MBC_MAXLEN];
5536 l = rb_enc_precise_mbclen(s, e, enc);
5537 if (!ONIGENC_MBCLEN_CHARFOUND_P(l))
continue;
5538 l = ONIGENC_MBCLEN_CHARFOUND_LEN(l);
5540 neighbor = enc_succ_char(tmp, l, enc);
5542 case NEIGHBOR_FOUND:
5546 case NEIGHBOR_WRAPPED:
5549 case NEIGHBOR_NOT_CHAR:
5552 if (rb_enc_precise_mbclen(s, s+l, enc) != l) {
5554 enc_succ_char(s, l, enc);
5556 if (!rb_enc_asciicompat(enc)) {
5557 MEMCPY(carry, s,
char, l);
5560 carry_pos = s - sbeg;
5564 RESIZE_CAPA(str, slen + carry_len);
5565 sbeg = RSTRING_PTR(str);
5566 s = sbeg + carry_pos;
5567 memmove(s + carry_len, s, slen - carry_pos);
5568 memmove(s, carry, carry_len);
5570 STR_SET_LEN(str, slen);
5571 TERM_FILL(&sbeg[slen], rb_enc_mbminlen(enc));
5572 rb_enc_str_coderange(str);
5587rb_str_succ_bang(
VALUE str)
5623 VALUE end, exclusive;
5627 return rb_str_upto_each(beg, end,
RTEST(exclusive), str_upto_i,
Qnil);
5633 VALUE current, after_end;
5640 enc = rb_enc_check(beg, end);
5641 ascii = (is_ascii_string(beg) && is_ascii_string(end));
5643 if (RSTRING_LEN(beg) == 1 && RSTRING_LEN(end) == 1 && ascii) {
5644 char c = RSTRING_PTR(beg)[0];
5645 char e = RSTRING_PTR(end)[0];
5647 if (c > e || (excl && c == e))
return beg;
5649 VALUE str = rb_enc_str_new(&c, 1, enc);
5651 if ((*each)(str, arg))
break;
5652 if (!excl && c == e)
break;
5654 if (excl && c == e)
break;
5659 if (ascii &&
ISDIGIT(RSTRING_PTR(beg)[0]) &&
ISDIGIT(RSTRING_PTR(end)[0]) &&
5660 all_digits_p(RSTRING_PTR(beg), RSTRING_LEN(beg)) &&
5661 all_digits_p(RSTRING_PTR(end), RSTRING_LEN(end))) {
5666 b = rb_str_to_inum(beg, 10, FALSE);
5667 e = rb_str_to_inum(end, 10, FALSE);
5674 if (excl && bi == ei)
break;
5675 if ((*each)(
rb_enc_sprintf(usascii,
"%.*ld", width, bi), arg))
break;
5680 ID op = excl ?
'<' : idLE;
5681 VALUE args[2], fmt = rb_fstring_lit(
"%.*d");
5686 if ((*each)(
rb_str_format(numberof(args), args, fmt), arg))
break;
5694 if (n > 0 || (excl && n == 0))
return beg;
5702 if ((*each)(current, arg))
break;
5703 if (
NIL_P(next))
break;
5707 if (RSTRING_LEN(current) > RSTRING_LEN(end) || RSTRING_LEN(current) == 0)
5722 if (is_ascii_string(beg) &&
ISDIGIT(RSTRING_PTR(beg)[0]) &&
5723 all_digits_p(RSTRING_PTR(beg), RSTRING_LEN(beg))) {
5724 VALUE b, args[2], fmt = rb_fstring_lit(
"%.*d");
5726 b = rb_str_to_inum(beg, 10, FALSE);
5732 if ((*each)(
rb_enc_sprintf(usascii,
"%.*ld", width, bi), arg))
break;
5740 if ((*each)(
rb_str_format(numberof(args), args, fmt), arg))
break;
5748 if ((*each)(current, arg))
break;
5751 if (RSTRING_LEN(current) == 0)
5762 if (!
rb_equal(str, *argp))
return 0;
5776 if (rb_enc_asciicompat(STR_ENC_GET(beg)) &&
5777 rb_enc_asciicompat(STR_ENC_GET(end)) &&
5778 rb_enc_asciicompat(STR_ENC_GET(val))) {
5779 const char *bp = RSTRING_PTR(beg);
5780 const char *ep = RSTRING_PTR(end);
5781 const char *vp = RSTRING_PTR(val);
5782 if (RSTRING_LEN(beg) == 1 && RSTRING_LEN(end) == 1) {
5783 if (RSTRING_LEN(val) == 0 || RSTRING_LEN(val) > 1)
5791 if (b <= v && v < e)
return Qtrue;
5792 return RBOOL(!
RTEST(exclusive) && b <= v && v == e);
5799 all_digits_p(bp, RSTRING_LEN(beg)) &&
5800 all_digits_p(ep, RSTRING_LEN(end))) {
5805 rb_str_upto_each(beg, end,
RTEST(exclusive), include_range_i, (
VALUE)&val);
5807 return RBOOL(
NIL_P(val));
5830 return rb_str_subpat(str, indx,
INT2FIX(0));
5833 if (rb_str_index(str, indx, 0) != -1)
5851 return str_substr(str, idx, 1, FALSE);
5868rb_str_aref_m(
int argc,
VALUE *argv,
VALUE str)
5872 return rb_str_subpat(str, argv[0], argv[1]);
5875 return rb_str_substr_two_fixnums(str, argv[0], argv[1], TRUE);
5879 return rb_str_aref(str, argv[0]);
5885 char *
ptr = RSTRING_PTR(str);
5886 rb_len_t olen = RSTRING_LEN(str), nlen;
5888 str_modifiable(str);
5889 if (
len > olen)
len = olen;
5891 if (str_embed_capa(str) >= nlen + TERM_LEN(str)) {
5893 size_t old_capa =
RSTRING(str)->as.heap.aux.capa + TERM_LEN(str);
5894 int fl = (int)(
RBASIC(str)->flags & (STR_NOEMBED|STR_SHARED|STR_NOFREE));
5897 memmove(
ptr, oldptr +
len, nlen);
5898 if (fl == STR_NOEMBED) {
5899 SIZED_FREE_N(oldptr, old_capa);
5903 if (!STR_SHARED_P(str)) {
5905 rb_enc_cr_str_exact_copy(
shared, str);
5910 STR_SET_LEN(str, nlen);
5912 if (!SHARABLE_MIDDLE_SUBSTRING) {
5913 TERM_FILL(
ptr + nlen, TERM_LEN(str));
5926 if (beg == 0 && vlen == 0) {
5931 str_modify_keep_cr(str);
5935 RESIZE_CAPA(str, slen + vlen -
len);
5936 sptr = RSTRING_PTR(str);
5940 cr = rb_enc_str_coderange(val);
5945 memmove(sptr + beg + vlen,
5947 slen - (beg +
len));
5949 if (vlen < beg &&
len < 0) {
5953 memmove(sptr + beg, RSTRING_PTR(val) + vbeg, vlen);
5956 STR_SET_LEN(str, slen);
5957 TERM_FILL(&sptr[slen], TERM_LEN(str));
5964 rb_str_update_1(str, beg,
len, val, 0, RSTRING_LEN(val));
5973 int singlebyte = single_byte_optimizable(str);
5979 enc = rb_enc_check(str, val);
5980 slen = str_strlen(str, enc);
5982 if ((slen < beg) || ((beg < 0) && (beg + slen < 0))) {
5991 if (
len > slen - beg) {
5994 p = str_nth(RSTRING_PTR(str),
RSTRING_END(str), beg, enc, singlebyte);
5999 beg = p - RSTRING_PTR(str);
6001 rb_str_update_0(str, beg,
len, val);
6002 rb_enc_associate(str, enc);
6021 int num_regs = RMATCH_NREGS(match);
6022 if (nth >= num_regs || nth + num_regs <= 0) {
6029 start = RMATCH_BEG(match, nth);
6033 end = RMATCH_END(match, nth);
6037 if (start +
len > RSTRING_LEN(str)) {
6041 enc = rb_enc_check_str(str, val);
6042 rb_str_update_0(str, start,
len, val);
6043 rb_enc_associate(str, enc);
6051 switch (
TYPE(indx)) {
6053 rb_str_subpat_set(str, indx,
INT2FIX(0), val);
6057 beg = rb_str_index(str, indx, 0);
6096rb_str_aset_m(
int argc,
VALUE *argv,
VALUE str)
6100 rb_str_subpat_set(str, argv[0], argv[1], argv[2]);
6108 return rb_str_aset(str, argv[0], argv[1]);
6160rb_str_slice_bang(
int argc,
VALUE *argv,
VALUE str)
6168 str_modify_keep_cr(str);
6173 int num_regs = RMATCH_NREGS(match);
6176 if ((nth += num_regs) <= 0)
return Qnil;
6178 else if (nth >= num_regs)
return Qnil;
6179 beg = RMATCH_BEG(match, nth);
6180 len = RMATCH_END(match, nth) - beg;
6182 if (beg > RSTRING_LEN(str))
return Qnil;
6183 if (
len > RSTRING_LEN(str) - beg)
len = RSTRING_LEN(str) - beg;
6186 else if (argc == 2) {
6195 beg = p - RSTRING_PTR(str);
6199 beg = rb_str_index(str, indx, 0);
6200 if (beg == -1)
return Qnil;
6201 len = RSTRING_LEN(indx);
6213 beg = p - RSTRING_PTR(str);
6222 beg = p - RSTRING_PTR(str);
6226 rb_enc_cr_str_copy_for_substr(result, str);
6234 char *sptr = RSTRING_PTR(str);
6236 if (beg +
len > slen)
6240 slen - (beg +
len));
6242 STR_SET_LEN(str, slen);
6243 TERM_FILL(&sptr[slen], TERM_LEN(str));
6254 switch (OBJ_BUILTIN_TYPE(pat)) {
6273get_pat_quoted(
VALUE pat,
int check)
6277 switch (OBJ_BUILTIN_TYPE(pat)) {
6291 if (check && is_broken_string(pat)) {
6301 pos = rb_str_byteindex(str, pat, pos);
6302 if (set_backref_str) {
6304 str = rb_str_new_frozen_String(str);
6305 VALUE match_data = rb_backref_set_string(str, pos, RSTRING_LEN(pat));
6307 *match = match_data;
6317 return rb_reg_search0(pat, str, pos, 0, set_backref_str, match);
6324 return rb_pat_search0(pat, str, pos, set_backref_str, NULL);
6342rb_str_sub_bang(
int argc,
VALUE *argv,
VALUE str)
6357 hash = rb_check_hash_type(repl);
6364 pat = get_pat_quoted(argv[0], 1);
6366 str_modifiable(str);
6367 beg = rb_pat_search(pat, str, 0, 1);
6379 end0 = beg0 + RSTRING_LEN(pat);
6383 beg0 = RMATCH_BEG(match, 0);
6384 end0 = RMATCH_END(match, 0);
6388 if (iter || !
NIL_P(hash)) {
6389 p = RSTRING_PTR(str);
len = RSTRING_LEN(str);
6395 repl = rb_hash_aref(hash,
rb_str_subseq(str, beg0, end0 - beg0));
6398 str_mod_check(str, p,
len);
6399 rb_check_frozen(str);
6402 repl = rb_reg_regsub_match(repl, str, match);
6405 enc = rb_enc_compatible(str, repl);
6408 p = RSTRING_PTR(str);
len = RSTRING_LEN(str);
6412 rb_enc_inspect_name(str_enc),
6413 rb_enc_inspect_name(STR_ENC_GET(repl)));
6415 enc = STR_ENC_GET(repl);
6418 rb_enc_associate(str, enc);
6428 rlen = RSTRING_LEN(repl);
6429 len = RSTRING_LEN(str);
6431 RESIZE_CAPA(str,
len + rlen - plen);
6433 p = RSTRING_PTR(str);
6435 memmove(p + beg0 + rlen, p + beg0 + plen,
len - beg0 - plen);
6437 rp = RSTRING_PTR(repl);
6438 memmove(p + beg0, rp, rlen);
6440 STR_SET_LEN(str,
len);
6441 TERM_FILL(&RSTRING_PTR(str)[
len], TERM_LEN(str));
6464 rb_str_sub_bang(argc, argv, str);
6469str_gsub(
int argc,
VALUE *argv,
VALUE str,
int bang)
6474 enum {STR, ITER, FAST_MAP, MAP} mode = STR;
6476 int need_backref_str = -1;
6487 hash = rb_check_hash_type(repl);
6491 else if (rb_hash_default_unredefined(hash) && !
FL_TEST_RAW(hash, RHASH_PROC_DEFAULT)) {
6500 rb_error_arity(argc, 1, 2);
6503 pat = get_pat_quoted(argv[0], 1);
6504 beg = rb_pat_search0(pat, str, 0, need_backref_str, &match);
6507 if (bang)
return Qnil;
6510 if (bang) str_modify_keep_cr(str);
6513 blen = RSTRING_LEN(str) + 30;
6515 sp = RSTRING_PTR(str);
6516 slen = RSTRING_LEN(str);
6518 str_enc = STR_ENC_GET(str);
6519 rb_enc_associate(dest, str_enc);
6525 end0 = beg0 + RSTRING_LEN(pat);
6529 beg0 = RMATCH_BEG(match, 0);
6530 end0 = RMATCH_END(match, 0);
6539 struct RString fake_str = {RBASIC_INIT};
6541 if (mode == FAST_MAP) {
6550 val = rb_hash_aref(hash, key);
6553 str_mod_check(str, sp, slen);
6558 else if (need_backref_str) {
6559 val = rb_reg_regsub_match(repl, str, match);
6560 if (need_backref_str < 0) {
6561 need_backref_str = val != repl;
6568 len = beg0 - offset;
6582 if (RSTRING_LEN(str) <= end0)
break;
6583 len = rb_enc_fast_mbclen(RSTRING_PTR(str)+end0,
RSTRING_END(str), str_enc);
6585 offset = end0 +
len;
6587 cp = RSTRING_PTR(str) + offset;
6588 if (offset > RSTRING_LEN(str))
break;
6591 if (mode != FAST_MAP && mode != STR) {
6594 beg = rb_pat_search0(pat, str, offset, need_backref_str, &match);
6599 if (RSTRING_LEN(str) > offset) {
6602 rb_pat_search0(pat, str, last, 1, &match);
6604 str_shared_replace(str, dest);
6629rb_str_gsub_bang(
int argc,
VALUE *argv,
VALUE str)
6631 str_modifiable(str);
6632 return str_gsub(argc, argv, str, 1);
6682 return str_gsub(argc, argv, str, 0);
6702 str_modifiable(str);
6703 if (str == str2)
return str;
6707 return str_replace(str, str2);
6724rb_str_clear(
VALUE str)
6728 STR_SET_LEN(str, 0);
6729 RSTRING_PTR(str)[0] = 0;
6730 if (rb_enc_asciicompat(STR_ENC_GET(str)))
6746rb_str_chr(
VALUE str)
6764 pos += RSTRING_LEN(str);
6765 if (pos < 0 || RSTRING_LEN(str) <= pos)
6768 return INT2FIX((
unsigned char)RSTRING_PTR(str)[pos]);
6788 char *
ptr, *head, *left = 0;
6794 char byte = (char)(
NUM2INT(w) & 0xFF);
6797 if (pos < -
len ||
len <= pos)
6802 if (!str_independent(str))
6803 str_make_independent(str);
6804 enc = STR_ENC_GET(str);
6805 head = RSTRING_PTR(str);
6807 if (!STR_EMBED_P(str)) {
6814 nlen = rb_enc_precise_mbclen(left, head+
len, enc);
6822 width = rb_enc_precise_mbclen(left, head+
len, enc);
6824 nlen = rb_enc_precise_mbclen(left, head+
len, enc);
6840str_bit_offset_out_of_range(
rb_len_t byte_len, uint64_t bit_offset)
6843 return bit_offset / CHAR_BIT >= (uint64_t)byte_len;
6859str_bit_offset_from_index(
VALUE index)
6872 offset.index_value =
FIX2LONG(integer);
6873 if (offset.index_value < 0) {
6876 offset.value = (uint64_t)offset.index_value;
6877 offset.fits_index =
true;
6882 if (rb_int_negative_p(integer)) {
6885 if (rb_cmpint(rb_int_cmp(integer,
ULL2NUM(UINT64_MAX)), integer,
ULL2NUM(UINT64_MAX)) > 0) {
6886 rb_raise(rb_eArgError,
"bit index out of representable range");
6889 offset.value = (uint64_t)
NUM2ULL(integer);
6891 offset.index_value = (
rb_len_t)offset.value;
6892 offset.fits_index =
true;
6895 offset.index_value = 0;
6896 offset.fits_index =
false;
6906str_bit_length_from_index(
VALUE index)
6913 rb_raise(rb_eArgError,
"negative bit length");
6915 return (uint64_t)value;
6919 if (rb_int_negative_p(integer)) {
6920 rb_raise(rb_eArgError,
"negative bit length");
6922 if (rb_cmpint(rb_int_cmp(integer,
ULL2NUM(UINT64_MAX)), integer,
ULL2NUM(UINT64_MAX)) > 0) {
6923 rb_raise(rb_eArgError,
"bit length out of representable range");
6925 return (uint64_t)
NUM2ULL(integer);
6928static inline uint64_t
6935 if ((uint64_t)byte_len > UINT64_MAX / CHAR_BIT)
return UINT64_MAX;
6936 return (uint64_t)byte_len * CHAR_BIT;
6941 uint64_t end_exclusive;
6964 out->beg =
NIL_P(beg_v) ? 0 : str_bit_offset_from_index(beg_v).value;
6966 out->end_open =
true;
6967 out->end_exclusive = 0;
6970 uint64_t end = str_bit_offset_from_index(end_v).value;
6971 out->end_open =
false;
6976 out->end_exclusive = (excl || end == UINT64_MAX) ? end : end + 1;
6986str_bit_range_resolve(
const struct str_bit_range *range, uint64_t total_bits, uint64_t *begp, uint64_t *lenp)
6988 uint64_t beg = range->beg;
6989 if (beg > total_bits)
return false;
6991 uint64_t end_exclusive = range->end_open ? total_bits : range->end_exclusive;
6992 if (end_exclusive < beg) end_exclusive = beg;
6995 *lenp = end_exclusive - beg;
7000str_lsb_first_from_opts(
VALUE opts)
7002 static ID keywords[1];
7010 if (vlsb_first ==
Qundef || vlsb_first ==
Qtrue) {
7013 if (vlsb_first ==
Qfalse) {
7016 rb_raise(rb_eArgError,
"lsb_first must be true or false");
7021str_lsb_first(
int argc,
VALUE *argv,
VALUE *index)
7026 return str_lsb_first_from_opts(opts);
7029static inline uint64_t
7030str_logical_to_physical_bit64(uint64_t logical,
bool lsb_first)
7032 return lsb_first ? logical : ((logical & ~(uint64_t)7) | (7 - (logical & 7)));
7036str_logical_to_physical_bit(
rb_len_t logical,
bool lsb_first)
7038 return lsb_first ? logical : ((logical & ~7L) | (7 - (logical & 7L)));
7043 unsigned int bit_offset;
7047str_bit_location_from_offset(uint64_t logical, bool lsb_first)
7053 uint64_t physical = str_logical_to_physical_bit64(logical, lsb_first);
7055 location.byte_index = (
rb_len_t)(physical / CHAR_BIT);
7056 location.bit_offset = (
unsigned int)(physical % CHAR_BIT);
7061str_get_bit(
const char *ptr,
rb_len_t bit_index)
7063 return (((
unsigned char)ptr[bit_index / CHAR_BIT]) >> (bit_index % CHAR_BIT)) & 1;
7069 return (((
unsigned char)ptr[location.byte_index]) >> location.bit_offset) & 1;
7076 bool lsb_first = str_lsb_first(argc, argv, &index);
7079 if (str_bit_offset_out_of_range(RSTRING_LEN(str), offset.value)) {
7083 if (offset.fits_index) {
7084 return str_get_bit(RSTRING_PTR(str), str_logical_to_physical_bit(offset.index_value, lsb_first));
7087 return str_get_bit_location(RSTRING_PTR(str), str_bit_location_from_offset(offset.value, lsb_first));
7099rb_str_bit_get(
int argc,
VALUE *argv,
VALUE str)
7101 int bit = str_bit_get(argc, argv, str);
7113rb_str_bit_set_p(
int argc,
VALUE *argv,
VALUE str)
7115 int bit = str_bit_get(argc, argv, str);
7116 return bit < 0 ?
Qnil : RBOOL(bit);
7119enum str_bit_mutation {
7130static inline unsigned char
7131str_bit_region_byte_mask(
unsigned int lo,
unsigned int hi,
bool lsb_first)
7134 return (
unsigned char)((0xFFu >> (7 - hi)) & (0xFFu << lo));
7137 return (
unsigned char)((0xFFu >> lo) & (0xFFu << (7 - hi)));
7142str_apply_bit_mask(
unsigned char *
byte,
unsigned char mask,
enum str_bit_mutation mutation)
7149 *
byte &= (
unsigned char)~mask;
7159str_mutate_bit_region(
unsigned char *ptr, uint64_t beg, uint64_t
len,
bool lsb_first,
enum str_bit_mutation mutation)
7161 uint64_t first_bit = beg;
7162 uint64_t last_bit = beg +
len - 1;
7165 unsigned int first_off = (
unsigned int)(first_bit % CHAR_BIT);
7166 unsigned int last_off = (
unsigned int)(last_bit % CHAR_BIT);
7168 if (first_byte == last_byte) {
7169 str_apply_bit_mask(ptr + first_byte, str_bit_region_byte_mask(first_off, last_off, lsb_first), mutation);
7173 str_apply_bit_mask(ptr + first_byte, str_bit_region_byte_mask(first_off, 7, lsb_first), mutation);
7174 rb_len_t middle_len = last_byte - first_byte - 1;
7175 if (middle_len > 0) {
7176 unsigned char *middle = ptr + first_byte + 1;
7179 memset(middle, 0xFF, middle_len);
7182 memset(middle, 0, middle_len);
7190 for (
rb_len_t i = 0; i < middle_len; i++) {
7196 str_apply_bit_mask(ptr + last_byte, str_bit_region_byte_mask(0, last_off, lsb_first), mutation);
7200str_mutate_single_bit(
VALUE str,
VALUE index,
bool lsb_first,
enum str_bit_mutation mutation)
7208 rb_check_frozen(str);
7210 if (str_bit_offset_out_of_range(RSTRING_LEN(str), offset.value)) {
7215 ptr = (
unsigned char *)RSTRING_PTR(str);
7216 if (offset.fits_index) {
7217 bit_index = str_logical_to_physical_bit(offset.index_value, lsb_first);
7218 mask = (
unsigned char)(1u << (bit_index % CHAR_BIT));
7219 location.byte_index = bit_index / CHAR_BIT;
7222 location = str_bit_location_from_offset(offset.value, lsb_first);
7223 mask = (
unsigned char)(1u << location.bit_offset);
7226 str_apply_bit_mask(ptr + location.byte_index, mask, mutation);
7231str_mutate_bit(
int argc,
VALUE *argv,
VALUE str,
enum str_bit_mutation mutation)
7233 VALUE target, length_v, opts;
7234 uint64_t beg = 0,
len = 0;
7237 int nargs =
rb_scan_args(argc, argv,
"11:", &target, &length_v, &opts);
7238 bool lsb_first = str_lsb_first_from_opts(opts);
7241 if (nargs == 1 && !is_range) {
7242 return str_mutate_single_bit(str, target, lsb_first, mutation);
7249 rb_raise(rb_eArgError,
"bit length not allowed with a Range");
7251 str_bit_range_to_offsets(target, &range);
7254 offset = str_bit_offset_from_index(target);
7255 len = str_bit_length_from_index(length_v);
7259 rb_check_frozen(str);
7267 uint64_t total_bits = str_bit_size(RSTRING_LEN(str));
7269 if (!str_bit_range_resolve(&range, total_bits, &beg, &
len) ||
len > total_bits - beg) {
7275 if (beg > total_bits ||
len > total_bits - beg) {
7280 if (
len == 0)
return str;
7283 str_mutate_bit_region((
unsigned char *)RSTRING_PTR(str), beg,
len, lsb_first, mutation);
7297rb_str_bit_set(
int argc,
VALUE *argv,
VALUE str)
7299 return str_mutate_bit(argc, argv, str, STR_BIT_SET);
7312rb_str_bit_clear(
int argc,
VALUE *argv,
VALUE str)
7314 return str_mutate_bit(argc, argv, str, STR_BIT_CLEAR);
7327rb_str_bit_flip(
int argc,
VALUE *argv,
VALUE str)
7329 return str_mutate_bit(argc, argv, str, STR_BIT_FLIP);
7333str_count_bits(
const unsigned char *ptr,
rb_len_t len)
7341 for (;
off < unrolled_end;
off += 32) {
7342 uint64_t w0, w1, w2, w3;
7343 memcpy(&w0, ptr +
off, 8);
7344 memcpy(&w1, ptr +
off + 8, 8);
7345 memcpy(&w2, ptr +
off + 16, 8);
7346 memcpy(&w3, ptr +
off + 24, 8);
7347 count += rb_popcount64(w0);
7348 count += rb_popcount64(w1);
7349 count += rb_popcount64(w2);
7350 count += rb_popcount64(w3);
7354 for (;
off < aligned_end;
off += 8) {
7356 memcpy(&word, ptr +
off, 8);
7357 count += rb_popcount64(word);
7364 for (;
off <
len;
off++, shift += CHAR_BIT) {
7365 word |= (uint64_t)ptr[
off] << shift;
7367 count += rb_popcount64(word);
7374str_count_bits_region(
const unsigned char *ptr, uint64_t beg, uint64_t
len,
bool lsb_first)
7376 uint64_t first_bit = beg;
7377 uint64_t last_bit = beg +
len - 1;
7380 unsigned int first_off = (
unsigned int)(first_bit % CHAR_BIT);
7381 unsigned int last_off = (
unsigned int)(last_bit % CHAR_BIT);
7383 if (first_byte == last_byte) {
7384 return rb_popcount32((uint32_t)(ptr[first_byte] & str_bit_region_byte_mask(first_off, last_off, lsb_first)));
7387 uint64_t count = rb_popcount32((uint32_t)(ptr[first_byte] & str_bit_region_byte_mask(first_off, 7, lsb_first)));
7388 count += str_count_bits(ptr + first_byte + 1, last_byte - first_byte - 1);
7389 count += rb_popcount32((uint32_t)(ptr[last_byte] & str_bit_region_byte_mask(0, last_off, lsb_first)));
7403rb_str_bit_count(
int argc,
VALUE *argv,
VALUE str)
7406 uint64_t beg = 0,
len = 0;
7409 int nargs =
rb_scan_args(argc, argv,
"02:", &v0, &v1, &opts);
7414 bool lsb_first = str_lsb_first_from_opts(opts);
7417 return ULL2NUM(str_count_bits((
const unsigned char *)RSTRING_PTR(str), RSTRING_LEN(str)));
7424 rb_raise(rb_eArgError,
"bit length not allowed with a Range");
7426 str_bit_range_to_offsets(v0, &range);
7428 else if (nargs == 1) {
7429 rb_raise(rb_eArgError,
"no bit length given");
7432 beg = str_bit_offset_from_index(v0).value;
7433 len = str_bit_length_from_index(v1);
7436 const unsigned char *ptr = (
const unsigned char *)RSTRING_PTR(str);
7437 uint64_t total_bits = str_bit_size(RSTRING_LEN(str));
7439 if (!str_bit_range_resolve(&range, total_bits, &beg, &
len)) {
7443 else if (beg >= total_bits) {
7448 if (
len > total_bits - beg)
len = total_bits - beg;
7450 return ULL2NUM(str_count_bits_region(ptr, beg,
len, lsb_first));
7454str_check_bitwise_length(
VALUE str,
VALUE other)
7456 if (RSTRING_LEN(str) != RSTRING_LEN(other)) {
7457 rb_raise(rb_eArgError,
"operands must have the same length (%"PRIdLEN
" vs %"PRIdLEN
")",
7458 RSTRING_LEN(str), RSTRING_LEN(other));
7463str_bitwise_result(
VALUE str)
7467 rb_str_resize(result,
len);
7468 rb_enc_associate(result, rb_ascii8bit_encoding());
7473#define STR_DEFINE_UNARY_BITWISE_KERNEL(name, expr_word, expr_byte) \
7475 name(unsigned char *dst, const unsigned char *src, rb_len_t len) \
7478 rb_len_t unrolled_end = len & ~31L; \
7479 rb_len_t aligned_end = len & ~7L; \
7480 for (; off < unrolled_end; off += 32) { \
7481 uint64_t s0, s1, s2, s3; \
7482 memcpy(&s0, src + off, 8); \
7483 memcpy(&s1, src + off + 8, 8); \
7484 memcpy(&s2, src + off + 16, 8); \
7485 memcpy(&s3, src + off + 24, 8); \
7486 s0 = (expr_word(s0)); \
7487 s1 = (expr_word(s1)); \
7488 s2 = (expr_word(s2)); \
7489 s3 = (expr_word(s3)); \
7490 memcpy(dst + off, &s0, 8); \
7491 memcpy(dst + off + 8, &s1, 8); \
7492 memcpy(dst + off + 16, &s2, 8); \
7493 memcpy(dst + off + 24, &s3, 8); \
7495 for (; off < aligned_end; off += 8) { \
7497 memcpy(&word, src + off, 8); \
7498 word = (expr_word(word)); \
7499 memcpy(dst + off, &word, 8); \
7501 for (; off < len; off++) dst[off] = (expr_byte(src[off])); \
7504#define STR_DEFINE_BINARY_BITWISE_KERNEL(name, expr_word, expr_byte) \
7506 name(unsigned char *dst, const unsigned char *lhs, \
7507 const unsigned char *rhs, rb_len_t len) \
7510 rb_len_t unrolled_end = len & ~31L; \
7511 rb_len_t aligned_end = len & ~7L; \
7512 for (; off < unrolled_end; off += 32) { \
7513 uint64_t l0, l1, l2, l3, r0, r1, r2, r3; \
7514 memcpy(&l0, lhs + off, 8); memcpy(&r0, rhs + off, 8); \
7515 memcpy(&l1, lhs + off + 8, 8); memcpy(&r1, rhs + off + 8, 8); \
7516 memcpy(&l2, lhs + off + 16, 8); memcpy(&r2, rhs + off + 16, 8); \
7517 memcpy(&l3, lhs + off + 24, 8); memcpy(&r3, rhs + off + 24, 8); \
7518 l0 = expr_word(l0, r0); \
7519 l1 = expr_word(l1, r1); \
7520 l2 = expr_word(l2, r2); \
7521 l3 = expr_word(l3, r3); \
7522 memcpy(dst + off, &l0, 8); \
7523 memcpy(dst + off + 8, &l1, 8); \
7524 memcpy(dst + off + 16, &l2, 8); \
7525 memcpy(dst + off + 24, &l3, 8); \
7527 for (; off < aligned_end; off += 8) { \
7528 uint64_t lhs_word, rhs_word; \
7529 memcpy(&lhs_word, lhs + off, 8); \
7530 memcpy(&rhs_word, rhs + off, 8); \
7531 lhs_word = expr_word(lhs_word, rhs_word); \
7532 memcpy(dst + off, &lhs_word, 8); \
7534 for (; off < len; off++) dst[off] = expr_byte(lhs[off], rhs[off]); \
7537#define STR_BITWISE_NOT_WORD(x) (~(x))
7538#define STR_BITWISE_NOT_BYTE(x) ((unsigned char)~(x))
7539#define STR_BITWISE_AND_WORD(x, y) ((x) & (y))
7540#define STR_BITWISE_AND_BYTE(x, y) ((unsigned char)((x) & (y)))
7541#define STR_BITWISE_OR_WORD(x, y) ((x) | (y))
7542#define STR_BITWISE_OR_BYTE(x, y) ((unsigned char)((x) | (y)))
7543#define STR_BITWISE_XOR_WORD(x, y) ((x) ^ (y))
7544#define STR_BITWISE_XOR_BYTE(x, y) ((unsigned char)((x) ^ (y)))
7546STR_DEFINE_UNARY_BITWISE_KERNEL(str_bitwise_not, STR_BITWISE_NOT_WORD, STR_BITWISE_NOT_BYTE)
7547STR_DEFINE_BINARY_BITWISE_KERNEL(str_bitwise_and, STR_BITWISE_AND_WORD, STR_BITWISE_AND_BYTE)
7548STR_DEFINE_BINARY_BITWISE_KERNEL(str_bitwise_or, STR_BITWISE_OR_WORD, STR_BITWISE_OR_BYTE)
7549STR_DEFINE_BINARY_BITWISE_KERNEL(str_bitwise_xor, STR_BITWISE_XOR_WORD, STR_BITWISE_XOR_BYTE)
7559rb_str_bitwise_not(
VALUE str)
7562 VALUE result = str_bitwise_result(str);
7563 str_bitwise_not((
unsigned char *)RSTRING_PTR(result),
7564 (
const unsigned char *)RSTRING_PTR(str),
len);
7576rb_str_bitwise_not_bang(
VALUE str)
7582 len = RSTRING_LEN(str);
7583 ptr = (
unsigned char *)RSTRING_PTR(str);
7584 str_bitwise_not(ptr, ptr,
len);
7648#define STR_DEFINE_BINARY_BITWISE_METHOD(name) \
7650 rb_str_bitwise_##name(VALUE str, VALUE other) \
7654 StringValue(other); \
7655 str_check_bitwise_length(str, other); \
7656 len = RSTRING_LEN(str); \
7657 result = str_bitwise_result(str); \
7658 str_bitwise_##name((unsigned char *)RSTRING_PTR(result), \
7659 (const unsigned char *)RSTRING_PTR(str), \
7660 (const unsigned char *)RSTRING_PTR(other), len); \
7664 rb_str_bitwise_##name##_bang(VALUE str, VALUE other) \
7667 unsigned char *ptr; \
7668 StringValue(other); \
7669 str_check_bitwise_length(str, other); \
7670 rb_str_modify(str); \
7671 len = RSTRING_LEN(str); \
7672 ptr = (unsigned char *)RSTRING_PTR(str); \
7673 str_bitwise_##name(ptr, ptr, \
7674 (const unsigned char *)RSTRING_PTR(other), len); \
7678STR_DEFINE_BINARY_BITWISE_METHOD(and)
7679STR_DEFINE_BINARY_BITWISE_METHOD(or)
7680STR_DEFINE_BINARY_BITWISE_METHOD(xor)
7687 if (beg > n ||
len < 0)
return Qnil;
7690 if (beg < 0)
return Qnil;
7695 if (!empty)
return Qnil;
7699 VALUE str2 = str_subseq(str, beg,
len);
7701 str_enc_copy_direct(str2, str);
7703 if (RSTRING_LEN(str2) == 0) {
7704 if (!rb_enc_asciicompat(STR_ENC_GET(str)))
7746 return str_byte_substr(str, beg,
len, TRUE);
7751 return str_byte_substr(str, idx, 1, FALSE);
7763rb_str_byteslice(
int argc,
VALUE *argv,
VALUE str)
7768 return str_byte_substr(str, beg,
len, TRUE);
7771 return str_byte_aref(str, argv[0]);
7777 rb_len_t end, slen = RSTRING_LEN(str);
7780 if ((slen < *beg) || ((*beg < 0) && (*beg + slen < 0))) {
7781 rb_raise(
rb_eIndexError,
"index %"PRIdLEN
" out of string", *beg);
7789 if (*
len > slen - *beg) {
7793 str_ensure_byte_pos(str, *beg);
7794 str_ensure_byte_pos(str, end);
7808rb_str_bytesplice(
int argc,
VALUE *argv,
VALUE str)
7815 if (!(argc == 2 || argc == 3 || argc == 5)) {
7816 rb_raise(rb_eArgError,
"wrong number of arguments (given %d, expected 2, 3, or 5)", argc);
7820 rb_raise(
rb_eTypeError,
"wrong argument type %s (expected Range)",
7821 rb_builtin_class_name(argv[0]));
7828 vlen = RSTRING_LEN(val);
7833 rb_raise(
rb_eTypeError,
"wrong argument type %s (expected Range)",
7834 rb_builtin_class_name(argv[2]));
7846 vlen = RSTRING_LEN(val);
7854 str_check_beg_len(str, &beg, &
len);
7855 str_check_beg_len(val, &vbeg, &vlen);
7856 str_modify_keep_cr(str);
7859 rb_enc_associate(str, rb_enc_check(str, val));
7862 rb_str_update_1(str, beg,
len, val, vbeg, vlen);
7884rb_str_reverse(
VALUE str)
7891 if (RSTRING_LEN(str) <= 1)
return str_duplicate(
rb_cString, str);
7892 enc = STR_ENC_GET(str);
7898 if (RSTRING_LEN(str) > 1) {
7899 if (single_byte_optimizable(str)) {
7906 int clen = rb_enc_fast_mbclen(s, e, enc);
7914 cr = rb_enc_asciicompat(enc) ?
7917 int clen = rb_enc_mbclen(s, e, enc);
7926 STR_SET_LEN(rev, RSTRING_LEN(str));
7927 str_enc_copy_direct(rev, str);
7949rb_str_reverse_bang(
VALUE str)
7951 if (RSTRING_LEN(str) > 1) {
7952 if (single_byte_optimizable(str)) {
7955 str_modify_keep_cr(str);
7956 s = RSTRING_PTR(str);
7965 str_shared_replace(str, rb_str_reverse(str));
7969 str_modify_keep_cr(str);
7998 i = rb_str_index(str, arg, 0);
8000 return RBOOL(i != -1);
8044 rb_raise(rb_eArgError,
"invalid radix %d", base);
8046 return rb_str_to_inum(str, base, FALSE);
8071rb_str_to_f(
VALUE str)
8088rb_str_to_s(
VALUE str)
8100 char s[RUBY_MAX_CHAR_LEN];
8101 int n = rb_enc_codelen(c, enc);
8103 rb_enc_mbcput(c, s, enc);
8108#define CHAR_ESC_LEN 13
8111rb_str_buf_cat_escaped_char(
VALUE result,
unsigned int c,
int unicode_p)
8113 char buf[CHAR_ESC_LEN + 1];
8121 snprintf(buf, CHAR_ESC_LEN,
"%c", c);
8123 else if (c < 0x10000) {
8124 snprintf(buf, CHAR_ESC_LEN,
"\\u%04X", c);
8127 snprintf(buf, CHAR_ESC_LEN,
"\\u{%X}", c);
8132 snprintf(buf, CHAR_ESC_LEN,
"\\x%02X", c);
8135 snprintf(buf, CHAR_ESC_LEN,
"\\x{%X}", c);
8138 l = (int)strlen(buf);
8144ruby_escaped_char(
int c)
8147 case '\0':
return "\\0";
8148 case '\n':
return "\\n";
8149 case '\r':
return "\\r";
8150 case '\t':
return "\\t";
8151 case '\f':
return "\\f";
8152 case '\013':
return "\\v";
8153 case '\010':
return "\\b";
8154 case '\007':
return "\\a";
8155 case '\033':
return "\\e";
8156 case '\x7f':
return "\\c?";
8162rb_str_escape(
VALUE str)
8166 const char *p = RSTRING_PTR(str);
8168 const char *prev = p;
8169 char buf[CHAR_ESC_LEN + 1];
8171 int unicode_p = rb_enc_unicode_p(enc);
8172 int asciicompat = rb_enc_asciicompat(enc);
8177 int n = rb_enc_precise_mbclen(p, pend, enc);
8179 if (p > prev) str_buf_cat(result, prev, p - prev);
8180 n = rb_enc_mbminlen(enc);
8182 n = (int)(pend - p);
8184 snprintf(buf, CHAR_ESC_LEN,
"\\x%02X", *p & 0377);
8185 str_buf_cat(result, buf, strlen(buf));
8191 c = rb_enc_mbc_to_codepoint(p, pend, enc);
8193 cc = ruby_escaped_char(c);
8195 if (p - n > prev) str_buf_cat(result, prev, p - n - prev);
8196 str_buf_cat(result, cc, strlen(cc));
8199 else if (asciicompat && rb_enc_isascii(c, enc) &&
ISPRINT(c)) {
8202 if (p - n > prev) str_buf_cat(result, prev, p - n - prev);
8203 rb_str_buf_cat_escaped_char(result, c, unicode_p);
8207 if (p > prev) str_buf_cat(result, prev, p - prev);
8217static const bool inspect_no_escape[256] = {
8218 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8219 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8220 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
8221 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
8222 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
8223 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1,
8224 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
8225 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,
8241 const char *p, *pend, *prev;
8242 char buf[CHAR_ESC_LEN + 1];
8244 rb_encoding *resenc = rb_default_internal_encoding();
8245 int unicode_p = rb_enc_unicode_p(enc);
8246 int asciicompat = rb_enc_asciicompat(enc);
8247 int cr = rb_enc_str_coderange(str);
8249 if (resenc == NULL) resenc = rb_default_external_encoding();
8250 if (!rb_enc_asciicompat(resenc)) resenc = rb_usascii_encoding();
8251 rb_enc_associate(result, resenc);
8252 str_buf_cat2(result,
"\"");
8265 while (p < pend && inspect_no_escape[(
unsigned char)*p]) p++;
8266 if (p >= pend)
break;
8269 n = rb_enc_precise_mbclen(p, pend, enc);
8271 if (p > prev) str_buf_cat(result, prev, p - prev);
8272 n = rb_enc_mbminlen(enc);
8274 n = (int)(pend - p);
8276 snprintf(buf, CHAR_ESC_LEN,
"\\x%02X", *p & 0377);
8277 str_buf_cat(result, buf, strlen(buf));
8283 c = rb_enc_mbc_to_codepoint(p, pend, enc);
8285 if ((asciicompat || unicode_p) &&
8286 (c ==
'"'|| c ==
'\\' ||
8291 (cc ==
'$' || cc ==
'@' || cc ==
'{'))))) {
8292 if (p - n > prev) str_buf_cat(result, prev, p - n - prev);
8293 str_buf_cat2(result,
"\\");
8294 if (asciicompat || enc == resenc) {
8300 case '\n': cc =
'n';
break;
8301 case '\r': cc =
'r';
break;
8302 case '\t': cc =
't';
break;
8303 case '\f': cc =
'f';
break;
8304 case '\013': cc =
'v';
break;
8305 case '\010': cc =
'b';
break;
8306 case '\007': cc =
'a';
break;
8307 case 033: cc =
'e';
break;
8308 default: cc = 0;
break;
8311 if (p - n > prev) str_buf_cat(result, prev, p - n - prev);
8314 str_buf_cat(result, buf, 2);
8327 (asciicompat && rb_enc_isascii(c, enc) &&
ISPRINT(c))) {
8331 if (p - n > prev) str_buf_cat(result, prev, p - n - prev);
8332 rb_str_buf_cat_escaped_char(result, c, unicode_p);
8337 if (p > prev) str_buf_cat(result, prev, p - prev);
8338 str_buf_cat2(result,
"\"");
8343#define IS_EVSTR(p,e) ((p) < (e) && (*(p) == '$' || *(p) == '@' || *(p) == '{'))
8356 int encidx = rb_enc_get_index(str);
8359 const char *p, *pend;
8362 int u8 = (encidx == rb_utf8_encindex());
8363 static const char nonascii_suffix[] =
".dup.force_encoding(\"%s\")";
8366 if (!rb_enc_asciicompat(enc)) {
8368 len += strlen(enc->name);
8371 p = RSTRING_PTR(str); pend = p + RSTRING_LEN(str);
8374 unsigned char c = *p++;
8377 case '"':
case '\\':
8378 case '\n':
case '\r':
8379 case '\t':
case '\f':
8380 case '\013':
case '\010':
case '\007':
case '\033':
8385 clen = IS_EVSTR(p, pend) ? 2 : 1;
8393 if (u8 && c > 0x7F) {
8394 int n = rb_enc_precise_mbclen(p-1, pend, enc);
8396 unsigned int cc = rb_enc_mbc_to_codepoint(p-1, pend, enc);
8399 else if (cc <= 0xFFFFF)
8419 p = RSTRING_PTR(str); pend = p + RSTRING_LEN(str);
8420 q = RSTRING_PTR(result); qend = q +
len + 1;
8424 unsigned char c = *p++;
8426 if (c ==
'"' || c ==
'\\') {
8430 else if (c ==
'#') {
8431 if (IS_EVSTR(p, pend)) *q++ =
'\\';
8434 else if (c ==
'\n') {
8438 else if (c ==
'\r') {
8442 else if (c ==
'\t') {
8446 else if (c ==
'\f') {
8450 else if (c ==
'\013') {
8454 else if (c ==
'\010') {
8458 else if (c ==
'\007') {
8462 else if (c ==
'\033') {
8472 int n = rb_enc_precise_mbclen(p-1, pend, enc) - 1;
8474 int cc = rb_enc_mbc_to_codepoint(p-1, pend, enc);
8477 snprintf(q, qend-q,
"u%04X", cc);
8479 snprintf(q, qend-q,
"u{%X}", cc);
8484 snprintf(q, qend-q,
"x%02X", c);
8490 if (!rb_enc_asciicompat(enc)) {
8491 snprintf(q, qend-q, nonascii_suffix, enc->name);
8492 encidx = rb_ascii8bit_encindex();
8495 rb_enc_associate_index(result, encidx);
8501unescape_ascii(
unsigned int c)
8525undump_after_backslash(
VALUE undumped,
const char **ss,
const char *s_end,
rb_encoding **penc,
bool *utf8,
bool *binary)
8527 const char *s = *ss;
8531 unsigned char buf[6];
8549 *buf = unescape_ascii(*s);
8561 if (enc_utf8 == NULL) enc_utf8 = rb_utf8_encoding();
8562 if (*penc != enc_utf8) {
8564 rb_enc_associate(undumped, enc_utf8);
8581 if (hexlen == 0 || hexlen > 6) {
8587 if (0xd800 <= c && c <= 0xdfff) {
8590 codelen = rb_enc_mbcput(c, (
char *)buf, *penc);
8600 if (0xd800 <= c && c <= 0xdfff) {
8603 codelen = rb_enc_mbcput(c, (
char *)buf, *penc);
8633static VALUE rb_str_is_ascii_only_p(
VALUE str);
8645str_undump(
VALUE str)
8647 const char *s = RSTRING_PTR(str);
8650 VALUE undumped = rb_enc_str_new(s, 0L, enc);
8652 bool binary =
false;
8656 if (rb_str_is_ascii_only_p(str) ==
Qfalse) {
8659 if (!str_null_check(str, &w)) {
8662 if (RSTRING_LEN(str) < 2)
goto invalid_format;
8663 if (*s !=
'"')
goto invalid_format;
8681 static const char force_encoding_suffix[] =
".force_encoding(\"";
8682 static const char dup_suffix[] =
".dup";
8683 const char *encname;
8688 size =
sizeof(dup_suffix) - 1;
8689 if (s_end - s > size && memcmp(s, dup_suffix, size) == 0) s += size;
8691 size =
sizeof(force_encoding_suffix) - 1;
8692 if (s_end - s <= size)
goto invalid_format;
8693 if (memcmp(s, force_encoding_suffix, size) != 0)
goto invalid_format;
8697 rb_raise(
rb_eRuntimeError,
"dumped string contained Unicode escape but used force_encoding");
8701 s = memchr(s,
'"', s_end-s);
8703 if (!s)
goto invalid_format;
8704 if (s_end - s != 2)
goto invalid_format;
8705 if (s[0] !=
'"' || s[1] !=
')')
goto invalid_format;
8707 encidx = rb_enc_find_index2(encname, (
rb_len_t)size);
8711 rb_enc_associate_index(undumped, encidx);
8721 undump_after_backslash(undumped, &s, s_end, &enc, &utf8, &binary);
8732 rb_raise(
rb_eRuntimeError,
"invalid dumped string; not wrapped with '\"' nor '\"...\".force_encoding(\"...\")' form");
8738 if (rb_enc_dummy_p(enc)) {
8745str_true_enc(
VALUE str)
8748 rb_str_check_dummy_enc(enc);
8752static OnigCaseFoldType
8753check_case_options(
int argc,
VALUE *argv, OnigCaseFoldType flags)
8758 rb_raise(rb_eArgError,
"too many options");
8759 if (argv[0]==sym_turkic) {
8760 flags |= ONIGENC_CASE_FOLD_TURKISH_AZERI;
8762 if (argv[1]==sym_lithuanian)
8763 flags |= ONIGENC_CASE_FOLD_LITHUANIAN;
8765 rb_raise(rb_eArgError,
"invalid second option");
8768 else if (argv[0]==sym_lithuanian) {
8769 flags |= ONIGENC_CASE_FOLD_LITHUANIAN;
8771 if (argv[1]==sym_turkic)
8772 flags |= ONIGENC_CASE_FOLD_TURKISH_AZERI;
8774 rb_raise(rb_eArgError,
"invalid second option");
8778 rb_raise(rb_eArgError,
"too many options");
8779 else if (argv[0]==sym_ascii)
8780 flags |= ONIGENC_CASE_ASCII_ONLY;
8781 else if (argv[0]==sym_fold) {
8782 if ((flags & (ONIGENC_CASE_UPCASE|ONIGENC_CASE_DOWNCASE)) == ONIGENC_CASE_DOWNCASE)
8783 flags ^= ONIGENC_CASE_FOLD|ONIGENC_CASE_DOWNCASE;
8785 rb_raise(rb_eArgError,
"option :fold only allowed for downcasing");
8788 rb_raise(rb_eArgError,
"invalid option");
8795 if ((flags & ONIGENC_CASE_ASCII_ONLY) && (enc==rb_utf8_encoding() ||
rb_enc_mbmaxlen(enc) == 1))
8797 return !(flags & ONIGENC_CASE_FOLD_TURKISH_AZERI) &&
8802#define CASE_MAPPING_ADDITIONAL_LENGTH 20
8803#ifndef CASEMAP_DEBUG
8804# define CASEMAP_DEBUG 0
8812 OnigUChar space[FLEX_ARY_LEN];
8816mapping_buffer_free(
void *p)
8820 while (current_buffer) {
8821 previous_buffer = current_buffer;
8822 current_buffer = current_buffer->next;
8823 ruby_xfree_sized(previous_buffer, offsetof(
mapping_buffer, space) + previous_buffer->capa);
8829 {0, mapping_buffer_free,},
8830 0, 0, RUBY_TYPED_THREAD_SAFE_FREE | RUBY_TYPED_WB_PROTECTED
8838 const OnigUChar *source_current, *source_end;
8839 int target_length = 0;
8840 VALUE buffer_anchor;
8843 size_t buffer_count = 0;
8844 int buffer_length_or_invalid;
8846 if (RSTRING_LEN(source) == 0)
return str_duplicate(
rb_cString, source);
8848 source_current = (OnigUChar*)RSTRING_PTR(source);
8853 while (source_current < source_end) {
8855 size_t capa = (size_t)(source_end-source_current)*++buffer_count + CASE_MAPPING_ADDITIONAL_LENGTH;
8856 if (CASEMAP_DEBUG) {
8857 fprintf(stderr,
"Buffer allocation, capa is %"PRIuSIZE
"\n",
capa);
8860 *pre_buffer = current_buffer;
8861 pre_buffer = ¤t_buffer->next;
8862 current_buffer->next = NULL;
8863 current_buffer->capa =
capa;
8864 buffer_length_or_invalid = enc->case_map(flags,
8865 &source_current, source_end,
8866 current_buffer->space,
8867 current_buffer->space+current_buffer->capa,
8869 if (buffer_length_or_invalid < 0) {
8870 current_buffer =
DATA_PTR(buffer_anchor);
8872 mapping_buffer_free(current_buffer);
8873 rb_raise(rb_eArgError,
"input string invalid");
8875 target_length += current_buffer->used = buffer_length_or_invalid;
8877 if (CASEMAP_DEBUG) {
8878 fprintf(stderr,
"Buffer count is %"PRIuSIZE
"\n", buffer_count);
8881 if (buffer_count==1) {
8882 target =
rb_str_new((
const char*)current_buffer->space, target_length);
8885 char *target_current;
8888 target_current = RSTRING_PTR(target);
8889 current_buffer =
DATA_PTR(buffer_anchor);
8890 while (current_buffer) {
8891 memcpy(target_current, current_buffer->space, current_buffer->used);
8892 target_current += current_buffer->used;
8893 current_buffer = current_buffer->next;
8896 current_buffer =
DATA_PTR(buffer_anchor);
8898 mapping_buffer_free(current_buffer);
8903 str_enc_copy_direct(target, source);
8912 const OnigUChar *source_current, *source_end;
8913 OnigUChar *target_current, *target_end;
8914 rb_len_t old_length = RSTRING_LEN(source);
8915 int length_or_invalid;
8917 if (old_length == 0)
return Qnil;
8919 source_current = (OnigUChar*)RSTRING_PTR(source);
8921 if (source == target) {
8922 target_current = (OnigUChar*)source_current;
8923 target_end = (OnigUChar*)source_end;
8926 target_current = (OnigUChar*)RSTRING_PTR(target);
8930 length_or_invalid = onigenc_ascii_only_case_map(flags,
8931 &source_current, source_end,
8932 target_current, target_end, enc);
8933 if (length_or_invalid < 0)
8934 rb_raise(rb_eArgError,
"input string invalid");
8935 if (CASEMAP_DEBUG && length_or_invalid != old_length) {
8936 fprintf(stderr,
"problem with rb_str_ascii_casemap"
8937 "; old_length=%"PRIdLEN
", new_length=%d\n", old_length, length_or_invalid);
8938 rb_raise(rb_eArgError,
"internal problem with rb_str_ascii_casemap"
8939 "; old_length=%"PRIdLEN
", new_length=%d\n", old_length, length_or_invalid);
8942 str_enc_copy(target, source);
8948upcase_single(
VALUE str)
8950 char *s = RSTRING_PTR(str), *send =
RSTRING_END(str);
8951 bool modified =
false;
8954 unsigned int c = *(
unsigned char*)s;
8956 if (
'a' <= c && c <=
'z') {
8957 *s =
'A' + (c -
'a');
8978rb_str_upcase_bang(
int argc,
VALUE *argv,
VALUE str)
8981 OnigCaseFoldType flags = ONIGENC_CASE_UPCASE;
8983 flags = check_case_options(argc, argv, flags);
8984 str_modify_keep_cr(str);
8985 enc = str_true_enc(str);
8986 if (case_option_single_p(flags, enc, str)) {
8987 if (upcase_single(str))
8988 flags |= ONIGENC_CASE_MODIFIED;
8990 else if (flags&ONIGENC_CASE_ASCII_ONLY)
8991 rb_str_ascii_casemap(str, str, &flags, enc);
8993 str_shared_replace(str, rb_str_casemap(str, &flags, enc));
8995 if (ONIGENC_CASE_MODIFIED&flags)
return str;
9008rb_str_upcase(
int argc,
VALUE *argv,
VALUE str)
9011 OnigCaseFoldType flags = ONIGENC_CASE_UPCASE;
9014 flags = check_case_options(argc, argv, flags);
9015 enc = str_true_enc(str);
9016 if (case_option_single_p(flags, enc, str)) {
9017 ret =
rb_str_new(RSTRING_PTR(str), RSTRING_LEN(str));
9018 str_enc_copy_direct(ret, str);
9021 else if (flags&ONIGENC_CASE_ASCII_ONLY) {
9023 rb_str_ascii_casemap(str, ret, &flags, enc);
9026 ret = rb_str_casemap(str, &flags, enc);
9033downcase_single(
VALUE str)
9035 char *s = RSTRING_PTR(str), *send =
RSTRING_END(str);
9036 bool modified =
false;
9039 unsigned int c = *(
unsigned char*)s;
9041 if (
'A' <= c && c <=
'Z') {
9042 *s =
'a' + (c -
'A');
9064rb_str_downcase_bang(
int argc,
VALUE *argv,
VALUE str)
9067 OnigCaseFoldType flags = ONIGENC_CASE_DOWNCASE;
9069 flags = check_case_options(argc, argv, flags);
9070 str_modify_keep_cr(str);
9071 enc = str_true_enc(str);
9072 if (case_option_single_p(flags, enc, str)) {
9073 if (downcase_single(str))
9074 flags |= ONIGENC_CASE_MODIFIED;
9076 else if (flags&ONIGENC_CASE_ASCII_ONLY)
9077 rb_str_ascii_casemap(str, str, &flags, enc);
9079 str_shared_replace(str, rb_str_casemap(str, &flags, enc));
9081 if (ONIGENC_CASE_MODIFIED&flags)
return str;
9095rb_str_downcase(
int argc,
VALUE *argv,
VALUE str)
9098 OnigCaseFoldType flags = ONIGENC_CASE_DOWNCASE;
9101 flags = check_case_options(argc, argv, flags);
9102 enc = str_true_enc(str);
9103 if (case_option_single_p(flags, enc, str)) {
9104 ret =
rb_str_new(RSTRING_PTR(str), RSTRING_LEN(str));
9105 str_enc_copy_direct(ret, str);
9106 downcase_single(ret);
9108 else if (flags&ONIGENC_CASE_ASCII_ONLY) {
9110 rb_str_ascii_casemap(str, ret, &flags, enc);
9113 ret = rb_str_casemap(str, &flags, enc);
9120capitalize_single(
VALUE str)
9122 char *s = RSTRING_PTR(str), *send =
RSTRING_END(str);
9123 bool modified =
false;
9126 unsigned int c = (
unsigned char)*s;
9128 if (
'a' <= c && c <=
'z') {
9129 *s =
'A' + (c -
'a');
9135 unsigned int c = (
unsigned char)*s;
9137 if (
'A' <= c && c <=
'Z') {
9138 *s =
'a' + (c -
'A');
9160rb_str_capitalize_bang(
int argc,
VALUE *argv,
VALUE str)
9163 OnigCaseFoldType flags = ONIGENC_CASE_UPCASE | ONIGENC_CASE_TITLECASE;
9165 flags = check_case_options(argc, argv, flags);
9166 str_modify_keep_cr(str);
9167 enc = str_true_enc(str);
9168 if (RSTRING_LEN(str) == 0 || !RSTRING_PTR(str))
return Qnil;
9169 if (case_option_single_p(flags, enc, str)) {
9170 if (capitalize_single(str))
9171 flags |= ONIGENC_CASE_MODIFIED;
9173 else if (flags&ONIGENC_CASE_ASCII_ONLY)
9174 rb_str_ascii_casemap(str, str, &flags, enc);
9176 str_shared_replace(str, rb_str_casemap(str, &flags, enc));
9178 if (ONIGENC_CASE_MODIFIED&flags)
return str;
9192rb_str_capitalize(
int argc,
VALUE *argv,
VALUE str)
9195 OnigCaseFoldType flags = ONIGENC_CASE_UPCASE | ONIGENC_CASE_TITLECASE;
9198 flags = check_case_options(argc, argv, flags);
9199 enc = str_true_enc(str);
9200 if (RSTRING_LEN(str) == 0 || !RSTRING_PTR(str))
return str;
9201 if (case_option_single_p(flags, enc, str)) {
9202 ret =
rb_str_new(RSTRING_PTR(str), RSTRING_LEN(str));
9203 str_enc_copy_direct(ret, str);
9204 capitalize_single(ret);
9206 else if (flags&ONIGENC_CASE_ASCII_ONLY) {
9208 rb_str_ascii_casemap(str, ret, &flags, enc);
9211 ret = rb_str_casemap(str, &flags, enc);
9230rb_str_swapcase_bang(
int argc,
VALUE *argv,
VALUE str)
9233 OnigCaseFoldType flags = ONIGENC_CASE_UPCASE | ONIGENC_CASE_DOWNCASE;
9235 flags = check_case_options(argc, argv, flags);
9236 str_modify_keep_cr(str);
9237 enc = str_true_enc(str);
9238 if (flags&ONIGENC_CASE_ASCII_ONLY)
9239 rb_str_ascii_casemap(str, str, &flags, enc);
9241 str_shared_replace(str, rb_str_casemap(str, &flags, enc));
9243 if (ONIGENC_CASE_MODIFIED&flags)
return str;
9257rb_str_swapcase(
int argc,
VALUE *argv,
VALUE str)
9260 OnigCaseFoldType flags = ONIGENC_CASE_UPCASE | ONIGENC_CASE_DOWNCASE;
9263 flags = check_case_options(argc, argv, flags);
9264 enc = str_true_enc(str);
9265 if (RSTRING_LEN(str) == 0 || !RSTRING_PTR(str))
return str_duplicate(
rb_cString, str);
9266 if (flags&ONIGENC_CASE_ASCII_ONLY) {
9268 rb_str_ascii_casemap(str, ret, &flags, enc);
9271 ret = rb_str_casemap(str, &flags, enc);
9276typedef unsigned char *USTR;
9280 unsigned int now, max;
9281 const char *p, *pend;
9292 if (t->p == t->pend)
return -1;
9293 if (rb_enc_ascget(t->p, t->pend, &n, enc) ==
'\\' && t->p + n < t->pend) {
9296 t->now = rb_enc_codepoint_len(t->p, t->pend, &n, enc);
9298 if (rb_enc_ascget(t->p, t->pend, &n, enc) ==
'-' && t->p + n < t->pend) {
9300 if (t->p < t->pend) {
9301 unsigned int c = rb_enc_codepoint_len(t->p, t->pend, &n, enc);
9304 if (t->now < 0x80 && c < 0x80) {
9305 rb_raise(rb_eArgError,
9306 "invalid range \"%c-%c\" in string transliteration",
9310 rb_raise(rb_eArgError,
"invalid range in string transliteration");
9314 else if (t->now < c) {
9323 while (ONIGENC_CODE_TO_MBCLEN(enc, ++t->now) <= 0) {
9324 if (t->now == t->max) {
9329 if (t->now < t->max) {
9345 const unsigned int errc = -1;
9346 unsigned int trans[256];
9348 struct tr trsrc, trrepl;
9350 unsigned int c, c0, last = 0;
9351 int modify = 0, i, l;
9352 unsigned char *s, *send;
9354 int singlebyte = single_byte_optimizable(str);
9358#define CHECK_IF_ASCII(c) \
9359 (void)((cr == ENC_CODERANGE_7BIT && !rb_isascii(c)) ? \
9360 (cr = ENC_CODERANGE_VALID) : 0)
9364 if (RSTRING_LEN(str) == 0 || !RSTRING_PTR(str))
return Qnil;
9365 if (RSTRING_LEN(repl) == 0) {
9366 return rb_str_delete_bang(1, &src, str);
9370 e1 = rb_enc_check(str, src);
9371 e2 = rb_enc_check(str, repl);
9376 enc = rb_enc_check(src, repl);
9378 trsrc.p = RSTRING_PTR(src); trsrc.pend = trsrc.p + RSTRING_LEN(src);
9379 if (RSTRING_LEN(src) > 1 &&
9380 rb_enc_ascget(trsrc.p, trsrc.pend, &l, enc) ==
'^' &&
9381 trsrc.p + l < trsrc.pend) {
9385 trrepl.p = RSTRING_PTR(repl);
9386 trrepl.pend = trrepl.p + RSTRING_LEN(repl);
9387 trsrc.gen = trrepl.gen = 0;
9388 trsrc.now = trrepl.now = 0;
9389 trsrc.max = trrepl.max = 0;
9392 for (i=0; i<256; i++) {
9395 while ((c = trnext(&trsrc, enc)) != errc) {
9400 if (!hash) hash = rb_hash_new();
9404 while ((c = trnext(&trrepl, enc)) != errc)
9407 for (i=0; i<256; i++) {
9408 if (trans[i] != errc) {
9416 for (i=0; i<256; i++) {
9419 while ((c = trnext(&trsrc, enc)) != errc) {
9420 r = trnext(&trrepl, enc);
9421 if (r == errc) r = trrepl.now;
9424 if (rb_enc_codelen(r, enc) != 1) singlebyte = 0;
9427 if (!hash) hash = rb_hash_new();
9435 str_modify_keep_cr(str);
9436 s = (
unsigned char *)RSTRING_PTR(str); send = (
unsigned char *)
RSTRING_END(str);
9437 termlen = rb_enc_mbminlen(enc);
9440 rb_len_t offset, max = RSTRING_LEN(str);
9441 unsigned int save = -1;
9442 unsigned char *buf =
ALLOC_N(
unsigned char, max + termlen), *t = buf;
9447 int r = rb_enc_precise_mbclen((
char *)s, (
char *)send, e1);
9449 SIZED_FREE_N(buf, max + termlen);
9450 rb_raise(rb_eArgError,
"invalid byte sequence in %s", rb_enc_name(e1));
9453 c0 = c = rb_enc_mbc_to_codepoint((
char *)s, (
char *)send, e1);
9455 tlen = enc == e1 ? clen : rb_enc_codelen(c, enc);
9464 if (cflag) c = last;
9467 else if (cflag) c = errc;
9473 if (c != (
unsigned int)-1) {
9479 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 + (send - s);
9490 SIZED_REALLOC_N(buf,
unsigned char, max + termlen, old);
9493 rb_enc_mbcput(c, t, enc);
9494 if (may_modify && memcmp(s, t, tlen) != 0) {
9500 if (!STR_EMBED_P(str)) {
9501 SIZED_FREE_N(STR_HEAP_PTR(str), STR_HEAP_SIZE(str));
9503 TERM_FILL((
char *)t, termlen);
9504 RSTRING(str)->as.heap.ptr = (
char *)buf;
9505 STR_SET_LEN(str, t - buf);
9506 STR_SET_NOEMBED(str);
9507 RSTRING(str)->as.heap.aux.capa = max;
9511 c = (
unsigned char)*s;
9512 if (trans[c] != errc) {
9530 unsigned char *buf =
ALLOC_N(
unsigned char, max + termlen), *t = buf;
9535 int r = rb_enc_precise_mbclen((
char *)s, (
char *)send, e1);
9537 SIZED_FREE_N(buf, max + termlen);
9538 rb_raise(rb_eArgError,
"invalid byte sequence in %s", rb_enc_name(e1));
9541 c0 = c = rb_enc_mbc_to_codepoint((
char *)s, (
char *)send, e1);
9543 tlen = enc == e1 ? clen : rb_enc_codelen(c, enc);
9551 if (cflag) c = last;
9554 else if (cflag) c = errc;
9558 c = cflag ? last : errc;
9561 tlen = rb_enc_codelen(c, enc);
9566 if (enc != e1) may_modify = 1;
9568 if ((offset = t - buf) + tlen > max) {
9569 size_t MAYBE_UNUSED(old) = max + termlen;
9570 max = offset + tlen + (
rb_len_t)((send - s) * 1.2);
9571 SIZED_REALLOC_N(buf,
unsigned char, max + termlen, old);
9575 rb_enc_mbcput(c, t, enc);
9576 if (may_modify && memcmp(s, t, tlen) != 0) {
9583 if (!STR_EMBED_P(str)) {
9584 SIZED_FREE_N(STR_HEAP_PTR(str), STR_HEAP_SIZE(str));
9586 TERM_FILL((
char *)t, termlen);
9587 RSTRING(str)->as.heap.ptr = (
char *)buf;
9588 STR_SET_LEN(str, t - buf);
9589 STR_SET_NOEMBED(str);
9590 RSTRING(str)->as.heap.aux.capa = max;
9596 rb_enc_associate(str, enc);
9606 size_t initial_capa;
9610tr_buffer_init(
struct tr_buffer *buffer,
size_t initial_capa)
9612 if (initial_capa < 32) {
9615 *buffer = (
struct tr_buffer){ .initial_capa = initial_capa };
9619tr_buffer_ensure_capa(
struct tr_buffer *buffer,
size_t extra_capa)
9621 size_t offset = buffer->ptr - buffer->buf;
9622 size_t required_capa = offset + extra_capa;
9623 if (UNLIKELY(buffer->capa < required_capa)) {
9624 size_t new_capa = buffer->capa ? buffer->capa : buffer->initial_capa;
9626 while (new_capa < required_capa) {
9627 new_capa = (size_t)(new_capa * 1.2);
9629 SIZED_REALLOC_N(buffer->buf,
unsigned char, new_capa, buffer->capa);
9630 buffer->ptr = buffer->buf + offset;
9631 buffer->capa = new_capa;
9636tr_buffer_append(
struct tr_buffer *buffer,
const unsigned char *ptr,
size_t len)
9639 tr_buffer_ensure_capa(buffer,
len);
9640 memcpy(buffer->ptr, ptr,
len);
9648 tr_buffer_append(buffer, (
unsigned char *)RSTRING_PTR(str), RSTRING_LEN(str));
9654 tr_buffer_ensure_capa(buffer, 4);
9655 buffer->ptr += rb_enc_mbcput(codepoint, buffer->ptr, enc);
9662 SIZED_FREE_N(buffer->buf, buffer->capa);
9679tr_trans_pairs_coerce_i(st_data_t key, st_data_t value, st_data_t _args)
9682 struct tr_pair *pair = &args->pairs[args->index];
9690 if (RSTRING_LEN(search) != 1 && str_strlen(search, NULL) != 1) {
9691 rb_raise(rb_eArgError,
"keys must be of size 1");
9694 args->enc = rb_enc_check_multi_str(args->enc, &args->cr, search);
9695 args->enc = rb_enc_check_multi_str(args->enc, &args->cr, replace);
9697 pair->search = search;
9698 pair->replace = replace;
9702#define TR_TRANS_PAIRS_SIMD_MAX_NEEDLES 16
9705 const unsigned char *s;
9706 const unsigned char *send;
9709 unsigned char needles[TR_TRANS_PAIRS_SIMD_MAX_NEEDLES];
9710 unsigned int needles_count;
9711#ifdef HAVE_SIMD_NEON
9712 uint64_t matches_bitmap;
9714#ifdef HAVE_SIMD_SSE2
9719 VALUE trans_table[256];
9725 while (search->s < search->send) {
9726 VALUE repl = search->trans_table[*search->s];
9727 if (UNLIKELY(repl)) {
9737#ifdef HAVE_SIMD_SSE2
9742 size_t trailing_zeros = (size_t)ntz_int32(search->matches_bitmap);
9744 RUBY_ASSERT(trailing_zeros < (
sizeof(search->matches_bitmap) * CHAR_BIT));
9745 search->matches_bitmap >>= trailing_zeros;
9746 search->s += trailing_zeros;
9749 return search->trans_table[*search->s];
9755 const unsigned int needles_count = search->needles_count;
9756 if (needles_count) {
9759 if (search->matches_bitmap) {
9760 return tr_trans_pairs_next_match_sse2(search);
9763 if ((
size_t)(search->send - search->s) >=
sizeof(__m128i)) {
9765 __m128i masks[TR_TRANS_PAIRS_SIMD_MAX_NEEDLES];
9766 for (i = 0; i < needles_count; i++) {
9767 masks[i] = _mm_set1_epi8(search->needles[i]);
9771 const __m128i bytes = _mm_loadu_si128((__m128i
const *)search->s);
9773 __m128i matches[TR_TRANS_PAIRS_SIMD_MAX_NEEDLES];
9774 for (i = 0; i < needles_count; i++) {
9775 matches[i] = _mm_cmpeq_epi8(bytes, masks[i]);
9778 for (i = 1; i < needles_count; i++) {
9779 matches[0] = _mm_or_si128(matches[0], matches[i]);
9782 const int bitmap = _mm_movemask_epi8(matches[0]);
9785 search->matches_bitmap = bitmap;
9786 return tr_trans_pairs_next_match_sse2(search);
9788 search->s +=
sizeof(__m128i);
9789 }
while ((
size_t)(search->send - search->s) >=
sizeof(__m128i));
9792 return tr_trans_pairs_search_basic(search);
9795#define tr_trans_pairs_search_impl tr_trans_pairs_search_sse2
9798#ifdef HAVE_SIMD_NEON
9803 size_t trailing_zeros = (size_t)ntz_int64(search->matches_bitmap);
9806 RUBY_ASSERT(trailing_zeros < (
sizeof(search->matches_bitmap) * CHAR_BIT));
9807 search->matches_bitmap >>= trailing_zeros;
9808 search->s += trailing_zeros / 4;
9811 return search->trans_table[*search->s];
9817 const unsigned int needles_count = search->needles_count;
9818 if (needles_count) {
9821 if (search->matches_bitmap) {
9822 return tr_trans_pairs_next_match_neon(search);
9825 if ((
size_t)(search->send - search->s) >=
sizeof(uint8x16_t)) {
9827 uint8x16_t masks[TR_TRANS_PAIRS_SIMD_MAX_NEEDLES];
9828 for (i = 0; i < needles_count; i++) {
9829 masks[i] = vdupq_n_u8(search->needles[i]);
9833 const uint8x16_t bytes = vld1q_u8(search->s);
9835 uint8x16_t matches[TR_TRANS_PAIRS_SIMD_MAX_NEEDLES];
9836 for (i = 0; i < needles_count; i++) {
9837 matches[i] = vceqq_u8(bytes, masks[i]);
9840 for (i = 1; i < needles_count; i++) {
9841 matches[0] = vorrq_u8(matches[0], matches[i]);
9844 const uint8x8_t res = vshrn_n_u16(vreinterpretq_u16_u8(matches[0]), 4);
9845 const uint64_t bitmap = vget_lane_u64(vreinterpret_u64_u8(res), 0);
9848 search->matches_bitmap = bitmap & 0x8888888888888888ull;
9849 return tr_trans_pairs_next_match_neon(search);
9851 search->s +=
sizeof(uint8x16_t);
9852 }
while ((
size_t)(search->send - search->s) >=
sizeof(uint8x16_t));
9855 return tr_trans_pairs_search_basic(search);
9858#define tr_trans_pairs_search_impl tr_trans_pairs_search_neon
9861#ifndef tr_trans_pairs_search_impl
9862#define tr_trans_pairs_search_impl tr_trans_pairs_search_basic
9870 search->matches_bitmap >>= 1;
9879 mustnot_broken(str);
9882 if (RSTRING_LEN(str) == 0 || !RSTRING_PTR(str) || pairs_count == 0)
return Qnil;
9887 int cr = rb_enc_str_coderange(str);
9901 pairs_count = coerce_args.index;
9905 const unsigned char *sstart = (
unsigned char *)RSTRING_PTR(str);
9906 rb_len_t str_len = RSTRING_LEN(str);
9907 int termlen = rb_enc_mbminlen(e1);
9910 tr_buffer_init(&buffer, str_len);
9911 bool modify =
false;
9913 if (RB_LIKELY(rb_str_encindex_fastpath(rb_enc_to_index(e1)))) {
9917 .send = sstart + str_len,
9920 for (
size_t index = 0; index < pairs_count; index++) {
9921 struct tr_pair *pair = &pairs[index];
9923 char *ptr = RSTRING_PTR(pair->search);
9924 unsigned int codepoint = rb_enc_mbc_to_codepoint(ptr,
RSTRING_END(pair->search), e1);
9926 const unsigned char first_byte = (
unsigned char)*ptr;
9929 if (pairs_count <= TR_TRANS_PAIRS_SIMD_MAX_NEEDLES) {
9930 search.needles[index] = first_byte;
9931 search.needles_count++;
9935 if (rb_enc_codelen(codepoint, e1) == 1) {
9936 search.trans_table[first_byte] = pair->replace;
9939 search.trans_table[first_byte] =
Qundef;
9941 hash =
rb_obj_hide(rb_hash_new_capa(pairs_count));
9943 rb_hash_aset(hash,
UINT2NUM(codepoint), pair->replace);
9947 const unsigned char *checkpoint = search.s;
9949 while ((repl = tr_trans_pairs_search_impl(&search))) {
9952 if (UNLIKELY(repl ==
Qundef)) {
9953 unsigned int c = rb_enc_mbc_to_codepoint((
char *)search.s, (
char *)search.send, e1);
9954 clen = rb_enc_codelen(c, e1);
9955 repl = rb_hash_lookup2(hash,
UINT2NUM(c), 0);
9957 tr_trans_pairs_consume_match(&search);
9965 if (checkpoint < search.s) {
9966 tr_buffer_append(&buffer, checkpoint, search.s - checkpoint);
9968 tr_buffer_append_str(&buffer, repl);
9969 checkpoint = search.s + clen;
9970 tr_trans_pairs_consume_match(&search);
9977 if (modify && checkpoint < search.s) {
9978 tr_buffer_append(&buffer, checkpoint, search.s - checkpoint);
9982 const unsigned char *s = sstart;
9983 const unsigned char *send = sstart + str_len;
9985 hash =
rb_obj_hide(rb_hash_new_capa(pairs_count));
9987 for (
size_t index = 0; index < pairs_count; index++) {
9988 struct tr_pair *pair = &pairs[index];
9990 unsigned int codepoint = rb_enc_mbc_to_codepoint(RSTRING_PTR(pair->search),
RSTRING_END(pair->search), e1);
9991 rb_hash_aset(hash,
UINT2NUM(codepoint), pair->replace);
9995 bool may_modify =
false;
9997 int r = rb_enc_precise_mbclen((
char *)s, (
char *)send, e1);
9999 tr_buffer_free(&buffer);
10000 rb_raise(rb_eArgError,
"invalid byte sequence in %s", rb_enc_name(e1));
10003 unsigned int c = rb_enc_mbc_to_codepoint((
char *)s, (
char *)send, e1);
10004 unsigned int c0 = c;
10006 rb_len_t tlen = enc == e1 ? clen : rb_enc_codelen(c, e1);
10009 if (
NIL_P(replacement)) {
10010 tlen = enc == e1 ? clen : rb_enc_codelen(c, enc);
10012 if (enc != e1) may_modify =
true;
10015 tlen = RSTRING_LEN(replacement);
10019 if (
NIL_P(replacement)) {
10020 tr_buffer_mbcput(&buffer, c, enc);
10023 tr_buffer_append_str(&buffer, replacement);
10026 if (may_modify && memcmp(s, buffer.ptr - tlen, tlen) != 0) {
10044 if (!STR_EMBED_P(str)) {
10045 SIZED_FREE_N(STR_HEAP_PTR(str), STR_HEAP_SIZE(str));
10047 tr_buffer_ensure_capa(&buffer, termlen);
10048 TERM_FILL((
char *)buffer.ptr, termlen);
10049 RSTRING(str)->as.heap.ptr = (
char *)buffer.buf;
10050 STR_SET_LEN(str, buffer.ptr - buffer.buf);
10051 STR_SET_NOEMBED(str);
10052 RSTRING(str)->as.heap.aux.capa = buffer.capa - termlen;
10058 rb_enc_associate(str, e1);
10076rb_str_tr_bang(
int argc,
VALUE *argv,
VALUE str)
10081 VALUE pairs = argv[0];
10082 return tr_trans_pairs(str, pairs);
10085 VALUE src = argv[0], repl = argv[1];
10086 return tr_trans(str, src, repl, 0);
10153 VALUE pairs = argv[0];
10154 VALUE result = tr_trans_pairs(str, pairs);
10155 if (
NIL_P(result)) result = str;
10159 VALUE src = argv[0], repl = argv[1];
10160 tr_trans(str, src, repl, 0);
10164#define TR_TABLE_MAX (UCHAR_MAX+1)
10165#define TR_TABLE_SIZE (TR_TABLE_MAX+1)
10167tr_setup_table(
VALUE str,
char stable[TR_TABLE_SIZE],
int first,
10170 const unsigned int errc = -1;
10171 char buf[TR_TABLE_MAX];
10174 VALUE table = 0, ptable = 0;
10175 int i, l, cflag = 0;
10177 tr.p = RSTRING_PTR(str);
tr.pend =
tr.p + RSTRING_LEN(str);
10178 tr.gen =
tr.now =
tr.max = 0;
10180 if (RSTRING_LEN(str) > 1 && rb_enc_ascget(
tr.p,
tr.pend, &l, enc) ==
'^') {
10185 for (i=0; i<TR_TABLE_MAX; i++) {
10188 stable[TR_TABLE_MAX] = cflag;
10190 else if (stable[TR_TABLE_MAX] && !cflag) {
10191 stable[TR_TABLE_MAX] = 0;
10193 for (i=0; i<TR_TABLE_MAX; i++) {
10197 while ((c = trnext(&
tr, enc)) != errc) {
10198 if (c < TR_TABLE_MAX) {
10199 buf[(
unsigned char)c] = !cflag;
10204 if (!table && (first || *tablep || stable[TR_TABLE_MAX])) {
10207 table = ptable ? ptable : rb_hash_new();
10211 table = rb_hash_new();
10216 if (table && (!ptable || (cflag ^ !
NIL_P(rb_hash_aref(ptable, key))))) {
10217 rb_hash_aset(table, key,
Qtrue);
10221 for (i=0; i<TR_TABLE_MAX; i++) {
10222 stable[i] = stable[i] && buf[i];
10224 if (!table && !cflag) {
10231tr_find(
unsigned int c,
const char table[TR_TABLE_SIZE],
VALUE del,
VALUE nodel)
10233 if (c < TR_TABLE_MAX) {
10234 return table[c] != 0;
10240 if (!
NIL_P(rb_hash_lookup(del, v)) &&
10241 (!nodel ||
NIL_P(rb_hash_lookup(nodel, v)))) {
10245 else if (nodel && !
NIL_P(rb_hash_lookup(nodel, v))) {
10248 return table[TR_TABLE_MAX] ? TRUE : FALSE;
10263rb_str_delete_bang(
int argc,
VALUE *argv,
VALUE str)
10265 char squeez[TR_TABLE_SIZE];
10267 char *s, *send, *t;
10268 VALUE del = 0, nodel = 0;
10270 int i, ascompat, cr;
10272 if (RSTRING_LEN(str) == 0 || !RSTRING_PTR(str))
return Qnil;
10274 for (i=0; i<argc; i++) {
10278 enc = rb_enc_check(str, s);
10279 tr_setup_table(s, squeez, i==0, &del, &nodel, enc);
10282 str_modify_keep_cr(str);
10283 ascompat = rb_enc_asciicompat(enc);
10284 s = t = RSTRING_PTR(str);
10291 if (ascompat && (c = *(
unsigned char*)s) < 0x80) {
10296 if (t != s) *t = c;
10302 c = rb_enc_codepoint_len(s, send, &clen, enc);
10304 if (tr_find(c, squeez, del, nodel)) {
10308 if (t != s) rb_enc_mbcput(c, t, enc);
10315 TERM_FILL(t, TERM_LEN(str));
10316 STR_SET_LEN(str, t - RSTRING_PTR(str));
10319 if (modify)
return str;
10333rb_str_delete(
int argc,
VALUE *argv,
VALUE str)
10336 rb_str_delete_bang(argc, argv, str);
10354rb_str_squeeze_bang(
int argc,
VALUE *argv,
VALUE str)
10356 char squeez[TR_TABLE_SIZE];
10358 VALUE del = 0, nodel = 0;
10359 unsigned char *s, *send, *t;
10361 int ascompat, singlebyte = single_byte_optimizable(str);
10365 enc = STR_ENC_GET(str);
10368 for (i=0; i<argc; i++) {
10372 enc = rb_enc_check(str, s);
10373 if (singlebyte && !single_byte_optimizable(s))
10375 tr_setup_table(s, squeez, i==0, &del, &nodel, enc);
10379 str_modify_keep_cr(str);
10380 s = t = (
unsigned char *)RSTRING_PTR(str);
10381 if (!s || RSTRING_LEN(str) == 0)
return Qnil;
10384 ascompat = rb_enc_asciicompat(enc);
10388 unsigned int c = *s++;
10389 if (c != save || (argc > 0 && !squeez[c])) {
10399 if (ascompat && (c = *s) < 0x80) {
10400 if (c != save || (argc > 0 && !squeez[c])) {
10406 c = rb_enc_codepoint_len((
char *)s, (
char *)send, &clen, enc);
10408 if (c != save || (argc > 0 && !tr_find(c, squeez, del, nodel))) {
10409 if (t != s) rb_enc_mbcput(c, t, enc);
10418 TERM_FILL((
char *)t, TERM_LEN(str));
10419 if ((
char *)t - RSTRING_PTR(str) != RSTRING_LEN(str)) {
10420 STR_SET_LEN(str, (
char *)t - RSTRING_PTR(str));
10424 if (modify)
return str;
10438rb_str_squeeze(
int argc,
VALUE *argv,
VALUE str)
10441 rb_str_squeeze_bang(argc, argv, str);
10461 return tr_trans(str, src, repl, 1);
10489 tr_trans(str, src, repl, 1);
10502rb_str_count(
int argc,
VALUE *argv,
VALUE str)
10504 char table[TR_TABLE_SIZE];
10506 VALUE del = 0, nodel = 0, tstr;
10507 const char *s, *send;
10516 enc = rb_enc_check(str, tstr);
10519 if (RSTRING_LEN(tstr) == 1 && rb_enc_asciicompat(enc) &&
10520 (ptstr = RSTRING_PTR(tstr),
10521 ONIGENC_IS_ALLOWED_REVERSE_MATCH(enc, (
const unsigned char *)ptstr, (
const unsigned char *)ptstr+1)) &&
10522 !is_broken_string(str)) {
10524 unsigned char c = rb_enc_codepoint_len(ptstr, ptstr+1, &clen, enc);
10526 s = RSTRING_PTR(str);
10527 if (!s || RSTRING_LEN(str) == 0)
return INT2FIX(0);
10530 if (*(
unsigned char*)s++ == c) n++;
10536 tr_setup_table(tstr, table, TRUE, &del, &nodel, enc);
10537 for (i=1; i<argc; i++) {
10540 enc = rb_enc_check(str, tstr);
10541 tr_setup_table(tstr, table, FALSE, &del, &nodel, enc);
10544 s = RSTRING_PTR(str);
10545 if (!s || RSTRING_LEN(str) == 0)
return INT2FIX(0);
10547 ascompat = rb_enc_asciicompat(enc);
10551 if (ascompat && (c = *(
unsigned char*)s) < 0x80) {
10559 c = rb_enc_codepoint_len(s, send, &clen, enc);
10560 if (tr_find(c, table, del, nodel)) {
10571rb_fs_check(
VALUE val)
10575 if (
NIL_P(val))
return 0;
10580static const char isspacetable[256] = {
10581 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0,
10582 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
10583 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
10584 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
10585 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
10586 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
10587 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
10588 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
10589 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
10590 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
10591 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
10592 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
10593 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
10594 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
10595 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
10596 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
10599#define ascii_isspace(c) isspacetable[(unsigned char)(c)]
10604 if (empty_count >= 0 &&
len == 0) {
10605 return empty_count + 1;
10607 if (empty_count > 0) {
10612 }
while (--empty_count > 0);
10616 rb_yield(str_new_empty_String(str));
10617 }
while (--empty_count > 0);
10627 return empty_count;
10631 SPLIT_TYPE_AWK, SPLIT_TYPE_STRING, SPLIT_TYPE_REGEXP, SPLIT_TYPE_CHARS
10635literal_split_pattern(
VALUE spat, split_type_t default_type)
10643 return SPLIT_TYPE_CHARS;
10645 else if (rb_enc_asciicompat(enc)) {
10646 if (
len == 1 && ptr[0] ==
' ') {
10647 return SPLIT_TYPE_AWK;
10652 if (rb_enc_ascget(ptr, ptr +
len, &l, enc) ==
' ' &&
len == l) {
10653 return SPLIT_TYPE_AWK;
10656 return default_type;
10669rb_str_split_m(
int argc,
VALUE *argv,
VALUE str)
10674 split_type_t split_type;
10675 rb_len_t beg, end, i = 0, empty_count = -1;
10680 if (
rb_scan_args(argc, argv,
"02", &spat, &limit) == 2) {
10682 if (lim <= 0) limit =
Qnil;
10683 else if (lim == 1) {
10684 if (RSTRING_LEN(str) == 0)
10695 if (
NIL_P(limit) && !lim) empty_count = 0;
10697 enc = STR_ENC_GET(str);
10698 split_type = SPLIT_TYPE_REGEXP;
10699 if (!
NIL_P(spat)) {
10700 spat = get_pat_quoted(spat, 0);
10702 else if (
NIL_P(spat = rb_fs)) {
10703 split_type = SPLIT_TYPE_AWK;
10705 else if (!(spat = rb_fs_check(spat))) {
10706 rb_raise(
rb_eTypeError,
"value of $; must be String or Regexp");
10711 if (split_type != SPLIT_TYPE_AWK) {
10716 split_type = literal_split_pattern(tmp, SPLIT_TYPE_REGEXP);
10717 if (split_type == SPLIT_TYPE_AWK) {
10719 split_type = SPLIT_TYPE_STRING;
10724 mustnot_broken(spat);
10725 split_type = literal_split_pattern(spat, SPLIT_TYPE_STRING);
10733#define SPLIT_STR(beg, len) ( \
10734 empty_count = split_string(result, str, beg, len, empty_count), \
10735 str_mod_check(str, str_start, str_len))
10738 const char *ptr = RSTRING_PTR(str);
10739 const char *
const str_start = ptr;
10740 const rb_len_t str_len = RSTRING_LEN(str);
10741 const char *
const eptr = str_start + str_len;
10742 if (split_type == SPLIT_TYPE_AWK) {
10743 const char *bptr = ptr;
10749 if (is_ascii_string(str)) {
10750 while (ptr < eptr) {
10751 c = (
unsigned char)*ptr++;
10753 if (ascii_isspace(c)) {
10759 if (!
NIL_P(limit) && lim <= i)
break;
10762 else if (ascii_isspace(c)) {
10763 SPLIT_STR(beg, end-beg);
10766 if (!
NIL_P(limit)) ++i;
10774 while (ptr < eptr) {
10777 c = rb_enc_codepoint_len(ptr, eptr, &n, enc);
10786 if (!
NIL_P(limit) && lim <= i)
break;
10790 SPLIT_STR(beg, end-beg);
10793 if (!
NIL_P(limit)) ++i;
10801 else if (split_type == SPLIT_TYPE_STRING) {
10802 const char *substr_start = ptr;
10803 const char *sptr = RSTRING_PTR(spat);
10804 rb_len_t slen = RSTRING_LEN(spat);
10807 mustnot_broken(str);
10808 enc = rb_enc_check(str, spat);
10809 while (ptr < eptr &&
10810 (end =
rb_memsearch(sptr, slen, ptr, eptr - ptr, enc)) >= 0) {
10813 if (t != ptr + end) {
10817 SPLIT_STR(substr_start - str_start, (ptr+end) - substr_start);
10818 str_mod_check(spat, sptr, slen);
10820 substr_start = ptr;
10821 if (!
NIL_P(limit) && lim <= ++i)
break;
10823 beg = ptr - str_start;
10825 else if (split_type == SPLIT_TYPE_CHARS) {
10829 mustnot_broken(str);
10830 enc = rb_enc_get(str);
10831 while (ptr < eptr &&
10832 (n = rb_enc_precise_mbclen(ptr, eptr, enc)) > 0) {
10833 SPLIT_STR(ptr - str_start, n);
10835 if (!
NIL_P(limit) && lim <= ++i)
break;
10837 beg = ptr - str_start;
10848 VALUE search = str;
10851 (match ? (rb_match_unbusy(match),
rb_backref_set(match)) : (void)0)) {
10853 search =
RMATCH(match)->str;
10855 end = RMATCH_BEG(match, 0);
10856 if (start == end && RMATCH_BEG(match, 0) == RMATCH_END(match, 0)) {
10861 else if (last_null == 1) {
10862 SPLIT_STR(beg, rb_enc_fast_mbclen(ptr+beg, eptr, enc));
10869 start += rb_enc_fast_mbclen(ptr+start,eptr,enc);
10875 SPLIT_STR(beg, end-beg);
10876 beg = start = RMATCH_END(match, 0);
10880 for (idx = 1; idx < RMATCH_NREGS(match); idx++) {
10881 if (RMATCH_BEG(match, idx) == -1)
continue;
10882 SPLIT_STR(RMATCH_BEG(match, idx), RMATCH_END(match, idx) - RMATCH_BEG(match, idx));
10884 if (!
NIL_P(limit) && lim <= ++i)
break;
10886 if (match) rb_match_unbusy(match);
10888 if (RSTRING_LEN(str) > 0 && (!
NIL_P(limit) || RSTRING_LEN(str) > beg || lim < 0)) {
10889 SPLIT_STR(beg, RSTRING_LEN(str)-beg);
10892 return result ? result : str;
10902 return rb_str_split_m(1, &sep, str);
10905#define WANTARRAY(m, size) (!rb_block_given_p() ? rb_ary_new_capa(size) : 0)
10920#define ENUM_ELEM(ary, e) enumerator_element(ary, e)
10923chomp_newline(
const char *p,
const char *e,
rb_encoding *enc)
10925 const char *prev = rb_enc_prev_char(p, e, e, enc);
10928 prev = rb_enc_prev_char(p, e, e, enc);
10929 if (prev && rb_enc_ascget(prev, e, NULL, enc) ==
'\r')
10941 RSTRING_LEN(rs) != 1 ||
10942 RSTRING_PTR(rs)[0] !=
'\n')) {
10948#define rb_rs get_rs()
10955 const char *pend, *subptr, *subend, *rsptr, *hit, *adjusted;
10961 if (!
NIL_P(opts)) {
10962 static ID keywords[1];
10963 if (!keywords[0]) {
10967 chomp = (!UNDEF_P(chomp) &&
RTEST(chomp));
10971 if (!ENUM_ELEM(ary, str)) {
10979 if (!RSTRING_LEN(str))
goto end;
10981 const char *
const ptr = subptr = RSTRING_PTR(str);
10985 rslen = RSTRING_LEN(rs);
10988 enc = rb_enc_get(str);
10990 enc = rb_enc_check(str, rs);
10995 const char *eol = NULL;
10997 while (subend < pend) {
11000 if (rb_enc_ascget(subend, pend, &n, enc) !=
'\r')
11002 rslen = n + rb_enc_mbclen(subend + n, pend, enc);
11004 if (eol == subend)
break;
11008 chomp_rslen = -rslen;
11012 if (!subptr) subptr = subend;
11016 }
while (subend < pend);
11017 if (!subptr)
break;
11018 if (rslen == 0) chomp_rslen = 0;
11020 subend - subptr + (chomp ? chomp_rslen : rslen));
11021 if (ENUM_ELEM(ary, line)) {
11022 str_mod_check(str, ptr,
len);
11024 subptr = eol = NULL;
11029 rsptr = RSTRING_PTR(rs);
11030 if (RSTRING_LEN(rs) == rb_enc_mbminlen(enc) &&
11039 rsptr = RSTRING_PTR(rs);
11040 rslen = RSTRING_LEN(rs);
11043 while (subptr < pend) {
11044 pos =
rb_memsearch(rsptr, rslen, subptr, pend - subptr, enc);
11045 if (pos < 0)
break;
11046 hit = subptr + pos;
11048 if (hit != adjusted) {
11052 subend = hit += rslen;
11055 subend = chomp_newline(subptr, subend, enc);
11062 if (ENUM_ELEM(ary, line)) {
11063 str_mod_check(str, ptr,
len);
11064 str_mod_check(rs, rsptr, rslen);
11069 if (subptr < pend) {
11072 pend = chomp_newline(subptr, pend, enc);
11074 else if (pend - subptr >= rslen &&
11075 memcmp(pend - rslen, rsptr, rslen) == 0) {
11080 ENUM_ELEM(ary, line);
11101rb_str_each_line(
int argc,
VALUE *argv,
VALUE str)
11104 return rb_str_enumerate_lines(argc, argv, str, 0);
11159rb_str_lines(
int argc,
VALUE *argv,
VALUE str)
11161 VALUE ary = WANTARRAY(
"lines", 0);
11162 return rb_str_enumerate_lines(argc, argv, str, ary);
11168 return LEN2NUM(RSTRING_LEN(str));
11176 for (i=0; i<RSTRING_LEN(str); i++) {
11177 ENUM_ELEM(ary,
INT2FIX((
unsigned char)RSTRING_PTR(str)[i]));
11195rb_str_each_byte(
VALUE str)
11198 return rb_str_enumerate_bytes(str, 0);
11210rb_str_bytes(
VALUE str)
11212 VALUE ary = WANTARRAY(
"bytes", RSTRING_LEN(str));
11213 return rb_str_enumerate_bytes(str, ary);
11231 ptr = RSTRING_PTR(str);
11232 len = RSTRING_LEN(str);
11233 enc = rb_enc_get(str);
11236 for (i = 0; i <
len; i += n) {
11237 n = rb_enc_fast_mbclen(ptr + i, ptr +
len, enc);
11242 for (i = 0; i <
len; i += n) {
11243 n = rb_enc_mbclen(ptr + i, ptr +
len, enc);
11264rb_str_each_char(
VALUE str)
11267 return rb_str_enumerate_chars(str, 0);
11279rb_str_chars(
VALUE str)
11282 return rb_str_enumerate_chars(str, ary);
11286rb_str_enumerate_codepoints(
VALUE str,
VALUE ary)
11291 const char *ptr, *end;
11293 int enc_asciicompat;
11295 if (single_byte_optimizable(str))
11296 return rb_str_enumerate_bytes(str, ary);
11299 ptr = RSTRING_PTR(str);
11301 enc = STR_ENC_GET(str);
11302 enc_asciicompat = rb_enc_asciicompat(enc);
11304 while (ptr < end) {
11309 c = (enc_asciicompat &&
ISASCII(*ptr)) ?
11310 (
unsigned char)*ptr : rb_enc_codepoint_len(ptr, end, &n, enc);
11331rb_str_each_codepoint(
VALUE str)
11334 return rb_str_enumerate_codepoints(str, 0);
11346rb_str_codepoints(
VALUE str)
11349 return rb_str_enumerate_codepoints(str, ary);
11355 int encidx = rb_enc_to_index(enc);
11357 const OnigUChar source_ascii[] =
"\\X";
11358 const OnigUChar *source = source_ascii;
11359 size_t source_len =
sizeof(source_ascii) - 1;
11362#define CHARS_16BE(x) (OnigUChar)((x)>>8), (OnigUChar)(x)
11363#define CHARS_16LE(x) (OnigUChar)(x), (OnigUChar)((x)>>8)
11364#define CHARS_32BE(x) CHARS_16BE((x)>>16), CHARS_16BE(x)
11365#define CHARS_32LE(x) CHARS_16LE(x), CHARS_16LE((x)>>16)
11366#define CASE_UTF(e) \
11367 case ENCINDEX_UTF_##e: { \
11368 static const OnigUChar source_UTF_##e[] = {CHARS_##e('\\'), CHARS_##e('X')}; \
11369 source = source_UTF_##e; \
11370 source_len = sizeof(source_UTF_##e); \
11373 CASE_UTF(16BE); CASE_UTF(16LE); CASE_UTF(32BE); CASE_UTF(32LE);
11381 regex_t *reg_grapheme_cluster;
11383 int r = onig_new(®_grapheme_cluster, source, source + source_len,
11384 ONIG_OPTION_DEFAULT, enc, OnigDefaultSyntax, &einfo);
11386 UChar message[ONIG_MAX_ERROR_MESSAGE_LEN];
11387 onig_error_code_to_str(message, r, &einfo);
11388 rb_fatal(
"cannot compile grapheme cluster regexp: %s", (
char *)message);
11391 return reg_grapheme_cluster;
11397 int encidx = rb_enc_to_index(enc);
11398 static regex_t *reg_grapheme_cluster_utf8 = NULL;
11400 if (encidx == rb_utf8_encindex()) {
11401 if (!reg_grapheme_cluster_utf8) {
11402 reg_grapheme_cluster_utf8 = get_reg_grapheme_cluster(enc);
11405 return reg_grapheme_cluster_utf8;
11414 size_t grapheme_cluster_count = 0;
11416 const char *ptr, *end;
11418 if (!rb_enc_unicode_p(enc)) {
11422 bool cached_reg_grapheme_cluster =
true;
11423 regex_t *reg_grapheme_cluster = get_cached_reg_grapheme_cluster(enc);
11424 if (!reg_grapheme_cluster) {
11425 reg_grapheme_cluster = get_reg_grapheme_cluster(enc);
11426 cached_reg_grapheme_cluster =
false;
11429 ptr = RSTRING_PTR(str);
11432 while (ptr < end) {
11433 OnigPosition
len = onig_match(reg_grapheme_cluster,
11434 (
const OnigUChar *)ptr, (
const OnigUChar *)end,
11435 (
const OnigUChar *)ptr, NULL, 0);
11436 if (
len <= 0)
break;
11437 grapheme_cluster_count++;
11441 if (!cached_reg_grapheme_cluster) {
11442 onig_free(reg_grapheme_cluster);
11445 return SIZET2NUM(grapheme_cluster_count);
11449rb_str_enumerate_grapheme_clusters(
VALUE str,
VALUE ary)
11453 const char *ptr0, *ptr, *end;
11455 if (!rb_enc_unicode_p(enc)) {
11456 return rb_str_enumerate_chars(str, ary);
11461 bool cached_reg_grapheme_cluster =
true;
11462 regex_t *reg_grapheme_cluster = get_cached_reg_grapheme_cluster(enc);
11463 if (!reg_grapheme_cluster) {
11464 reg_grapheme_cluster = get_reg_grapheme_cluster(enc);
11465 cached_reg_grapheme_cluster =
false;
11468 ptr0 = ptr = RSTRING_PTR(str);
11471 while (ptr < end) {
11472 OnigPosition
len = onig_match(reg_grapheme_cluster,
11473 (
const OnigUChar *)ptr, (
const OnigUChar *)end,
11474 (
const OnigUChar *)ptr, NULL, 0);
11475 if (
len <= 0)
break;
11480 if (!cached_reg_grapheme_cluster) {
11481 onig_free(reg_grapheme_cluster);
11501rb_str_each_grapheme_cluster(
VALUE str)
11504 return rb_str_enumerate_grapheme_clusters(str, 0);
11516rb_str_grapheme_clusters(
VALUE str)
11519 return rb_str_enumerate_grapheme_clusters(str, ary);
11523chopped_length(
VALUE str)
11526 const char *p, *p2, *beg, *end;
11528 beg = RSTRING_PTR(str);
11529 end = beg + RSTRING_LEN(str);
11530 if (beg >= end)
return 0;
11531 p = rb_enc_prev_char(beg, end, end, enc);
11533 if (p > beg && rb_enc_ascget(p, end, 0, enc) ==
'\n') {
11534 p2 = rb_enc_prev_char(beg, p, end, enc);
11535 if (p2 && rb_enc_ascget(p2, end, 0, enc) ==
'\r') p = p2;
11553rb_str_chop_bang(
VALUE str)
11555 str_modify_keep_cr(str);
11556 if (RSTRING_LEN(str) > 0) {
11558 len = chopped_length(str);
11559 STR_SET_LEN(str,
len);
11560 TERM_FILL(&RSTRING_PTR(str)[
len], TERM_LEN(str));
11579rb_str_chop(
VALUE str)
11585smart_chomp(
VALUE str,
const char *e,
const char *p)
11588 if (rb_enc_mbminlen(enc) > 1) {
11590 if (e - p < rb_enc_mbminlen(enc))
return e - p;
11595 pp = e - rb_enc_mbminlen(enc);
11598 if (rb_enc_ascget(pp, e, 0, enc) ==
'\r') {
11606 if (--e > p && *(e-1) ==
'\r') {
11623 const char *pp, *e, *rsptr;
11625 const char *
const p = RSTRING_PTR(str);
11628 if (
len == 0)
return 0;
11631 return smart_chomp(str, e, p);
11634 enc = rb_enc_get(str);
11637 if (rb_enc_mbminlen(enc) > 1) {
11638 while (e - p >= rb_enc_mbminlen(enc)) {
11642 pp -= rb_enc_mbminlen(enc);
11645 if (rb_enc_ascget(pp, e, 0, enc) ==
'\r') {
11652 while (e > p && *(e-1) ==
'\n') {
11654 if (e > p && *(e-1) ==
'\r')
11660 if (rslen >
len)
return len;
11662 enc = rb_enc_get(rs);
11663 newline = rsptr[rslen-1];
11664 if (rslen == rb_enc_mbminlen(enc)) {
11666 if (newline ==
'\n')
11667 return smart_chomp(str, e, p);
11671 return smart_chomp(str, e, p);
11675 enc = rb_enc_check(str, rs);
11676 if (is_broken_string(rs)) {
11680 if (p[
len-1] == newline &&
11682 memcmp(rsptr, pp, rslen) == 0)) {
11683 if (at_char_boundary(p, pp, e, enc))
11684 return len - rslen;
11696chomp_rs(
int argc,
const VALUE *argv)
11700 VALUE rs = argv[0];
11712 str_modify_keep_cr(str);
11713 STR_SET_LEN(str,
len);
11714 TERM_FILL(&RSTRING_PTR(str)[
len], TERM_LEN(str));
11726 if (
len >= olen)
return Qnil;
11727 return str_shrink(str,
len);
11743rb_str_chomp_bang(
int argc,
VALUE *argv,
VALUE str)
11746 str_modifiable(str);
11747 if (RSTRING_LEN(str) == 0 && argc < 2)
return Qnil;
11748 rs = chomp_rs(argc, argv);
11750 return rb_str_chomp_string(str, rs);
11763rb_str_chomp(
int argc,
VALUE *argv,
VALUE str)
11765 VALUE rs = chomp_rs(argc, argv);
11771tr_setup_table_multi(
char table[TR_TABLE_SIZE],
VALUE *tablep,
VALUE *ctablep,
11772 VALUE str,
int num_selectors,
VALUE *selectors)
11776 for (i=0; i<num_selectors; i++) {
11777 VALUE selector = selectors[i];
11781 enc = rb_enc_check(str, selector);
11782 tr_setup_table(selector, table, i==0, tablep, ctablep, enc);
11789 const char *
const start = s;
11791 if (!s || s >= e)
return 0;
11794 if (single_byte_optimizable(str)) {
11795 while (s < e && (*s ==
'\0' || ascii_isspace(*s))) s++;
11800 unsigned int cc = rb_enc_codepoint_len(s, e, &n, enc);
11810lstrip_offset_table(
VALUE str,
const char *s,
const char *e,
rb_encoding *enc,
11811 char table[TR_TABLE_SIZE],
VALUE del,
VALUE nodel)
11813 const char *
const start = s;
11815 if (!s || s >= e)
return 0;
11820 unsigned int cc = rb_enc_codepoint_len(s, e, &n, enc);
11822 if (!tr_find(cc, table, del, nodel))
break;
11841rb_str_lstrip_bang(
int argc,
VALUE *argv,
VALUE str)
11847 str_modify_keep_cr(str);
11848 enc = STR_ENC_GET(str);
11851 char table[TR_TABLE_SIZE];
11852 VALUE del = 0, nodel = 0;
11854 tr_setup_table_multi(table, &del, &nodel, str, argc, argv);
11857 str_modify_keep_cr(str);
11858 enc = STR_ENC_GET(str);
11861 loffset = lstrip_offset_table(str, start, start+olen, enc, table, del, nodel);
11864 loffset = lstrip_offset(str, start, start+olen, enc);
11869 memmove(start, start + loffset,
len);
11870 STR_SET_LEN(str,
len);
11871 TERM_FILL(start+
len, rb_enc_mbminlen(enc));
11906rb_str_lstrip(
int argc,
VALUE *argv,
VALUE str)
11913 char table[TR_TABLE_SIZE];
11914 VALUE del = 0, nodel = 0;
11916 tr_setup_table_multi(table, &del, &nodel, str, argc, argv);
11921 loffset = lstrip_offset_table(str, start, start+
len, STR_ENC_GET(str), table, del, nodel);
11924 loffset = lstrip_offset(str, start, start+
len, STR_ENC_GET(str));
11926 if (loffset <= 0)
return str_duplicate(
rb_cString, str);
11935 rb_str_check_dummy_enc(enc);
11939 if (!s || s >= e)
return 0;
11943 if (single_byte_optimizable(str)) {
11945 while (s < t && ((c = *(t-1)) ==
'\0' || ascii_isspace(c))) t--;
11950 while ((tp = rb_enc_prev_char(s, t, e, enc)) != NULL) {
11960rstrip_offset_table(
VALUE str,
const char *s,
const char *e,
rb_encoding *enc,
11961 char table[TR_TABLE_SIZE],
VALUE del,
VALUE nodel)
11963 const char *t, *tp;
11965 rb_str_check_dummy_enc(enc);
11969 if (!s || s >= e)
return 0;
11973 while ((tp = rb_enc_prev_char(s, t, e, enc)) != NULL) {
11975 if (!tr_find(c, table, del, nodel))
break;
11995rb_str_rstrip_bang(
int argc,
VALUE *argv,
VALUE str)
12001 str_modify_keep_cr(str);
12002 enc = STR_ENC_GET(str);
12005 char table[TR_TABLE_SIZE];
12006 VALUE del = 0, nodel = 0;
12008 tr_setup_table_multi(table, &del, &nodel, str, argc, argv);
12011 str_modify_keep_cr(str);
12012 enc = STR_ENC_GET(str);
12015 roffset = rstrip_offset_table(str, start, start+olen, enc, table, del, nodel);
12018 roffset = rstrip_offset(str, start, start+olen, enc);
12023 STR_SET_LEN(str,
len);
12024 TERM_FILL(start+
len, rb_enc_mbminlen(enc));
12058rb_str_rstrip(
int argc,
VALUE *argv,
VALUE str)
12064 enc = STR_ENC_GET(str);
12067 char table[TR_TABLE_SIZE];
12068 VALUE del = 0, nodel = 0;
12070 tr_setup_table_multi(table, &del, &nodel, str, argc, argv);
12073 enc = STR_ENC_GET(str);
12076 roffset = rstrip_offset_table(str, start, start+olen, enc, table, del, nodel);
12079 roffset = rstrip_offset(str, start, start+olen, enc);
12081 if (roffset <= 0)
return str_duplicate(
rb_cString, str);
12099rb_str_strip_bang(
int argc,
VALUE *argv,
VALUE str)
12105 str_modify_keep_cr(str);
12106 enc = STR_ENC_GET(str);
12110 char table[TR_TABLE_SIZE];
12111 VALUE del = 0, nodel = 0;
12113 tr_setup_table_multi(table, &del, &nodel, str, argc, argv);
12116 str_modify_keep_cr(str);
12117 enc = STR_ENC_GET(str);
12120 loffset = lstrip_offset_table(str, start, start+olen, enc, table, del, nodel);
12121 roffset = rstrip_offset_table(str, start+loffset, start+olen, enc, table, del, nodel);
12124 loffset = lstrip_offset(str, start, start+olen, enc);
12125 roffset = rstrip_offset(str, start+loffset, start+olen, enc);
12128 if (loffset > 0 || roffset > 0) {
12132 memmove(start, start + loffset,
len);
12134 STR_SET_LEN(str,
len);
12135 TERM_FILL(start+
len, rb_enc_mbminlen(enc));
12170rb_str_strip(
int argc,
VALUE *argv,
VALUE str)
12179 char table[TR_TABLE_SIZE];
12180 VALUE del = 0, nodel = 0;
12182 tr_setup_table_multi(table, &del, &nodel, str, argc, argv);
12185 enc = STR_ENC_GET(str);
12188 loffset = lstrip_offset_table(str, start, start+olen, enc, table, del, nodel);
12189 roffset = rstrip_offset_table(str, start+loffset, start+olen, enc, table, del, nodel);
12192 loffset = lstrip_offset(str, start, start+olen, enc);
12193 roffset = rstrip_offset(str, start+loffset, start+olen, enc);
12196 if (loffset <= 0 && roffset <= 0)
return str_duplicate(
rb_cString, str);
12204 rb_len_t end, pos = rb_pat_search(pat, str, *start, set_backref_str);
12208 end = pos + RSTRING_LEN(pat);
12212 pos = RMATCH_BEG(match, 0);
12213 end = RMATCH_END(match, 0);
12221 if (RSTRING_LEN(str) > end)
12222 *start = end + rb_enc_fast_mbclen(RSTRING_PTR(str) + end,
12231 if (
NIL_P(match) || RMATCH_NREGS(match) == 1) {
12236 int num_regs = RMATCH_NREGS(match);
12238 for (
int i = 1; i < num_regs; i++) {
12240 if (RMATCH_BEG(match, i) >= 0) {
12241 s =
rb_str_subseq(str, RMATCH_BEG(match, i), RMATCH_END(match, i) - RMATCH_BEG(match, i));
12270 const char *p = RSTRING_PTR(str);
12273 pat = get_pat_quoted(pat, 1);
12274 mustnot_broken(str);
12278 while (!
NIL_P(result = scan_once(str, pat, &start, 0))) {
12283 if (last >= 0) rb_pat_search(pat, str, last, 1);
12288 while (!
NIL_P(result = scan_once(str, pat, &start, 1))) {
12292 str_mod_check(str, p,
len);
12294 if (last >= 0) rb_pat_search(pat, str, last, 1);
12346rb_str_hex(
VALUE str)
12348 return rb_str_to_inum(str, 16, FALSE);
12432rb_str_oct(
VALUE str)
12434 return rb_str_to_inum(str, -8, FALSE);
12437#ifndef HAVE_CRYPT_R
12442 rb_nativethread_lock_t lock;
12443} crypt_mutex = {PTHREAD_MUTEX_INITIALIZER};
12512# define CRYPT_END() ALLOCV_END(databuf)
12515 extern char *crypt(
const char *,
const char *);
12516# define CRYPT_END() rb_nativethread_lock_unlock(&crypt_mutex.lock)
12519 const char *s, *saltp, *res;
12521 char salt_8bit_clean[3];
12525 mustnot_wchar(str);
12526 mustnot_wchar(salt);
12528 saltp = RSTRING_PTR(salt);
12529 if (RSTRING_LEN(salt) < 2 || !saltp[0] || !saltp[1]) {
12530 rb_raise(rb_eArgError,
"salt too short (need >=2 bytes)");
12534 if (!
ISASCII((
unsigned char)saltp[0]) || !
ISASCII((
unsigned char)saltp[1])) {
12535 salt_8bit_clean[0] = saltp[0] & 0x7f;
12536 salt_8bit_clean[1] = saltp[1] & 0x7f;
12537 salt_8bit_clean[2] =
'\0';
12538 saltp = salt_8bit_clean;
12543# ifdef HAVE_STRUCT_CRYPT_DATA_INITIALIZED
12544 data->initialized = 0;
12546 res = crypt_r(s, saltp, data);
12549 res = crypt(s, saltp);
12564 size_t res_size = strlen(res);
12565 tmp_buf =
ALLOCA_N(
char, res_size);
12566 memcpy(tmp_buf, res, res_size);
12602 char *ptr, *p, *pend;
12605 unsigned long sum0 = 0;
12610 ptr = p = RSTRING_PTR(str);
12611 len = RSTRING_LEN(str);
12617 str_mod_check(str, ptr,
len);
12620 sum0 += (
unsigned char)*p;
12631 if (bits < (
int)
sizeof(
long)*CHAR_BIT) {
12632 sum0 &= (((
unsigned long)1)<<bits)-1;
12652rb_str_justify(
int argc,
VALUE *argv,
VALUE str,
char jflag)
12659 const char *f =
" ";
12660 rb_len_t n, size, llen, rlen, llen2 = 0, rlen2 = 0;
12662 int singlebyte = 1, cr;
12666 enc = STR_ENC_GET(str);
12670 enc = rb_enc_check(str, pad);
12671 f = RSTRING_PTR(pad);
12672 flen = RSTRING_LEN(pad);
12673 fclen = str_strlen(pad, enc);
12674 singlebyte = single_byte_optimizable(pad);
12675 if (flen == 0 || fclen == 0) {
12676 rb_raise(rb_eArgError,
"zero width padding");
12679 termlen = rb_enc_mbminlen(enc);
12680 len = str_strlen(str, enc);
12681 if (width < 0 || len >= width)
return str_duplicate(
rb_cString, str);
12683 llen = (jflag ==
'l') ? 0 : ((jflag ==
'r') ? n : n/2);
12687 llen2 = str_offset(f, f + flen, llen % fclen, enc, singlebyte);
12688 rlen2 = str_offset(f, f + flen, rlen % fclen, enc, singlebyte);
12690 size = RSTRING_LEN(str);
12691 if ((
len = llen / fclen + rlen / fclen) >=
RB_LEN_MAX / flen ||
12694 rb_raise(rb_eArgError,
"argument too big");
12698 p = RSTRING_PTR(res);
12700 memset(p, *f, llen);
12704 while (llen >= fclen) {
12710 memcpy(p, f, llen2);
12714 memcpy(p, RSTRING_PTR(str), size);
12717 memset(p, *f, rlen);
12721 while (rlen >= fclen) {
12727 memcpy(p, f, rlen2);
12731 TERM_FILL(p, termlen);
12732 STR_SET_LEN(res, p-RSTRING_PTR(res));
12753rb_str_ljust(
int argc,
VALUE *argv,
VALUE str)
12755 return rb_str_justify(argc, argv, str,
'l');
12767rb_str_rjust(
int argc,
VALUE *argv,
VALUE str)
12769 return rb_str_justify(argc, argv, str,
'r');
12782rb_str_center(
int argc,
VALUE *argv,
VALUE str)
12784 return rb_str_justify(argc, argv, str,
'c');
12800 sep = get_pat_quoted(sep, 0);
12807 pos = RMATCH_BEG(match, 0);
12811 pos = rb_str_index(str, sep, 0);
12812 if (pos < 0)
goto failed;
12815 rb_len_t rpos = pos + RSTRING_LEN(sep);
12816 if (rpos > RSTRING_LEN(str))
goto failed;
12822 return rb_ary_new3(3, str_duplicate(
rb_cString, str), str_new_empty_String(str), str_new_empty_String(str));
12838 sep = get_pat_quoted(sep, 0);
12840 pos = RSTRING_LEN(str);
12846 pos = RMATCH_BEG(match, 0);
12852 pos = rb_str_rindex(str, sep, pos);
12858 rb_len_t rpos = pos + RSTRING_LEN(sep);
12859 if (rpos > RSTRING_LEN(str))
goto failed;
12864 return rb_ary_new3(3, str_new_empty_String(str), str_new_empty_String(str), str_duplicate(
rb_cString, str));
12876rb_str_start_with(
int argc,
VALUE *argv,
VALUE str)
12880 for (i=0; i<argc; i++) {
12881 VALUE tmp = argv[i];
12883 if (rb_reg_start_with_p(tmp, str))
12887 const char *p, *s, *e;
12892 enc = rb_enc_check(str, tmp);
12893 if ((tlen = RSTRING_LEN(tmp)) == 0)
return Qtrue;
12894 if ((slen = RSTRING_LEN(str)) < tlen)
continue;
12895 p = RSTRING_PTR(str);
12898 if (!at_char_right_boundary(p, s, e, enc))
12900 if (memcmp(p, RSTRING_PTR(tmp), tlen) == 0)
12916rb_str_end_with(
int argc,
VALUE *argv,
VALUE str)
12920 for (i=0; i<argc; i++) {
12921 VALUE tmp = argv[i];
12922 const char *p, *s, *e;
12927 enc = rb_enc_check(str, tmp);
12928 if ((tlen = RSTRING_LEN(tmp)) == 0)
return Qtrue;
12929 if ((slen = RSTRING_LEN(str)) < tlen)
continue;
12930 p = RSTRING_PTR(str);
12933 if (!at_char_boundary(p, s, e, enc))
12935 if (memcmp(s, RSTRING_PTR(tmp), tlen) == 0)
12951deleted_prefix_length(
VALUE str,
VALUE prefix)
12953 const char *strptr, *prefixptr;
12959 if (!is_broken_string(prefix) ||
12960 !rb_enc_asciicompat(enc) ||
12961 !rb_enc_asciicompat(rb_enc_get(prefix))) {
12962 enc = rb_enc_check(str, prefix);
12966 prefixlen = RSTRING_LEN(prefix);
12967 if (prefixlen <= 0)
return 0;
12968 olen = RSTRING_LEN(str);
12969 if (olen < prefixlen)
return 0;
12970 strptr = RSTRING_PTR(str);
12971 prefixptr = RSTRING_PTR(prefix);
12972 if (memcmp(strptr, prefixptr, prefixlen) != 0)
return 0;
12973 if (is_broken_string(prefix)) {
12974 if (!is_broken_string(str)) {
12978 const char *strend = strptr + olen;
12979 const char *after_prefix = strptr + prefixlen;
12980 if (!at_char_right_boundary(strptr, after_prefix, strend, enc)) {
13001rb_str_delete_prefix_bang(
VALUE str,
VALUE prefix)
13004 str_modify_keep_cr(str);
13006 prefixlen = deleted_prefix_length(str, prefix);
13007 if (prefixlen <= 0)
return Qnil;
13021rb_str_delete_prefix(
VALUE str,
VALUE prefix)
13025 prefixlen = deleted_prefix_length(str, prefix);
13026 if (prefixlen <= 0)
return str_duplicate(
rb_cString, str);
13028 return rb_str_subseq(str, prefixlen, RSTRING_LEN(str) - prefixlen);
13041deleted_suffix_length(
VALUE str,
VALUE suffix)
13043 const char *strptr, *suffixptr;
13048 if (is_broken_string(suffix))
return 0;
13049 enc = rb_enc_check(str, suffix);
13052 suffixlen = RSTRING_LEN(suffix);
13053 if (suffixlen <= 0)
return 0;
13054 olen = RSTRING_LEN(str);
13055 if (olen < suffixlen)
return 0;
13056 strptr = RSTRING_PTR(str);
13057 suffixptr = RSTRING_PTR(suffix);
13058 const char *strend = strptr + olen;
13059 const char *before_suffix = strend - suffixlen;
13060 if (memcmp(before_suffix, suffixptr, suffixlen) != 0)
return 0;
13061 if (!at_char_boundary(strptr, before_suffix, strend, enc))
return 0;
13077rb_str_delete_suffix_bang(
VALUE str,
VALUE suffix)
13080 str_modifiable(str);
13082 suffixlen = deleted_suffix_length(str, suffix);
13083 if (suffixlen <= 0)
return Qnil;
13085 return str_shrink(str, RSTRING_LEN(str) - suffixlen);
13097rb_str_delete_suffix(
VALUE str,
VALUE suffix)
13101 suffixlen = deleted_suffix_length(str, suffix);
13102 if (suffixlen <= 0)
return str_duplicate(
rb_cString, str);
13104 return rb_str_subseq(str, 0, RSTRING_LEN(str) - suffixlen);
13111 rb_raise(
rb_eTypeError,
"value of %"PRIsVALUE
" must be String", rb_id2str(
id));
13117nil_setter_warning(
ID id)
13119 rb_warn_deprecated(
"non-nil '%"PRIsVALUE
"'", NULL, rb_id2str(
id));
13126 if (!
NIL_P(*var)) {
13127 nil_setter_warning(
id);
13134 val = rb_fs_check(val);
13137 "value of %"PRIsVALUE
" must be String or Regexp",
13141 nil_setter_warning(
id);
13158 str_modifiable(str);
13161 int idx = rb_enc_to_index(encoding);
13168 rb_enc_associate_index(str, idx);
13192 if (STR_EMBED_P(str)) {
13193 str2 = str_alloc_embed(
rb_cString, RSTRING_LEN(str) + TERM_LEN(str));
13198 str_replace_shared_without_enc(str2, str);
13200 if (rb_enc_asciicompat(STR_ENC_GET(str))) {
13223rb_str_valid_encoding_p(
VALUE str)
13225 int cr = rb_enc_str_coderange(str);
13232rb_str_is_ascii_only_p(
VALUE str)
13234 int cr = rb_enc_str_coderange(str);
13242 static const char ellipsis[] =
"...";
13243 const rb_len_t ellipsislen =
sizeof(ellipsis) - 1;
13245 const rb_len_t blen = RSTRING_LEN(str);
13246 const char *
const p = RSTRING_PTR(str), *e = p + blen;
13247 VALUE estr, ret = 0;
13250 if (
len * rb_enc_mbminlen(enc) >= blen ||
13254 else if (
len <= ellipsislen ||
13256 if (rb_enc_asciicompat(enc)) {
13258 rb_enc_associate(ret, enc);
13265 else if (ret =
rb_str_subseq(str, 0, e - p), rb_enc_asciicompat(enc)) {
13270 rb_enc_from_encoding(enc), 0,
Qnil);
13281 cr = rb_enc_str_coderange(str);
13283 rb_raise(rb_eArgError,
"replacement must be valid byte sequence '%+"PRIsVALUE
"'", str);
13289 rb_enc_inspect_name(enc), rb_enc_inspect_name(e));
13308 if (enc == STR_ENC_GET(str)) {
13313 return enc_str_scrub(enc, str, repl, cr);
13321 const char *rep, *p, *e, *p1, *sp;
13327 rb_raise(rb_eArgError,
"both of block and replacement given");
13334 if (!
NIL_P(repl)) {
13335 repl = str_compat_and_valid(repl, enc);
13338 if (rb_enc_dummy_p(enc)) {
13341 encidx = rb_enc_to_index(enc);
13343#define DEFAULT_REPLACE_CHAR(str) do { \
13344 RBIMPL_ATTR_NONSTRING() static const char replace[sizeof(str)-1] = str; \
13345 rep = replace; replen = (int)sizeof(replace); \
13348 slen = RSTRING_LEN(str);
13349 p = RSTRING_PTR(str);
13354 if (rb_enc_asciicompat(enc)) {
13360 else if (!
NIL_P(repl)) {
13361 rep = RSTRING_PTR(repl);
13362 replen = RSTRING_LEN(repl);
13365 else if (encidx == rb_utf8_encindex()) {
13366 DEFAULT_REPLACE_CHAR(
"\xEF\xBF\xBD");
13370 DEFAULT_REPLACE_CHAR(
"?");
13375 p = search_nonascii(p, e);
13380 int ret = rb_enc_precise_mbclen(p, e, enc);
13388 p = search_nonascii(p, e);
13405 if (e - p < clen) clen = e - p;
13412 for (; clen > 1; clen--) {
13413 ret = rb_enc_precise_mbclen(q, q + clen, enc);
13424 repl =
rb_yield(rb_enc_str_new(p, clen, enc));
13425 str_mod_check(str, sp, slen);
13426 repl = str_compat_and_valid(repl, enc);
13433 p = search_nonascii(p, e);
13459 repl =
rb_yield(rb_enc_str_new(p, e-p, enc));
13460 str_mod_check(str, sp, slen);
13461 repl = str_compat_and_valid(repl, enc);
13470 rb_len_t mbminlen = rb_enc_mbminlen(enc);
13474 else if (!
NIL_P(repl)) {
13475 rep = RSTRING_PTR(repl);
13476 replen = RSTRING_LEN(repl);
13478 else if (encidx == ENCINDEX_UTF_16BE) {
13479 DEFAULT_REPLACE_CHAR(
"\xFF\xFD");
13481 else if (encidx == ENCINDEX_UTF_16LE) {
13482 DEFAULT_REPLACE_CHAR(
"\xFD\xFF");
13484 else if (encidx == ENCINDEX_UTF_32BE) {
13485 DEFAULT_REPLACE_CHAR(
"\x00\x00\xFF\xFD");
13487 else if (encidx == ENCINDEX_UTF_32LE) {
13488 DEFAULT_REPLACE_CHAR(
"\xFD\xFF\x00\x00");
13491 DEFAULT_REPLACE_CHAR(
"?");
13495 int ret = rb_enc_precise_mbclen(p, e, enc);
13508 if (e - p < clen) clen = e - p;
13509 if (clen <= mbminlen * 2) {
13514 for (; clen > mbminlen; clen-=mbminlen) {
13515 ret = rb_enc_precise_mbclen(q, q + clen, enc);
13525 repl =
rb_yield(rb_enc_str_new(p, clen, enc));
13526 str_mod_check(str, sp, slen);
13527 repl = str_compat_and_valid(repl, enc);
13552 repl =
rb_yield(rb_enc_str_new(p, e-p, enc));
13553 str_mod_check(str, sp, slen);
13554 repl = str_compat_and_valid(repl, enc);
13594str_scrub_bang(
int argc,
VALUE *argv,
VALUE str)
13602static ID id_normalize;
13603static ID id_normalized_p;
13604static VALUE mUnicodeNormalize;
13607unicode_normalize_common(
int argc,
VALUE *argv,
VALUE str,
ID id)
13609 static int UnicodeNormalizeRequired = 0;
13612 if (!UnicodeNormalizeRequired) {
13613 rb_require(
"unicode_normalize/normalize.rb");
13614 UnicodeNormalizeRequired = 1;
13618 return rb_funcallv(mUnicodeNormalize,
id, argc+1, argv2);
13629rb_str_unicode_normalize(
int argc,
VALUE *argv,
VALUE str)
13631 return unicode_normalize_common(argc, argv, str, id_normalize);
13645rb_str_unicode_normalize_bang(
int argc,
VALUE *argv,
VALUE str)
13647 return rb_str_replace(str, unicode_normalize_common(argc, argv, str, id_normalize));
13674rb_str_unicode_normalized_p(
int argc,
VALUE *argv,
VALUE str)
13676 return unicode_normalize_common(argc, argv, str, id_normalized_p);
13808#define sym_equal rb_obj_equal
13811sym_printable(
const char *s,
const char *send,
rb_encoding *enc)
13815 int c = rb_enc_precise_mbclen(s, send, enc);
13819 c = rb_enc_mbc_to_codepoint(s, send, enc);
13827rb_str_symname_p(
VALUE sym)
13832 rb_encoding *resenc = rb_default_internal_encoding();
13834 if (resenc == NULL) resenc = rb_default_external_encoding();
13835 enc = STR_ENC_GET(sym);
13836 ptr = RSTRING_PTR(sym);
13837 len = RSTRING_LEN(sym);
13838 if ((resenc != enc && !rb_str_is_ascii_only_p(sym)) ||
len != (
rb_len_t)strlen(ptr) ||
13846rb_str_quote_unprintable(
VALUE str)
13854 resenc = rb_default_internal_encoding();
13855 if (resenc == NULL) resenc = rb_default_external_encoding();
13856 enc = STR_ENC_GET(str);
13857 ptr = RSTRING_PTR(str);
13858 len = RSTRING_LEN(str);
13859 if ((resenc != enc && !rb_str_is_ascii_only_p(str)) ||
13860 !sym_printable(ptr, ptr +
len, enc)) {
13861 return rb_str_escape(str);
13867rb_id_quote_unprintable(
ID id)
13869 VALUE str = rb_id2str(
id);
13870 if (!rb_str_symname_p(str)) {
13871 return rb_str_escape(str);
13889sym_inspect(
VALUE sym)
13896 if (!rb_str_symname_p(str)) {
13898 len = RSTRING_LEN(str);
13899 rb_str_resize(str,
len + 1);
13900 dest = RSTRING_PTR(str);
13901 memmove(dest + 1, dest,
len);
13905 VALUE orig_str = str;
13907 len = RSTRING_LEN(orig_str);
13908 str = rb_enc_str_new(0,
len + 1, enc);
13911 ptr = RSTRING_PTR(orig_str);
13912 dest = RSTRING_PTR(str);
13913 memcpy(dest + 1, ptr,
len);
13931rb_sym_proc_call(
ID mid,
int argc,
const VALUE *argv,
int kw_splat,
VALUE passed_proc)
13936 rb_raise(rb_eArgError,
"no receiver given");
14039 return rb_str_match(
rb_sym2str(sym), other);
14054sym_match_m(
int argc,
VALUE *argv,
VALUE sym)
14056 return rb_str_match_m(argc, argv,
rb_sym2str(sym));
14069sym_match_m_p(
int argc,
VALUE *argv,
VALUE sym)
14071 return rb_str_match_m_p(argc, argv, sym);
14089 return rb_str_aref_m(argc, argv,
rb_sym2str(sym));
14100sym_length(
VALUE sym)
14134sym_downcase(
int argc,
VALUE *argv,
VALUE sym)
14150sym_capitalize(
int argc,
VALUE *argv,
VALUE sym)
14166sym_swapcase(
int argc,
VALUE *argv,
VALUE sym)
14180sym_start_with(
int argc,
VALUE *argv,
VALUE sym)
14182 return rb_str_start_with(argc, argv,
rb_sym2str(sym));
14195sym_end_with(
int argc,
VALUE *argv,
VALUE sym)
14197 return rb_str_end_with(argc, argv,
rb_sym2str(sym));
14209sym_encoding(
VALUE sym)
14215string_for_symbol(
VALUE name)
14220 rb_raise(
rb_eTypeError,
"%+"PRIsVALUE
" is not a symbol nor a string",
14234 name = string_for_symbol(name);
14235 return rb_intern_str(name);
14244 name = string_for_symbol(name);
14268 return rb_fstring(str);
14274 struct RString fake_str = {RBASIC_INIT};
14275 int encidx = ENCINDEX_US_ASCII;
14278 encidx = ENCINDEX_ASCII_8BIT;
14281 VALUE str = setup_fake_str(&fake_str,
ptr,
len, encidx);
14283 return register_fstring(str,
true,
false);
14295 if (enc != NULL && UNLIKELY(rb_enc_autoload_p(enc))) {
14296 rb_enc_autoload(enc);
14299 struct RString fake_str = {RBASIC_INIT};
14300 return register_fstring(rb_setup_fake_str(&fake_str,
ptr,
len, enc),
true,
false);
14306 if (enc != NULL && UNLIKELY(rb_enc_autoload_p(enc))) {
14307 rb_enc_autoload(enc);
14310 struct RString fake_str = {RBASIC_INIT};
14311 VALUE str = register_fstring(rb_setup_fake_str(&fake_str,
ptr,
len, enc),
true,
true);
14322#if USE_YJIT || USE_ZJIT
14324rb_jit_str_concat_codepoint(
VALUE str,
VALUE codepoint)
14329 if (RB_LIKELY(code >= 0 && code < 0xff)) {
14330 rb_str_buf_cat_byte(str, (
char) code);
14340fstring_set_class_i(
VALUE *str,
void *data)
14344 return ST_CONTINUE;
14352 rb_concurrent_set_foreach_with_replace(fstring_table_obj, fstring_set_class_i, NULL);
14520 mUnicodeNormalize = rb_define_module(
"UnicodeNormalize");
14531 rb_gc_register_address(&
rb_fs);
14569#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.
#define RMATCH(obj)
Convenient casting macro.
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.
#define RB_LEN_MIN
Minimum 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.