Sync with 5.4.0
[deliverable/titan.core.git] / compiler2 / string.cc
CommitLineData
970ed795 1///////////////////////////////////////////////////////////////////////////////
3abe9331 2// Copyright (c) 2000-2015 Ericsson Telecom AB
970ed795
EL
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
28void 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
44void 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 */
80void 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
121void 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
128int 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
134int 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
140string::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
148string::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
156string::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
168bool 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
175void string::clear()
176{
177 if (val_ptr->n_chars > 0) {
178 clean_up(val_ptr);
179 init_struct(0);
180 }
181}
182
183string 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
194void 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
223void 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
230void 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
236size_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
245size_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
256size_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
264size_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
274bool 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
289bool 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
308void 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
345string 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
397ustring 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
422string& 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
432string& 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
445char& 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
458char 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
465string 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
480string 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
496string& 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
510string& 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
519bool 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
527bool 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
535string 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
551void 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
560const 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
581const 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
587string 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.068718 seconds and 5 git commands to generate.