-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathrb_u_string_aref.c
More file actions
142 lines (121 loc) · 4.7 KB
/
rb_u_string_aref.c
File metadata and controls
142 lines (121 loc) · 4.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
#include "rb_includes.h"
#include "rb_u_re.h"
static VALUE
rb_u_string_substr_impl(VALUE self, long offset, long len, bool nil_on_empty)
{
if (len < 0)
return Qnil;
const struct rb_u_string *string = RVAL2USTRING(self);
const char *begin = rb_u_string_begin_from_offset(string, offset);
if (begin == NULL)
return Qnil;
const char *end = u_offset_to_pointer_n(begin, len, USTRING_END(string) - begin);
if (end == NULL)
end = USTRING_END(string);
if (nil_on_empty && begin == end)
return Qnil;
if (begin == USTRING_STR(string) && end == USTRING_END(string))
return self;
return rb_u_string_new_c(self, begin, end - begin);
}
VALUE
rb_u_string_substr(VALUE self, long offset, long len)
{
return rb_u_string_substr_impl(self, offset, len, false);
}
static VALUE
rb_u_string_subpat(VALUE self, VALUE re, VALUE reference)
{
if (rb_reg_search(re, StringValue(self), 0, 0) < 0)
return Qnil;
volatile VALUE match = rb_u_pattern_match_reference(reference);
return NIL_P(match) ? Qnil : rb_u_string_new_rb(match);
}
static VALUE
rb_u_string_aref_num(VALUE self, long offset)
{
return rb_u_string_substr_impl(self, offset, 1, true);
}
static VALUE
rb_u_string_aref_default(VALUE self, VALUE index)
{
const struct rb_u_string *string = RVAL2USTRING(self);
long n_chars = u_n_chars_n(USTRING_STR(string), USTRING_LENGTH(string));
long begin, length;
switch (rb_range_beg_len(index, &begin, &length, n_chars, 0)) {
case Qfalse:
return rb_u_string_aref_num(self, NUM2LONG(index));
case Qnil:
return Qnil;
default:
return rb_u_string_substr(self, begin, length);
}
}
static VALUE
rb_u_string_aref(VALUE self, VALUE index)
{
if (TYPE(index) == T_STRING || RTEST(rb_obj_is_kind_of(index, rb_cUString))) {
if (rb_u_string_index(self, index, 0) == -1)
return Qnil;
return TYPE(index) == T_STRING ?
rb_u_string_new_c(index, RSTRING_PTR(index), RSTRING_LEN(index)) :
index;
}
switch (TYPE(index)) {
case T_FIXNUM:
return rb_u_string_aref_num(self, FIX2LONG(index));
case T_REGEXP:
return rb_u_string_subpat(self, index, INT2FIX(0));
default:
return rb_u_string_aref_default(self, index);
}
}
/* @overload [](index)
* @param [#to_int] index
* @return [U::String, nil] The substring [max(_i_, 0), min({#length}, _i_ +
* 1)], where _i_ = INDEX if INDEX ≥ 0, _i_ = {#length} - abs(INDEX)
* otherwise, inheriting any taint and untrust, or nil if this substring is
* empty
*
* @overload [](index, length)
* @param [#to_int] index
* @param [#to_int] length
* @return [U::String, nil] The substring [max(_i_, 0), min({#length}, _i_ +
* LENGTH)], where _i_ = INDEX if INDEX ≥ 0, _i_ = {#length} - abs(INDEX)
* otherwise, inheriting any taint or untrust, or nil if LENGTH < 0
*
* @overload [](range)
* @param [Range] range
* @return [U::String, nil] The result of `#[i, j - k]`, where _i_ =
* RANGE#begin if RANGE#begin ≥ 0, _i_ = {#length} - abs(RANGE#begin)
* otherwise, _j_ = RANGE#end if RANGE#end ≥ 0, _j_ = {#length} -
* abs(RANGE#end) otherwise, and _k_ = 1 if RANGE#exclude_end?, _k_ = 0
* otherwise, or nil if _j_ - _k_ < 0
*
* @overload [](regexp, reference = 0)
* @param [Regexp] regexp
* @param [#to_int, #to_str, Symbol] reference
* @raise [IndexError] If REFERENCE doesn’t refer to a submatch
* @return [U::String, nil] The submatch REFERENCE from the first match of
* REGEXP in the receiver, inheriting any taint and untrust from both
* the receiver and from REGEXP, or nil if there is no match or if the
* submatch isn’t part of the overall match
*
* @overload [](string)
* @param [U::String, ::String] string
* @return [U::String, nil] The substring STRING, inheriting any taint and
* untrust from STRING, if STRING is a substring of the receiver
*
* @overload [](object)
* @param [Object] object
* @return [nil] Nil for any object that doesn’t satisfy the other cases */
VALUE
rb_u_string_aref_m(int argc, VALUE *argv, VALUE self)
{
need_m_to_n_arguments(argc, 1, 2);
if (argc == 1)
return rb_u_string_aref(self, argv[0]);
if (TYPE(argv[0]) == T_REGEXP)
return rb_u_string_subpat(self, argv[0], argv[1]);
return rb_u_string_substr(self, NUM2LONG(argv[0]), NUM2LONG(argv[1]));
}