1 /******************************************************************************
2 * Copyright (c) 2000-2016 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
15 * Szabo, Janos Zoltan – initial implementation
16 * Zalanyi, Balazs Andor
18 ******************************************************************************/
24 #include "../common/memory.h"
32 /** Parameters for tuning memory usage of class stringpool */
33 #define STRINGPOOL_INITIAL_SIZE 8
34 #define STRINGPOOL_INCREMENT_FACTOR 2
36 /** The amount of memory needed for a string containing n characters. */
37 #define MEMORY_SIZE(n) (sizeof(string_struct) - sizeof(size_t) + 1 + (n))
39 void string::init_struct(size_t n_chars
)
42 /** This will represent the empty strings so they won't need allocated
43 * memory, this delays the memory allocation until it is really needed. */
44 static string_struct empty_string
= { 1, 0, "" };
45 val_ptr
= &empty_string
;
46 empty_string
.ref_count
++;
48 val_ptr
= static_cast<string_struct
*>(Malloc(MEMORY_SIZE(n_chars
)));
49 val_ptr
->ref_count
= 1;
50 val_ptr
->n_chars
= n_chars
;
51 val_ptr
->chars_ptr
[n_chars
] = '\0';
55 void string::copy_value_and_append(const char *s
, size_t n
)
57 if (n
> max_string_len
- val_ptr
->n_chars
)
58 FATAL_ERROR("string::copy_value_and_append(const char*, size_t): " \
60 if (val_ptr
->ref_count
== 1) {
61 ptrdiff_t offset
= s
- val_ptr
->chars_ptr
;
62 val_ptr
= static_cast<string_struct
*>
63 (Realloc(val_ptr
, MEMORY_SIZE(val_ptr
->n_chars
+ n
)));
64 // check whether the source buffer s is (part of) our existing buffer
65 if (offset
>= 0 && static_cast<size_t>(offset
) < val_ptr
->n_chars
)
66 memcpy(val_ptr
->chars_ptr
+ val_ptr
->n_chars
,
67 val_ptr
->chars_ptr
+ offset
, n
);
68 else memcpy(val_ptr
->chars_ptr
+ val_ptr
->n_chars
, s
, n
);
69 val_ptr
->n_chars
+= n
;
70 val_ptr
->chars_ptr
[val_ptr
->n_chars
] = '\0';
72 string_struct
*old_ptr
= val_ptr
;
74 init_struct(old_ptr
->n_chars
+ n
);
75 memcpy(val_ptr
->chars_ptr
, old_ptr
->chars_ptr
, old_ptr
->n_chars
);
76 memcpy(val_ptr
->chars_ptr
+ old_ptr
->n_chars
, s
, n
);
80 /** Internal worker for various replace() methods.
82 * @param pos the index of the first character to replace
83 * @param n the number of characters to replace
84 * @param s the replacement
85 * @param s_len the length of the replacement
87 * @pre \p pos must point inside the string
88 * @pre \p pos + \p n must point inside the string
89 * @pre the resulting string must not exceed max_string_len
91 void string::replace(size_t pos
, size_t n
, const char *s
, size_t s_len
)
93 if (pos
> val_ptr
->n_chars
)
94 FATAL_ERROR("string::replace(): start position is outside the string");
95 if (pos
+ n
> val_ptr
->n_chars
)
96 FATAL_ERROR("string::replace(): end position is outside the string");
97 if (s_len
> max_string_len
- val_ptr
->n_chars
+ n
)
98 FATAL_ERROR("string::replace(): length overflow");
99 // do nothing if we are replacing with the same string
100 if (n
== s_len
&& memcmp(val_ptr
->chars_ptr
+ pos
, s
, n
) == 0) return;
101 size_t new_size
= val_ptr
->n_chars
- n
+ s_len
;
103 // the result is an empty string
106 } else if (val_ptr
->ref_count
== 1 && (s
< val_ptr
->chars_ptr
||
107 s
>= val_ptr
->chars_ptr
+ val_ptr
->n_chars
)) {
108 // check whether this string is not referenced by others and we are not
109 // replacing with ourselves
110 if (val_ptr
->n_chars
< new_size
) val_ptr
= static_cast<string_struct
*>
111 (Realloc(val_ptr
, MEMORY_SIZE(new_size
)));
112 memmove(val_ptr
->chars_ptr
+ pos
+ s_len
,
113 val_ptr
->chars_ptr
+ pos
+ n
, val_ptr
->n_chars
- pos
- n
);
114 memcpy(val_ptr
->chars_ptr
+ pos
, s
, s_len
);
115 if (val_ptr
->n_chars
> new_size
) val_ptr
= static_cast<string_struct
*>
116 (Realloc(val_ptr
, MEMORY_SIZE(new_size
)));
117 val_ptr
->n_chars
= new_size
;
118 val_ptr
->chars_ptr
[new_size
] = '\0';
120 // the result must be copied into a new memory area
121 string_struct
*old_ptr
= val_ptr
;
122 old_ptr
->ref_count
--;
123 init_struct(new_size
);
124 memcpy(val_ptr
->chars_ptr
, old_ptr
->chars_ptr
, pos
);
125 memcpy(val_ptr
->chars_ptr
+ pos
, s
, s_len
);
126 memcpy(val_ptr
->chars_ptr
+ pos
+ s_len
, old_ptr
->chars_ptr
+ pos
+ n
,
127 old_ptr
->n_chars
- pos
- n
);
128 if (old_ptr
->ref_count
== 0) Free(old_ptr
);
132 void string::clean_up(string_struct
*ptr
)
134 if (ptr
->ref_count
> 1) ptr
->ref_count
--;
135 else if (ptr
->ref_count
== 1) Free(ptr
);
136 else FATAL_ERROR("string::clean_up()");
139 int string::compare(const string
& s
) const
141 if (val_ptr
== s
.val_ptr
) return 0;
142 else return strcmp(val_ptr
->chars_ptr
, s
.val_ptr
->chars_ptr
);
145 int string::compare(const char *s
) const
147 if (val_ptr
->chars_ptr
== s
) return 0;
148 else return strcmp(val_ptr
->chars_ptr
, s
);
151 string::string(const char *s
)
153 if (s
== NULL
) FATAL_ERROR("string::string(const char*): called with NULL");
154 size_t n_chars
= strlen(s
);
155 init_struct(n_chars
);
156 memcpy(val_ptr
->chars_ptr
, s
, n_chars
);
159 string::string(size_t n
, const char *s
)
161 if (s
== NULL
&& n
> 0)
162 FATAL_ERROR("string::string(size_t, const char*): called with NULL");
164 memcpy(val_ptr
->chars_ptr
, s
, n
);
167 string::string(const ustring
& s
)
169 size_t s_len
= s
.size();
171 const ustring::universal_char
*src
= s
.u_str();
172 for (size_t i
= 0; i
< s_len
; i
++) {
173 if (src
[i
].group
!= 0 || src
[i
].plane
!= 0 || src
[i
].row
!= 0)
174 FATAL_ERROR("string::string(const ustring&)");
175 val_ptr
->chars_ptr
[i
] = src
[i
].cell
;
179 bool string::is_cstr() const
181 for (size_t i
= 0; i
< val_ptr
->n_chars
; i
++)
182 if ((unsigned char)val_ptr
->chars_ptr
[i
] > 127) return false;
188 if (val_ptr
->n_chars
> 0) {
194 string
string::substr(size_t pos
, size_t n
) const
196 if (pos
> val_ptr
->n_chars
)
197 FATAL_ERROR("string::substr(size_t, size_t): position is outside the " \
199 size_t n_chars
= val_ptr
->n_chars
- pos
;
200 if (n_chars
> n
) n_chars
= n
;
201 if (n_chars
== val_ptr
->n_chars
) return *this;
202 else return string(n_chars
, val_ptr
->chars_ptr
+ pos
);
205 void string::resize(size_t n
, char c
)
207 size_t old_length
= val_ptr
->n_chars
;
208 if (old_length
== n
) return;
209 if (val_ptr
->ref_count
== 1) {
211 val_ptr
= static_cast<string_struct
*>(Realloc(val_ptr
, MEMORY_SIZE(n
)));
212 if (n
> old_length
) {
213 memset(val_ptr
->chars_ptr
+ old_length
, c
, n
- old_length
);
215 val_ptr
->chars_ptr
[n
] = '\0';
216 val_ptr
->n_chars
= n
;
222 val_ptr
->ref_count
--;
223 string_struct
*tmp_ptr
= val_ptr
;
225 if (n
> old_length
) {
226 memcpy(val_ptr
->chars_ptr
, tmp_ptr
->chars_ptr
, old_length
);
227 memset(val_ptr
->chars_ptr
+ old_length
, c
, n
- old_length
);
229 memcpy(val_ptr
->chars_ptr
, tmp_ptr
->chars_ptr
, n
);
234 void string::replace(size_t pos
, size_t n
, const char *s
)
236 if (s
== NULL
) FATAL_ERROR("string::replace(size_t, size_t, const char*): " \
238 replace(pos
, n
, s
, strlen(s
));
241 void string::replace(size_t pos
, size_t n
, const string
& s
)
243 if (pos
== 0 && n
== val_ptr
->n_chars
) *this = s
;
244 else replace(pos
, n
, s
.val_ptr
->chars_ptr
, s
.val_ptr
->n_chars
);
247 size_t string::find(char c
, size_t pos
) const
249 if (pos
> val_ptr
->n_chars
)
250 FATAL_ERROR("string::find(char, size_t): position is outside of string");
251 for (size_t r
= pos
; r
< val_ptr
->n_chars
; r
++)
252 if (c
== val_ptr
->chars_ptr
[r
]) return r
;
253 return val_ptr
->n_chars
;
256 size_t string::find(const char *s
, size_t pos
) const
259 FATAL_ERROR("string::find(const char *, size_t): called with NULL");
260 if (pos
>= val_ptr
->n_chars
)
261 FATAL_ERROR("string::find(const char *, size_t): position outside of string");
262 const char *ptr
= strstr(val_ptr
->chars_ptr
+ pos
, s
);
263 if (ptr
!= NULL
) return ptr
- val_ptr
->chars_ptr
;
264 else return val_ptr
->n_chars
;
267 size_t string::rfind(char c
, size_t pos
) const
269 if (pos
> val_ptr
->n_chars
) pos
= val_ptr
->n_chars
;
270 for (size_t i
= pos
; i
> 0; i
--)
271 if (c
== val_ptr
->chars_ptr
[i
- 1]) return i
- 1;
272 return val_ptr
->n_chars
;
275 size_t string::find_if(size_t first
, size_t last
, int (*pred
)(int)) const
277 if (first
> last
) FATAL_ERROR("string::find_if(): first greater than last");
278 else if (last
> val_ptr
->n_chars
)
279 FATAL_ERROR("string::find_if(): last greater than string length");
280 for (size_t r
= first
; r
< last
; r
++)
281 if (pred(val_ptr
->chars_ptr
[r
])) return r
;
285 bool string::is_whitespace(unsigned char c
)
300 bool string::is_printable(unsigned char c
)
302 if (isprint(c
)) return true;
319 void string::append_stringRepr(char c
)
350 if (is_printable(c
)) *this += c
;
351 else FATAL_ERROR("string::append_stringRepr()");
356 string
string::get_stringRepr() const
359 enum { INIT
, PCHAR
, NPCHAR
} state
= INIT
;
360 for (size_t i
= 0; i
< val_ptr
->n_chars
; i
++) {
361 char c
= val_ptr
->chars_ptr
[i
];
362 if (is_printable(c
)) {
363 // the actual character is printable
365 case NPCHAR
: // concatenation sign if previous part was not printable
368 case INIT
: // opening "
371 case PCHAR
: // the character itself
372 ret_val
.append_stringRepr(c
);
377 // the actual character is not printable
379 case PCHAR
: // closing " if previous part was printable
382 case NPCHAR
: // concatenation sign
385 case INIT
: // the character itself in quadruple notation
386 ret_val
+= "char(0, 0, 0, ";
387 ret_val
+= Common::Int2string((unsigned char)c
);
396 case INIT
: // the string was empty
399 case PCHAR
: // last character was printable -> closing "
408 ustring
string::convert_stringRepr_for_pattern() const {
411 if (val_ptr
->n_chars
% 8 != 0)
412 FATAL_ERROR("string::convert_stringRepr_for_pattern(): Cannot create"
413 "universal string. Length must be a multiple of 8.");
415 unsigned char c1
, c2
;
416 unsigned char array
[4];
418 while (index
< val_ptr
->n_chars
) {
419 for (size_t j
= 0; j
< 4; j
++) {
420 c1
= (unsigned char)val_ptr
->chars_ptr
[index
++];
421 c2
= (unsigned char)val_ptr
->chars_ptr
[index
++];
422 if (c1
>= 'A' && c1
<= 'P' && c2
>= 'A' && c2
<= 'P') {
423 array
[j
] = ((c1
- 'A') << 4) | (c2
- 'A');
425 FATAL_ERROR("string::convert_stringRepr_for_pattern(): Cannot create"
426 "universal string. Source contains illegal character.");
428 ret_val
+= ustring(array
[0], array
[1], array
[2], array
[3]);
433 string
& string::operator=(const string
& s
)
438 val_ptr
->ref_count
++;
443 string
& string::operator=(const char *s
)
446 FATAL_ERROR("string::operator=(const char*): called with NULL");
447 if (val_ptr
->chars_ptr
!= s
) {
449 size_t n_chars
= strlen(s
);
450 init_struct(n_chars
);
451 memcpy(val_ptr
->chars_ptr
, s
, n_chars
);
456 char& string::operator[](size_t n
)
458 if (n
>= val_ptr
->n_chars
)
459 FATAL_ERROR("string::operator[](size_t): position is outside the string");
460 if (val_ptr
->ref_count
> 1) {
461 string_struct
*old_ptr
= val_ptr
;
462 old_ptr
->ref_count
--;
463 init_struct(old_ptr
->n_chars
);
464 memcpy(val_ptr
->chars_ptr
, old_ptr
->chars_ptr
, old_ptr
->n_chars
);
466 return val_ptr
->chars_ptr
[n
];
469 char string::operator[](size_t n
) const
471 if (n
>= val_ptr
->n_chars
)
472 FATAL_ERROR("string::operator[](size_t) const: position is outside the string");
473 return val_ptr
->chars_ptr
[n
];
476 string
string::operator+(const string
& s
) const
478 if (s
.val_ptr
->n_chars
> max_string_len
- val_ptr
->n_chars
)
479 FATAL_ERROR("string::operator+(const string&): length overflow");
480 if (val_ptr
->n_chars
== 0) return s
;
481 else if (s
.val_ptr
->n_chars
== 0) return *this;
483 string
ret_val(val_ptr
->n_chars
+ s
.val_ptr
->n_chars
);
484 memcpy(ret_val
.val_ptr
->chars_ptr
, val_ptr
->chars_ptr
, val_ptr
->n_chars
);
485 memcpy(ret_val
.val_ptr
->chars_ptr
+ val_ptr
->n_chars
,
486 s
.val_ptr
->chars_ptr
, s
.val_ptr
->n_chars
);
491 string
string::operator+(const char *s
) const
494 FATAL_ERROR("string::operator+(const char*): called with NULL)");
495 size_t s_len
= strlen(s
);
496 if (s_len
> max_string_len
- val_ptr
->n_chars
)
497 FATAL_ERROR("string::operator+(const char*): length overflow");
498 if (s_len
== 0) return *this;
500 string
ret_val(val_ptr
->n_chars
+ s_len
);
501 memcpy(ret_val
.val_ptr
->chars_ptr
, val_ptr
->chars_ptr
, val_ptr
->n_chars
);
502 memcpy(ret_val
.val_ptr
->chars_ptr
+ val_ptr
->n_chars
, s
, s_len
);
507 string
& string::operator+=(const string
& s
)
509 if (s
.val_ptr
->n_chars
> 0) {
510 if (val_ptr
->n_chars
> 0) {
511 copy_value_and_append(s
.val_ptr
->chars_ptr
, s
.val_ptr
->n_chars
);
515 val_ptr
->ref_count
++;
521 string
& string::operator+=(const char *s
)
524 FATAL_ERROR("string::operator+=(const char*): called with NULL");
525 size_t s_len
= strlen(s
);
526 if (s_len
> 0) copy_value_and_append(s
, s_len
);
530 bool string::operator==(const string
& s
) const
532 if (val_ptr
== s
.val_ptr
) return true;
533 else if (val_ptr
->n_chars
!= s
.val_ptr
->n_chars
) return false;
534 else return memcmp(val_ptr
->chars_ptr
, s
.val_ptr
->chars_ptr
,
535 val_ptr
->n_chars
) == 0;
538 bool string::operator==(const char *s
) const
541 FATAL_ERROR("string::operator==(const char*): called with NULL");
542 if (s
== val_ptr
->chars_ptr
) return true;
543 else return strcmp(val_ptr
->chars_ptr
, s
) == 0;
546 string
operator+(const char *s1
, const string
& s2
)
549 FATAL_ERROR("operator+(const char *, const string&): called with NULL");
550 size_t s1_len
= strlen(s1
);
551 if (s1_len
> string::max_string_len
- s2
.val_ptr
->n_chars
)
552 FATAL_ERROR("operator+(const char *,const string&): length overflow");
554 string
s(s1_len
+ s2
.val_ptr
->n_chars
);
555 memcpy(s
.val_ptr
->chars_ptr
, s1
, s1_len
);
556 memcpy(s
.val_ptr
->chars_ptr
+ s1_len
, s2
.val_ptr
->chars_ptr
,
557 s2
.val_ptr
->n_chars
);
562 void stringpool::clear()
564 for (size_t i
= 0; i
< list_len
; i
++) string::clean_up(string_list
[i
]);
571 const char *stringpool::add(const string
& s
)
573 if (list_len
> list_size
) FATAL_ERROR("stringpool::add()");
574 else if (list_len
== list_size
) {
575 if (list_size
== 0) {
576 string_list
= static_cast<string::string_struct
**>
577 (Malloc(STRINGPOOL_INITIAL_SIZE
* sizeof(*string_list
)));
578 list_size
= STRINGPOOL_INITIAL_SIZE
;
580 list_size
*= STRINGPOOL_INCREMENT_FACTOR
;
581 string_list
= static_cast<string::string_struct
**>
582 (Realloc(string_list
, list_size
* sizeof(*string_list
)));
584 if (list_len
>= list_size
) FATAL_ERROR("stringpool::add()");
586 string::string_struct
*val_ptr
= s
.val_ptr
;
587 string_list
[list_len
++] = val_ptr
;
588 val_ptr
->ref_count
++;
589 return val_ptr
->chars_ptr
;
592 const char *stringpool::get_str(size_t n
) const
594 if (n
>= list_len
) FATAL_ERROR("stringpool::get_str()");
595 return string_list
[n
]->chars_ptr
;
598 string
stringpool::get_string(size_t n
) const
600 if (n
>= list_len
) FATAL_ERROR("stringpool::get_string()");
601 return string(string_list
[n
]);