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 ///////////////////////////////////////////////////////////////////////////////
13 #include "../common/memory.h"
21 /** Parameters for tuning memory usage of class stringpool */
22 #define STRINGPOOL_INITIAL_SIZE 8
23 #define STRINGPOOL_INCREMENT_FACTOR 2
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))
28 void string::init_struct(size_t n_chars
)
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
++;
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';
44 void string::copy_value_and_append(const char *s
, size_t n
)
46 if (n
> max_string_len
- val_ptr
->n_chars
)
47 FATAL_ERROR("string::copy_value_and_append(const char*, size_t): " \
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';
61 string_struct
*old_ptr
= val_ptr
;
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
);
69 /** Internal worker for various replace() methods.
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
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
80 void string::replace(size_t pos
, size_t n
, const char *s
, size_t s_len
)
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
;
92 // the result is an empty string
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';
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
);
121 void string::clean_up(string_struct
*ptr
)
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()");
128 int string::compare(const string
& s
) const
130 if (val_ptr
== s
.val_ptr
) return 0;
131 else return strcmp(val_ptr
->chars_ptr
, s
.val_ptr
->chars_ptr
);
134 int string::compare(const char *s
) const
136 if (val_ptr
->chars_ptr
== s
) return 0;
137 else return strcmp(val_ptr
->chars_ptr
, s
);
140 string::string(const char *s
)
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
);
148 string::string(size_t n
, const char *s
)
150 if (s
== NULL
&& n
> 0)
151 FATAL_ERROR("string::string(size_t, const char*): called with NULL");
153 memcpy(val_ptr
->chars_ptr
, s
, n
);
156 string::string(const ustring
& s
)
158 size_t s_len
= s
.size();
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
;
168 bool string::is_cstr() const
170 for (size_t i
= 0; i
< val_ptr
->n_chars
; i
++)
171 if ((unsigned char)val_ptr
->chars_ptr
[i
] > 127) return false;
177 if (val_ptr
->n_chars
> 0) {
183 string
string::substr(size_t pos
, size_t n
) const
185 if (pos
> val_ptr
->n_chars
)
186 FATAL_ERROR("string::substr(size_t, size_t): position is outside the " \
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
);
194 void string::resize(size_t n
, char c
)
196 size_t old_length
= val_ptr
->n_chars
;
197 if (old_length
== n
) return;
198 if (val_ptr
->ref_count
== 1) {
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
);
204 val_ptr
->chars_ptr
[n
] = '\0';
205 val_ptr
->n_chars
= n
;
211 val_ptr
->ref_count
--;
212 string_struct
*tmp_ptr
= val_ptr
;
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
);
218 memcpy(val_ptr
->chars_ptr
, tmp_ptr
->chars_ptr
, n
);
223 void string::replace(size_t pos
, size_t n
, const char *s
)
225 if (s
== NULL
) FATAL_ERROR("string::replace(size_t, size_t, const char*): " \
227 replace(pos
, n
, s
, strlen(s
));
230 void string::replace(size_t pos
, size_t n
, const string
& s
)
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
);
236 size_t string::find(char c
, size_t pos
) const
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
;
245 size_t string::find(const char *s
, size_t pos
) const
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
;
256 size_t string::rfind(char c
, size_t pos
) const
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
;
264 size_t string::find_if(size_t first
, size_t last
, int (*pred
)(int)) const
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
;
274 bool string::is_whitespace(unsigned char c
)
289 bool string::is_printable(unsigned char c
)
291 if (isprint(c
)) return true;
308 void string::append_stringRepr(char c
)
339 if (is_printable(c
)) *this += c
;
340 else FATAL_ERROR("string::append_stringRepr()");
345 string
string::get_stringRepr() const
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
354 case NPCHAR
: // concatenation sign if previous part was not printable
357 case INIT
: // opening "
360 case PCHAR
: // the character itself
361 ret_val
.append_stringRepr(c
);
366 // the actual character is not printable
368 case PCHAR
: // closing " if previous part was printable
371 case NPCHAR
: // concatenation sign
374 case INIT
: // the character itself in quadruple notation
375 ret_val
+= "char(0, 0, 0, ";
376 ret_val
+= Common::Int2string((unsigned char)c
);
385 case INIT
: // the string was empty
388 case PCHAR
: // last character was printable -> closing "
397 ustring
string::convert_stringRepr_for_pattern() const {
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.");
404 unsigned char c1
, c2
;
405 unsigned char array
[4];
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');
414 FATAL_ERROR("string::convert_stringRepr_for_pattern(): Cannot create"
415 "universal string. Source contains illegal character.");
417 ret_val
+= ustring(array
[0], array
[1], array
[2], array
[3]);
422 string
& string::operator=(const string
& s
)
427 val_ptr
->ref_count
++;
432 string
& string::operator=(const char *s
)
435 FATAL_ERROR("string::operator=(const char*): called with NULL");
436 if (val_ptr
->chars_ptr
!= s
) {
438 size_t n_chars
= strlen(s
);
439 init_struct(n_chars
);
440 memcpy(val_ptr
->chars_ptr
, s
, n_chars
);
445 char& string::operator[](size_t n
)
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
);
455 return val_ptr
->chars_ptr
[n
];
458 char string::operator[](size_t n
) const
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
];
465 string
string::operator+(const string
& s
) const
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;
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
);
480 string
string::operator+(const char *s
) const
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;
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
);
496 string
& string::operator+=(const string
& s
)
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
);
504 val_ptr
->ref_count
++;
510 string
& string::operator+=(const char *s
)
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
);
519 bool string::operator==(const string
& s
) const
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;
527 bool string::operator==(const char *s
) const
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;
535 string
operator+(const char *s1
, const string
& s2
)
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");
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
);
551 void stringpool::clear()
553 for (size_t i
= 0; i
< list_len
; i
++) string::clean_up(string_list
[i
]);
560 const char *stringpool::add(const string
& s
)
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
;
569 list_size
*= STRINGPOOL_INCREMENT_FACTOR
;
570 string_list
= static_cast<string::string_struct
**>
571 (Realloc(string_list
, list_size
* sizeof(*string_list
)));
573 if (list_len
>= list_size
) FATAL_ERROR("stringpool::add()");
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
;
581 const char *stringpool::get_str(size_t n
) const
583 if (n
>= list_len
) FATAL_ERROR("stringpool::get_str()");
584 return string_list
[n
]->chars_ptr
;
587 string
stringpool::get_string(size_t n
) const
589 if (n
>= list_len
) FATAL_ERROR("stringpool::get_string()");
590 return string(string_list
[n
]);