Titan Core Initial Contribution
[deliverable/titan.core.git] / compiler2 / string.cc
1 ///////////////////////////////////////////////////////////////////////////////
2 // Copyright (c) 2000-2014 Ericsson Telecom AB
3 // All rights reserved. This program and the accompanying materials
4 // are made available under the terms of the Eclipse Public License v1.0
5 // which accompanies this distribution, and is available at
6 // http://www.eclipse.org/legal/epl-v10.html
7 ///////////////////////////////////////////////////////////////////////////////
8 #include <stdio.h>
9 #include <string.h>
10 #include <stddef.h>
11 #include <ctype.h>
12
13 #include "../common/memory.h"
14 #include "error.h"
15
16 #include "string.hh"
17 #include "ustring.hh"
18
19 #include "Int.hh"
20
21 /** Parameters for tuning memory usage of class stringpool */
22 #define STRINGPOOL_INITIAL_SIZE 8
23 #define STRINGPOOL_INCREMENT_FACTOR 2
24
25 /** The amount of memory needed for a string containing n characters. */
26 #define MEMORY_SIZE(n) (sizeof(string_struct) - sizeof(size_t) + 1 + (n))
27
28 void string::init_struct(size_t n_chars)
29 {
30 if (n_chars == 0) {
31 /** This will represent the empty strings so they won't need allocated
32 * memory, this delays the memory allocation until it is really needed. */
33 static string_struct empty_string = { 1, 0, "" };
34 val_ptr = &empty_string;
35 empty_string.ref_count++;
36 } else {
37 val_ptr = static_cast<string_struct*>(Malloc(MEMORY_SIZE(n_chars)));
38 val_ptr->ref_count = 1;
39 val_ptr->n_chars = n_chars;
40 val_ptr->chars_ptr[n_chars] = '\0';
41 }
42 }
43
44 void string::copy_value_and_append(const char *s, size_t n)
45 {
46 if (n > max_string_len - val_ptr->n_chars)
47 FATAL_ERROR("string::copy_value_and_append(const char*, size_t): " \
48 "length overflow");
49 if (val_ptr->ref_count == 1) {
50 ptrdiff_t offset = s - val_ptr->chars_ptr;
51 val_ptr = static_cast<string_struct*>
52 (Realloc(val_ptr, MEMORY_SIZE(val_ptr->n_chars + n)));
53 // check whether the source buffer s is (part of) our existing buffer
54 if (offset >= 0 && static_cast<size_t>(offset) < val_ptr->n_chars)
55 memcpy(val_ptr->chars_ptr + val_ptr->n_chars,
56 val_ptr->chars_ptr + offset, n);
57 else memcpy(val_ptr->chars_ptr + val_ptr->n_chars, s, n);
58 val_ptr->n_chars += n;
59 val_ptr->chars_ptr[val_ptr->n_chars] = '\0';
60 } else {
61 string_struct *old_ptr = val_ptr;
62 old_ptr->ref_count--;
63 init_struct(old_ptr->n_chars + n);
64 memcpy(val_ptr->chars_ptr, old_ptr->chars_ptr, old_ptr->n_chars);
65 memcpy(val_ptr->chars_ptr + old_ptr->n_chars, s, n);
66 }
67 }
68
69 /** Internal worker for various replace() methods.
70 *
71 * @param pos the index of the first character to replace
72 * @param n the number of characters to replace
73 * @param s the replacement
74 * @param s_len the length of the replacement
75 *
76 * @pre \p pos must point inside the string
77 * @pre \p pos + \p n must point inside the string
78 * @pre the resulting string must not exceed max_string_len
79 */
80 void string::replace(size_t pos, size_t n, const char *s, size_t s_len)
81 {
82 if (pos > val_ptr->n_chars)
83 FATAL_ERROR("string::replace(): start position is outside the string");
84 if (pos + n > val_ptr->n_chars)
85 FATAL_ERROR("string::replace(): end position is outside the string");
86 if (s_len > max_string_len - val_ptr->n_chars + n)
87 FATAL_ERROR("string::replace(): length overflow");
88 // do nothing if we are replacing with the same string
89 if (n == s_len && memcmp(val_ptr->chars_ptr + pos, s, n) == 0) return;
90 size_t new_size = val_ptr->n_chars - n + s_len;
91 if (new_size == 0) {
92 // the result is an empty string
93 clean_up(val_ptr);
94 init_struct(0);
95 } else if (val_ptr->ref_count == 1 && (s < val_ptr->chars_ptr ||
96 s >= val_ptr->chars_ptr + val_ptr->n_chars)) {
97 // check whether this string is not referenced by others and we are not
98 // replacing with ourselves
99 if (val_ptr->n_chars < new_size) val_ptr = static_cast<string_struct*>
100 (Realloc(val_ptr, MEMORY_SIZE(new_size)));
101 memmove(val_ptr->chars_ptr + pos + s_len,
102 val_ptr->chars_ptr + pos + n, val_ptr->n_chars - pos - n);
103 memcpy(val_ptr->chars_ptr + pos, s, s_len);
104 if (val_ptr->n_chars > new_size) val_ptr = static_cast<string_struct*>
105 (Realloc(val_ptr, MEMORY_SIZE(new_size)));
106 val_ptr->n_chars = new_size;
107 val_ptr->chars_ptr[new_size] = '\0';
108 } else {
109 // the result must be copied into a new memory area
110 string_struct *old_ptr = val_ptr;
111 old_ptr->ref_count--;
112 init_struct(new_size);
113 memcpy(val_ptr->chars_ptr, old_ptr->chars_ptr, pos);
114 memcpy(val_ptr->chars_ptr + pos, s, s_len);
115 memcpy(val_ptr->chars_ptr + pos + s_len, old_ptr->chars_ptr + pos + n,
116 old_ptr->n_chars - pos - n);
117 if (old_ptr->ref_count == 0) Free(old_ptr);
118 }
119 }
120
121 void string::clean_up(string_struct *ptr)
122 {
123 if (ptr->ref_count > 1) ptr->ref_count--;
124 else if (ptr->ref_count == 1) Free(ptr);
125 else FATAL_ERROR("string::clean_up()");
126 }
127
128 int string::compare(const string& s) const
129 {
130 if (val_ptr == s.val_ptr) return 0;
131 else return strcmp(val_ptr->chars_ptr, s.val_ptr->chars_ptr);
132 }
133
134 int string::compare(const char *s) const
135 {
136 if (val_ptr->chars_ptr == s) return 0;
137 else return strcmp(val_ptr->chars_ptr, s);
138 }
139
140 string::string(const char *s)
141 {
142 if (s == NULL) FATAL_ERROR("string::string(const char*): called with NULL");
143 size_t n_chars = strlen(s);
144 init_struct(n_chars);
145 memcpy(val_ptr->chars_ptr, s, n_chars);
146 }
147
148 string::string(size_t n, const char *s)
149 {
150 if (s == NULL && n > 0)
151 FATAL_ERROR("string::string(size_t, const char*): called with NULL");
152 init_struct(n);
153 memcpy(val_ptr->chars_ptr, s, n);
154 }
155
156 string::string(const ustring& s)
157 {
158 size_t s_len = s.size();
159 init_struct(s_len);
160 const ustring::universal_char *src = s.u_str();
161 for (size_t i = 0; i < s_len; i++) {
162 if (src[i].group != 0 || src[i].plane != 0 || src[i].row != 0)
163 FATAL_ERROR("string::string(const ustring&)");
164 val_ptr->chars_ptr[i] = src[i].cell;
165 }
166 }
167
168 bool string::is_cstr() const
169 {
170 for (size_t i = 0; i < val_ptr->n_chars; i++)
171 if ((unsigned char)val_ptr->chars_ptr[i] > 127) return false;
172 return true;
173 }
174
175 void string::clear()
176 {
177 if (val_ptr->n_chars > 0) {
178 clean_up(val_ptr);
179 init_struct(0);
180 }
181 }
182
183 string string::substr(size_t pos, size_t n) const
184 {
185 if (pos > val_ptr->n_chars)
186 FATAL_ERROR("string::substr(size_t, size_t): position is outside the " \
187 "string");
188 size_t n_chars = val_ptr->n_chars - pos;
189 if (n_chars > n) n_chars = n;
190 if (n_chars == val_ptr->n_chars) return *this;
191 else return string(n_chars, val_ptr->chars_ptr + pos);
192 }
193
194 void string::resize(size_t n, char c)
195 {
196 size_t old_length = val_ptr->n_chars;
197 if (old_length == n) return;
198 if (val_ptr->ref_count == 1) {
199 if (n > 0) {
200 val_ptr = static_cast<string_struct*>(Realloc(val_ptr, MEMORY_SIZE(n)));
201 if (n > old_length) {
202 memset(val_ptr->chars_ptr + old_length, c, n - old_length);
203 }
204 val_ptr->chars_ptr[n] = '\0';
205 val_ptr->n_chars = n;
206 } else {
207 clean_up(val_ptr);
208 init_struct(0);
209 }
210 } else {
211 val_ptr->ref_count--;
212 string_struct *tmp_ptr = val_ptr;
213 init_struct(n);
214 if (n > old_length) {
215 memcpy(val_ptr->chars_ptr, tmp_ptr->chars_ptr, old_length);
216 memset(val_ptr->chars_ptr + old_length, c, n - old_length);
217 } else {
218 memcpy(val_ptr->chars_ptr, tmp_ptr->chars_ptr, n);
219 }
220 }
221 }
222
223 void string::replace(size_t pos, size_t n, const char *s)
224 {
225 if (s == NULL) FATAL_ERROR("string::replace(size_t, size_t, const char*): " \
226 "called with NULL");
227 replace(pos, n, s, strlen(s));
228 }
229
230 void string::replace(size_t pos, size_t n, const string& s)
231 {
232 if (pos == 0 && n == val_ptr->n_chars) *this = s;
233 else replace(pos, n, s.val_ptr->chars_ptr, s.val_ptr->n_chars);
234 }
235
236 size_t string::find(char c, size_t pos) const
237 {
238 if (pos > val_ptr->n_chars)
239 FATAL_ERROR("string::find(char, size_t): position is outside of string");
240 for (size_t r = pos; r < val_ptr->n_chars; r++)
241 if (c == val_ptr->chars_ptr[r]) return r;
242 return val_ptr->n_chars;
243 }
244
245 size_t string::find(const char *s, size_t pos) const
246 {
247 if (s == NULL)
248 FATAL_ERROR("string::find(const char *, size_t): called with NULL");
249 if (pos >= val_ptr->n_chars)
250 FATAL_ERROR("string::find(const char *, size_t): position outside of string");
251 const char *ptr = strstr(val_ptr->chars_ptr + pos, s);
252 if (ptr != NULL) return ptr - val_ptr->chars_ptr;
253 else return val_ptr->n_chars;
254 }
255
256 size_t string::rfind(char c, size_t pos) const
257 {
258 if (pos > val_ptr->n_chars) pos = val_ptr->n_chars;
259 for (size_t i = pos; i > 0; i--)
260 if (c == val_ptr->chars_ptr[i - 1]) return i - 1;
261 return val_ptr->n_chars;
262 }
263
264 size_t string::find_if(size_t first, size_t last, int (*pred)(int)) const
265 {
266 if (first > last) FATAL_ERROR("string::find_if(): first greater than last");
267 else if (last > val_ptr->n_chars)
268 FATAL_ERROR("string::find_if(): last greater than string length");
269 for (size_t r = first; r < last; r++)
270 if (pred(val_ptr->chars_ptr[r])) return r;
271 return last;
272 }
273
274 bool string::is_whitespace(unsigned char c)
275 {
276 switch (c) {
277 case ' ':
278 case '\t':
279 case '\n':
280 case '\r':
281 case '\v':
282 case '\f':
283 return true;
284 default:
285 return false;
286 }
287 }
288
289 bool string::is_printable(unsigned char c)
290 {
291 if (isprint(c)) return true;
292 else {
293 switch (c) {
294 case '\a':
295 case '\b':
296 case '\t':
297 case '\n':
298 case '\v':
299 case '\f':
300 case '\r':
301 return true;
302 default:
303 return false;
304 }
305 }
306 }
307
308 void string::append_stringRepr(char c)
309 {
310 switch (c) {
311 case '\a':
312 *this += "\\a";
313 break;
314 case '\b':
315 *this += "\\b";
316 break;
317 case '\t':
318 *this += "\\t";
319 break;
320 case '\n':
321 *this += "\\n";
322 break;
323 case '\v':
324 *this += "\\v";
325 break;
326 case '\f':
327 *this += "\\f";
328 break;
329 case '\r':
330 *this += "\\r";
331 break;
332 case '\\':
333 *this += "\\\\";
334 break;
335 case '"':
336 *this += "\\\"";
337 break;
338 default:
339 if (is_printable(c)) *this += c;
340 else FATAL_ERROR("string::append_stringRepr()");
341 break;
342 }
343 }
344
345 string string::get_stringRepr() const
346 {
347 string ret_val;
348 enum { INIT, PCHAR, NPCHAR } state = INIT;
349 for (size_t i = 0; i < val_ptr->n_chars; i++) {
350 char c = val_ptr->chars_ptr[i];
351 if (is_printable(c)) {
352 // the actual character is printable
353 switch (state) {
354 case NPCHAR: // concatenation sign if previous part was not printable
355 ret_val += " & ";
356 // no break
357 case INIT: // opening "
358 ret_val += '"';
359 // no break
360 case PCHAR: // the character itself
361 ret_val.append_stringRepr(c);
362 break;
363 }
364 state = PCHAR;
365 } else {
366 // the actual character is not printable
367 switch (state) {
368 case PCHAR: // closing " if previous part was printable
369 ret_val += '"';
370 // no break
371 case NPCHAR: // concatenation sign
372 ret_val += " & ";
373 // no break
374 case INIT: // the character itself in quadruple notation
375 ret_val += "char(0, 0, 0, ";
376 ret_val += Common::Int2string((unsigned char)c);
377 ret_val += ')';
378 break;
379 }
380 state = NPCHAR;
381 }
382 }
383 // final steps
384 switch (state) {
385 case INIT: // the string was empty
386 ret_val += "\"\"";
387 break;
388 case PCHAR: // last character was printable -> closing "
389 ret_val += '"';
390 break;
391 default:
392 break;
393 }
394 return ret_val;
395 }
396
397 ustring string::convert_stringRepr_for_pattern() const {
398 ustring ret_val;
399
400 if (val_ptr->n_chars % 8 != 0)
401 FATAL_ERROR("string::convert_stringRepr_for_pattern(): Cannot create"
402 "universal string. Length must be a multiple of 8.");
403
404 unsigned char c1, c2;
405 unsigned char array[4];
406 size_t index = 0;
407 while (index < val_ptr->n_chars) {
408 for (size_t j = 0; j < 4; j++) {
409 c1 = (unsigned char)val_ptr->chars_ptr[index++];
410 c2 = (unsigned char)val_ptr->chars_ptr[index++];
411 if (c1 >= 'A' && c1 <= 'P' && c2 >= 'A' && c2 <= 'P') {
412 array[j] = ((c1 - 'A') << 4) | (c2 - 'A');
413 } else
414 FATAL_ERROR("string::convert_stringRepr_for_pattern(): Cannot create"
415 "universal string. Source contains illegal character.");
416 }
417 ret_val += ustring(array[0], array[1], array[2], array[3]);
418 }
419 return ret_val;
420 }
421
422 string& string::operator=(const string& s)
423 {
424 if (&s != this) {
425 clean_up(val_ptr);
426 val_ptr = s.val_ptr;
427 val_ptr->ref_count++;
428 }
429 return *this;
430 }
431
432 string& string::operator=(const char *s)
433 {
434 if (s == NULL)
435 FATAL_ERROR("string::operator=(const char*): called with NULL");
436 if (val_ptr->chars_ptr != s) {
437 clean_up(val_ptr);
438 size_t n_chars = strlen(s);
439 init_struct(n_chars);
440 memcpy(val_ptr->chars_ptr, s, n_chars);
441 }
442 return *this;
443 }
444
445 char& string::operator[](size_t n)
446 {
447 if (n >= val_ptr->n_chars)
448 FATAL_ERROR("string::operator[](size_t): position is outside the string");
449 if (val_ptr->ref_count > 1) {
450 string_struct *old_ptr = val_ptr;
451 old_ptr->ref_count--;
452 init_struct(old_ptr->n_chars);
453 memcpy(val_ptr->chars_ptr, old_ptr->chars_ptr, old_ptr->n_chars);
454 }
455 return val_ptr->chars_ptr[n];
456 }
457
458 char string::operator[](size_t n) const
459 {
460 if (n >= val_ptr->n_chars)
461 FATAL_ERROR("string::operator[](size_t) const: position is outside the string");
462 return val_ptr->chars_ptr[n];
463 }
464
465 string string::operator+(const string& s) const
466 {
467 if (s.val_ptr->n_chars > max_string_len - val_ptr->n_chars)
468 FATAL_ERROR("string::operator+(const string&): length overflow");
469 if (val_ptr->n_chars == 0) return s;
470 else if (s.val_ptr->n_chars == 0) return *this;
471 else {
472 string ret_val(val_ptr->n_chars + s.val_ptr->n_chars);
473 memcpy(ret_val.val_ptr->chars_ptr, val_ptr->chars_ptr, val_ptr->n_chars);
474 memcpy(ret_val.val_ptr->chars_ptr + val_ptr->n_chars,
475 s.val_ptr->chars_ptr, s.val_ptr->n_chars);
476 return ret_val;
477 }
478 }
479
480 string string::operator+(const char *s) const
481 {
482 if (s == NULL)
483 FATAL_ERROR("string::operator+(const char*): called with NULL)");
484 size_t s_len = strlen(s);
485 if (s_len > max_string_len - val_ptr->n_chars)
486 FATAL_ERROR("string::operator+(const char*): length overflow");
487 if (s_len == 0) return *this;
488 else {
489 string ret_val(val_ptr->n_chars + s_len);
490 memcpy(ret_val.val_ptr->chars_ptr, val_ptr->chars_ptr, val_ptr->n_chars);
491 memcpy(ret_val.val_ptr->chars_ptr + val_ptr->n_chars, s, s_len);
492 return ret_val;
493 }
494 }
495
496 string& string::operator+=(const string& s)
497 {
498 if (s.val_ptr->n_chars > 0) {
499 if (val_ptr->n_chars > 0) {
500 copy_value_and_append(s.val_ptr->chars_ptr, s.val_ptr->n_chars);
501 } else {
502 clean_up(val_ptr);
503 val_ptr = s.val_ptr;
504 val_ptr->ref_count++;
505 }
506 }
507 return *this;
508 }
509
510 string& string::operator+=(const char *s)
511 {
512 if (s == NULL)
513 FATAL_ERROR("string::operator+=(const char*): called with NULL");
514 size_t s_len = strlen(s);
515 if (s_len > 0) copy_value_and_append(s, s_len);
516 return *this;
517 }
518
519 bool string::operator==(const string& s) const
520 {
521 if (val_ptr == s.val_ptr) return true;
522 else if (val_ptr->n_chars != s.val_ptr->n_chars) return false;
523 else return memcmp(val_ptr->chars_ptr, s.val_ptr->chars_ptr,
524 val_ptr->n_chars) == 0;
525 }
526
527 bool string::operator==(const char *s) const
528 {
529 if (s == NULL)
530 FATAL_ERROR("string::operator==(const char*): called with NULL");
531 if (s == val_ptr->chars_ptr) return true;
532 else return strcmp(val_ptr->chars_ptr, s) == 0;
533 }
534
535 string operator+(const char *s1, const string& s2)
536 {
537 if (s1 == NULL)
538 FATAL_ERROR("operator+(const char *, const string&): called with NULL");
539 size_t s1_len = strlen(s1);
540 if (s1_len > string::max_string_len - s2.val_ptr->n_chars)
541 FATAL_ERROR("operator+(const char *,const string&): length overflow");
542 if (s1_len > 0) {
543 string s(s1_len + s2.val_ptr->n_chars);
544 memcpy(s.val_ptr->chars_ptr, s1, s1_len);
545 memcpy(s.val_ptr->chars_ptr + s1_len, s2.val_ptr->chars_ptr,
546 s2.val_ptr->n_chars);
547 return s;
548 } else return s2;
549 }
550
551 void stringpool::clear()
552 {
553 for (size_t i = 0; i < list_len; i++) string::clean_up(string_list[i]);
554 Free(string_list);
555 string_list = NULL;
556 list_size = 0;
557 list_len = 0;
558 }
559
560 const char *stringpool::add(const string& s)
561 {
562 if (list_len > list_size) FATAL_ERROR("stringpool::add()");
563 else if (list_len == list_size) {
564 if (list_size == 0) {
565 string_list = static_cast<string::string_struct**>
566 (Malloc(STRINGPOOL_INITIAL_SIZE * sizeof(*string_list)));
567 list_size = STRINGPOOL_INITIAL_SIZE;
568 } else {
569 list_size *= STRINGPOOL_INCREMENT_FACTOR;
570 string_list = static_cast<string::string_struct**>
571 (Realloc(string_list, list_size * sizeof(*string_list)));
572 }
573 if (list_len >= list_size) FATAL_ERROR("stringpool::add()");
574 }
575 string::string_struct *val_ptr = s.val_ptr;
576 string_list[list_len++] = val_ptr;
577 val_ptr->ref_count++;
578 return val_ptr->chars_ptr;
579 }
580
581 const char *stringpool::get_str(size_t n) const
582 {
583 if (n >= list_len) FATAL_ERROR("stringpool::get_str()");
584 return string_list[n]->chars_ptr;
585 }
586
587 string stringpool::get_string(size_t n) const
588 {
589 if (n >= list_len) FATAL_ERROR("stringpool::get_string()");
590 return string(string_list[n]);
591 }
This page took 0.054532 seconds and 6 git commands to generate.