Line data Source code
1 : /* stringlib: find/index implementation */
2 :
3 : #ifndef STRINGLIB_FIND_H
4 : #define STRINGLIB_FIND_H
5 :
6 : #ifndef STRINGLIB_FASTSEARCH_H
7 : #error must include "stringlib/fastsearch.h" before including this module
8 : #endif
9 :
10 : Py_LOCAL_INLINE(Py_ssize_t)
11 8085 : stringlib_find(const STRINGLIB_CHAR* str, Py_ssize_t str_len,
12 : const STRINGLIB_CHAR* sub, Py_ssize_t sub_len,
13 : Py_ssize_t offset)
14 : {
15 : Py_ssize_t pos;
16 :
17 8085 : if (str_len < 0)
18 0 : return -1;
19 8085 : if (sub_len == 0)
20 0 : return offset;
21 :
22 8085 : pos = fastsearch(str, str_len, sub, sub_len, -1, FAST_SEARCH);
23 :
24 8085 : if (pos >= 0)
25 5187 : pos += offset;
26 :
27 8085 : return pos;
28 : }
29 :
30 : Py_LOCAL_INLINE(Py_ssize_t)
31 18 : stringlib_rfind(const STRINGLIB_CHAR* str, Py_ssize_t str_len,
32 : const STRINGLIB_CHAR* sub, Py_ssize_t sub_len,
33 : Py_ssize_t offset)
34 : {
35 : Py_ssize_t pos;
36 :
37 18 : if (str_len < 0)
38 0 : return -1;
39 18 : if (sub_len == 0)
40 0 : return str_len + offset;
41 :
42 18 : pos = fastsearch(str, str_len, sub, sub_len, -1, FAST_RSEARCH);
43 :
44 18 : if (pos >= 0)
45 15 : pos += offset;
46 :
47 18 : return pos;
48 : }
49 :
50 : /* helper macro to fixup start/end slice values */
51 : #define ADJUST_INDICES(start, end, len) \
52 : if (end > len) \
53 : end = len; \
54 : else if (end < 0) { \
55 : end += len; \
56 : if (end < 0) \
57 : end = 0; \
58 : } \
59 : if (start < 0) { \
60 : start += len; \
61 : if (start < 0) \
62 : start = 0; \
63 : }
64 :
65 : Py_LOCAL_INLINE(Py_ssize_t)
66 2550 : stringlib_find_slice(const STRINGLIB_CHAR* str, Py_ssize_t str_len,
67 : const STRINGLIB_CHAR* sub, Py_ssize_t sub_len,
68 : Py_ssize_t start, Py_ssize_t end)
69 : {
70 2550 : ADJUST_INDICES(start, end, str_len);
71 2550 : return stringlib_find(str + start, end - start, sub, sub_len, start);
72 : }
73 :
74 : Py_LOCAL_INLINE(Py_ssize_t)
75 18 : stringlib_rfind_slice(const STRINGLIB_CHAR* str, Py_ssize_t str_len,
76 : const STRINGLIB_CHAR* sub, Py_ssize_t sub_len,
77 : Py_ssize_t start, Py_ssize_t end)
78 : {
79 18 : ADJUST_INDICES(start, end, str_len);
80 18 : return stringlib_rfind(str + start, end - start, sub, sub_len, start);
81 : }
82 :
83 : #ifdef STRINGLIB_WANT_CONTAINS_OBJ
84 :
85 : Py_LOCAL_INLINE(int)
86 5535 : stringlib_contains_obj(PyObject* str, PyObject* sub)
87 : {
88 22140 : return stringlib_find(
89 5535 : STRINGLIB_STR(str), STRINGLIB_LEN(str),
90 5535 : STRINGLIB_STR(sub), STRINGLIB_LEN(sub), 0
91 5535 : ) != -1;
92 : }
93 :
94 : #endif /* STRINGLIB_WANT_CONTAINS_OBJ */
95 :
96 : /*
97 : This function is a helper for the "find" family (find, rfind, index,
98 : rindex) and for count, startswith and endswith, because they all have
99 : the same behaviour for the arguments.
100 :
101 : It does not touch the variables received until it knows everything
102 : is ok.
103 : */
104 :
105 : #define FORMAT_BUFFER_SIZE 50
106 :
107 : Py_LOCAL_INLINE(int)
108 3372 : stringlib_parse_args_finds(const char * function_name, PyObject *args,
109 : PyObject **subobj,
110 : Py_ssize_t *start, Py_ssize_t *end)
111 : {
112 : PyObject *tmp_subobj;
113 3372 : Py_ssize_t tmp_start = 0;
114 3372 : Py_ssize_t tmp_end = PY_SSIZE_T_MAX;
115 3372 : PyObject *obj_start=Py_None, *obj_end=Py_None;
116 3372 : char format[FORMAT_BUFFER_SIZE] = "O|OO:";
117 3372 : size_t len = strlen(format);
118 :
119 3372 : strncpy(format + len, function_name, FORMAT_BUFFER_SIZE - len - 1);
120 3372 : format[FORMAT_BUFFER_SIZE - 1] = '\0';
121 :
122 3372 : if (!PyArg_ParseTuple(args, format, &tmp_subobj, &obj_start, &obj_end))
123 0 : return 0;
124 :
125 : /* To support None in "start" and "end" arguments, meaning
126 : the same as if they were not passed.
127 : */
128 3372 : if (obj_start != Py_None)
129 2442 : if (!_PyEval_SliceIndex(obj_start, &tmp_start))
130 0 : return 0;
131 3372 : if (obj_end != Py_None)
132 0 : if (!_PyEval_SliceIndex(obj_end, &tmp_end))
133 0 : return 0;
134 :
135 3372 : *start = tmp_start;
136 3372 : *end = tmp_end;
137 3372 : *subobj = tmp_subobj;
138 3372 : return 1;
139 : }
140 :
141 : #undef FORMAT_BUFFER_SIZE
142 :
143 : #if STRINGLIB_IS_UNICODE
144 :
145 : /*
146 : Wraps stringlib_parse_args_finds() and additionally ensures that the
147 : first argument is a unicode object.
148 :
149 : Note that we receive a pointer to the pointer of the substring object,
150 : so when we create that object in this function we don't DECREF it,
151 : because it continues living in the caller functions (those functions,
152 : after finishing using the substring, must DECREF it).
153 : */
154 :
155 : Py_LOCAL_INLINE(int)
156 0 : stringlib_parse_args_finds_unicode(const char * function_name, PyObject *args,
157 : PyUnicodeObject **substring,
158 : Py_ssize_t *start, Py_ssize_t *end)
159 : {
160 : PyObject *tmp_substring;
161 :
162 0 : if(stringlib_parse_args_finds(function_name, args, &tmp_substring,
163 : start, end)) {
164 0 : tmp_substring = PyUnicode_FromObject(tmp_substring);
165 0 : if (!tmp_substring)
166 0 : return 0;
167 0 : *substring = (PyUnicodeObject *)tmp_substring;
168 0 : return 1;
169 : }
170 0 : return 0;
171 : }
172 :
173 : #endif /* STRINGLIB_IS_UNICODE */
174 :
175 : #endif /* STRINGLIB_FIND_H */
|