source: git/ppcc/adlib/str.cc @ 54b24c

spielwiese
Last change on this file since 54b24c was 54b24c, checked in by Reimer Behrends <behrends@…>, 5 years ago
Finalizing thread support.
  • Property mode set to 100644
File size: 6.7 KB
Line 
1#include "lib.h"
2
3Str *Str::chomp() {
4  if (_len > 0 && _data[_len - 1] == '\n')
5    _len--;
6  if (_len > 0 && _data[_len - 1] == '\r')
7    _len--;
8  _data[_len] = '\0';
9  return this;
10}
11
12StrArr *Str::split(const char *s, Int n) {
13  Arr<Int> *parts = new Arr<Int>();
14  parts->add(-n);
15  for (Int i = 0; i < _len - n; i++) {
16    if (_data[i] == s[0] && memcmp(_data + i, s, n)) {
17      parts->add(i);
18      i += n;
19    }
20  }
21  parts->add(_len);
22  StrArr *result = new StrArr(parts->len() - 1);
23  for (Int i = 1; i < parts->len(); i++) {
24    Int begin = parts->at(i - 1) + n;
25    Int end = parts->at(i);
26    result->add(new Str(_data + begin, end - begin));
27  }
28  return result;
29}
30
31StrArr *Str::split(Str *sep) {
32  return split(sep->_data, sep->_len);
33}
34
35StrArr *Str::split(char ch) {
36  Int parts = 1;
37  for (Int i = 0; i < _len; i++) {
38    if (_data[i] == ch)
39      parts++;
40  }
41  StrArr *result = new StrArr(parts);
42  Int last = 0;
43  for (Int i = 0; i < _len; i++) {
44    if (_data[i] == ch) {
45      result->add(new Str(_data + last, i - last));
46      last = i + 1;
47    }
48  }
49  result->add(new Str(_data + last, _len - last));
50  return result;
51}
52
53Str *Str::remove(Int start, Int count) {
54  Int end = start + count;
55  require(start >= 0 && start <= _len, "index out of range");
56  require(end <= _len, "index out of range");
57  if (count <= 0) return this;
58  memmove(_data + start, _data + end, _len - end);
59  _len -= count;
60  _data[_len] ='\0';
61  return shrink(false);
62}
63
64Str *Str::remove(Int at) {
65  return remove(at, 1);
66}
67
68Str *Str::set_len(Int len) {
69  require (len >= 0, "invalid length");
70  if (len > _len) {
71    expand(len);
72    memset(_data + _len, 0, len - _len + 1);
73    _len = len;
74  }
75  else if (len < _len) {
76    memset(_data + len, 0, _len - len);
77    _len = len;
78    return shrink(false);
79  }
80  return this;
81}
82
83StrArr *Str::split(const char *s) {
84  return split(s, strlen(s));
85}
86
87StrArr *Str::splitLines() {
88  StrArr *result = split('\n');
89  for (Int i = 0; i < result->len(); i++) {
90    result->at(i)->chomp();
91  }
92  return result;
93}
94
95Str *StrJoin(StrArr *arr, const char *sep, Int n) {
96  if (arr->len() == 0)
97    return new Str();
98  Str *result = new Str(arr->len() * (n + 1));
99  result->add(arr->first());
100  for (Int i = 1; i < arr->len(); i++) {
101    result->add(sep, n);
102    result->add(arr->at(i));
103  }
104  return result;
105}
106
107Str *StrJoin(StrArr *arr, const char *sep) {
108  return StrJoin(arr, sep, strlen(sep));
109}
110
111Str *StrJoin(StrArr *arr, char ch) {
112  return StrJoin(arr, &ch, 1);
113}
114
115Str *StrJoin(StrArr *arr, Str *sep) {
116  return StrJoin(arr, sep->c_str(), sep->len());
117}
118
119bool Str::starts_with(const char *s, Int n) {
120  if (n > _len)
121    return false;
122  return memcmp(_data, s, n) == 0;
123}
124
125bool Str::starts_with(const char *s) {
126  return starts_with(s, strlen(s));
127}
128
129bool Str::starts_with(Str *str) {
130  return starts_with(str->c_str(), str->len());
131}
132
133bool Str::ends_with(const char *s, Int n) {
134  if (n > _len)
135    return false;
136  return memcmp(_data + _len - n, s, n) == 0;
137}
138
139bool Str::ends_with(const char *s) {
140  return ends_with(s, strlen(s));
141}
142
143bool Str::ends_with(Str *str) {
144  return ends_with(str->c_str(), str->len());
145}
146
147int Cmp(Str *str1, Str *str2) {
148  Int len1 = str1->len();
149  Int len2 = str2->len();
150  int result = memcmp(str1->c_str(), str2->c_str(), Min(len1, len2));
151  if (result == 0) {
152    if (len1 < len2)
153      result = -1;
154    else if (len1 > len2)
155      result = 1;
156  }
157  return result;
158}
159
160int StrCmp(Str *str1, Str *str2) {
161  return Cmp(str1, str2);
162}
163
164bool Str::eq(const char *s, Int n) {
165  if (n != _len)
166    return false;
167  return memcmp(_data, s, n) == 0;
168}
169
170bool Str::eq(const char *s) {
171  return eq(s, strlen(s));
172}
173
174bool Str::eq(Str *str) {
175  return eq(str->c_str(), str->len());
176}
177
178Str *Str::substr(Int start, Int count) {
179  require(0 <= start && start < _len && count >= 0 && start + count <= _len,
180    "index out of range");
181  return new Str(_data + start, count);
182}
183
184Int Str::find(char ch, Int from) {
185  require(from <= _len, "index out of range");
186  for (Int i = from; i < _len; i++) {
187    if (_data[i] == ch)
188      return i;
189  }
190  return NOWHERE;
191}
192
193Int Str::find(const char *s, Int n, Int from) {
194  const int mult_base = 3;
195  require(n >= 0, "negative length");
196  require(from < _len, "index out of range");
197  if (n == 0)
198    return from;
199  if (n > _len)
200    return NOWHERE;
201  if (n == 1)
202    return find(s[0], from);
203  if (n <= 4) {
204    Int end = _len - n + 1;
205    char ch = s[0];
206    for (Int i = from; i < end; i++) {
207      if (memcmp(_data + i, s, n) == 0)
208        return i;
209    }
210    return NOWHERE;
211  }
212  // Rabin-Karp search with a simple hash function
213  Word32 hash = (Byte) s[0];
214  Word32 rollhash = 0;
215  Word32 hashmul = 1;
216  // rollhash only hashes the first n-1 characters; it will
217  // be updated in the search loop
218  for (Int i = 1; i < n; i++) {
219    hash = hash * mult_base + (Byte) s[i];
220    rollhash = rollhash * mult_base + (Byte) _data[from+i-1];
221    hashmul *= mult_base;
222  }
223  Int end = _len - n + 1;
224  char ch = s[0];
225  for (Int i = from; i < end; i++) {
226    rollhash = rollhash * mult_base + (Byte) _data[i+n-1];
227    if (hash == rollhash) {
228      if (memcmp(_data + i, s, n) == 0)
229        return i;
230    }
231    rollhash -= hashmul * (Byte) _data[i];
232  }
233  return NOWHERE;
234}
235
236Int Str::find(const char *s, Int from) {
237  return find(s, strlen(s), from);
238}
239
240Int Str::find(Str *str, Int from) {
241  return find(str->_data, str->_len, from);
242}
243
244Int Str::rfind(char ch) {
245  for (Int i = _len - 1; i >= 0; i--) {
246    if (_data[i] == ch)
247      return i;
248  }
249  return NOWHERE;
250}
251
252Int Str::rfind(const char *s, Int n) {
253  require(n >= 0, "empty string");
254  if (n == 0)
255    return _len;
256  if (n == 1)
257    return rfind(s[0]);
258  if (n >_len)
259    return NOWHERE;
260  Int end = _len - n;
261  char ch = s[0];
262  for (Int i = end - 1; i >= 0; i--) {
263    if (memcmp(_data + i, s, n) == 0)
264      return i;
265  }
266  return NOWHERE;
267}
268
269Int Str::rfind(const char *s) {
270  return rfind(s, strlen(s));
271}
272
273Int Str::rfind(Str *str) {
274  return rfind(str->_data, str->_len);
275}
276
277Str *Str::replace_count(Int n, Str *pattern, Str *replacement) {
278  require(pattern->len() > 0, "pattern must be non-empty");
279  Str *result = new Str();
280  Int from = 0;
281  for (;;) {
282    if (n-- <= 0) {
283      result->add(_data + from, _len - from);
284      break;
285    }
286    Int pos = find(pattern, from);
287    if (pos < 0) {
288      result->add(_data + from, _len - from);
289      break;
290    }
291    result->add(_data + from, pos - from);
292    result->add(replacement);
293    from = pos + pattern->len();
294  }
295  return result;
296}
297
298Str *ToStr(Int x) {
299  char buffer[sizeof(LongInt) * 4 + 1];
300  sprintf(buffer, "%" LONG_FMT "d", (LongInt) x);
301  return S(buffer);
302}
303
304Str *ToStr(Word x) {
305  char buffer[sizeof(LongWord) * 4 + 1];
306  sprintf(buffer, "%" LONG_FMT "u", (LongWord) x);
307  return S(buffer);
308}
309
310Str *CStrToStr(const char *s) {
311  return S(s);
312}
Note: See TracBrowser for help on using the repository browser.