Geant4 11.4.0
Toolkit for the simulation of the passage of particles through matter
Loading...
Searching...
No Matches
MCGIDI_string.cc
Go to the documentation of this file.
1/*
2 # <<BEGIN-copyright>>
3# Copyright 2019, Lawrence Livermore National Security, LLC.
4# This file is part of the gidiplus package (https://github.com/LLNL/gidiplus).
5# gidiplus is licensed under the MIT license (see https://opensource.org/licenses/MIT).
6# SPDX-License-Identifier: MIT
7 # <<END-copyright>>
8 *
9 * IMPLEMENTATION NOTES
10 *
11 * My goal was to create a small, and conceptually simple
12 * string class. I allocate unique memory for every object
13 * created, instead of doing anything fancy.
14 *
15 * I've taken care about the order in which I free memory,
16 * in case we are copying overlapping regions.
17 *
18 */
19
20#include <stdio.h>
21#include <stdlib.h> // malloc, realloc
22#include <string.h>
23#include <assert.h>
24
25#include "MCGIDI_string.hpp"
26
27namespace MCGIDI {
28
29#define MCGIDI_MIN(x,y) ( ( (x) < (y) ) ? (x) : (y) )
30#define MCGIDI_SWAP(a,b,type) {type ttttttttt=a;a=b;b=ttttttttt;}
31LUPI_HOST_DEVICE int MCGIDI_strcmp (const char *p1, const char *p2);
32LUPI_HOST_DEVICE size_t MCGIDI_strlen (const char *str);
33LUPI_HOST_DEVICE void MCGIDI_memmove(char *dest, const char *src, size_t n);
34LUPI_HOST_DEVICE int MCGIDI_strncmp( const char * s1, const char * s2, size_t n );
35
36 const String::size_type String::npos = static_cast<size_t>(-1);
37
38 /*
39 * Like the 'new' operator, we want to guarantee that we NEVER
40 * return nullptr. Loop until there is free memory.
41 *
42 */
43 LUPI_HOST_DEVICE static char* malloc_never_null(const size_t b)
44 {
45 char *p;
46
47 do {
48 p = static_cast<char*>(malloc(b));
49 } while ( p == nullptr );
50
51 return p;
52 }
53
54 /**
55 * Allocates memory for the copy the string at the same time sets "this->allocated".
56 * @param s
57 * @return
58 */
59 LUPI_HOST_DEVICE char* String::strdup_never_null(const char* s)
60 {
61 const size_t len = MCGIDI_strlen(s)+1;
62 char *p2 = malloc_never_null(len);
63 memcpy(p2, s, len);
64 allocated_=len;
65 size_=len-1;
66 return p2;
67 }
68
69 LUPI_HOST_DEVICE String::String() : p( nullptr ), allocated_(0), size_(0) { }
70
75
77 : p(nullptr)
78 {
79 p = malloc_never_null( s.size_ + 1 ); // copy only used part
80 allocated_ = s.size_ + 1;
81 size_ = s.size_;
82 memcpy(p, s.p, size_ + 1);
83 }
84
86 : p(strdup_never_null(s))
87 {
88 }
89
91 {
92 if ( p != s ) {
93 // s could point into our own string, so we have to allocate a new string
94 const size_t len = MCGIDI_strlen(s);
95 char* copy = (char*) malloc( len + 1);
96 MCGIDI_memmove(copy, s, len+1); // trailing 0
97 free( p );
98 p = copy;
99 size_ = len;
100 allocated_ = len+1;
101 }
102
103 return *this;
104 }
105
107 {
108 return operator=(s.p);
109 }
110
112 {
113 if (s.size_ > 0){
114 this->reserve(size_ + s.size_);
115 MCGIDI_memmove(p+size_, s.p, s.size_+1); // trailing 0
116 size_ += s.size_;
117 }
118 return *this;
119 }
120
121 // since p and s may overlap, we have to copy our own string first
123 {
124 const size_type lens = MCGIDI_strlen(s);
125 if (lens > 0){
126 if (size_ + lens + 1 <= allocated_) {
127 MCGIDI_memmove(p+size_, s, lens+1); // trailing 0
128 size_ += lens;
129 }
130 else {
131 String s2( *this ); // copy own data
132 s2.reserve(size_ + lens);
133 MCGIDI_memmove(s2.p+size_, s, lens+1); // trailing 0
134 s2.size_ = size_ + lens;
135 this->swap( s2 );
136 }
137 }
138 return *this;
139 }
140
142 {
143 push_back(c);
144 return *this;
145 }
146
147
149
150 if (size_ == allocated_ - 1) {
151 size_t more = (allocated_* 3) / 2; // factor 1.5
152 if ( more < 4 ) more = 4;
153 reserve( size_ + more );
154 }
155
156 p[size_] = c;
157 size_++;
158 p[size_] = 0;
159 }
160
161 LUPI_HOST_DEVICE bool String::operator==(const char* s) const
162 {
163 return !MCGIDI_strcmp(p, s);
164 }
165
167 {
168 return !MCGIDI_strcmp(p, s.p);
169 }
170
172 {
173 String s;
174 this->swap( s );
175 }
176
178 {
179 size_ = 0;
180 p[0] = 0;
181 }
182
184 {
185 return String(lhs) += rhs;
186 }
187
189 {
190 String s;
191 const size_type len = size_;
192
193 if ( pos > len )
194 LUPI_THROW("MCGIDI::String::substr: pos index out of range");
195
196 size_type remain = len - pos;
197
198 if ( in_length > remain )
199 in_length = remain;
200
201 s.reserve( in_length );
202
203 memcpy(s.p, p + pos, in_length);
204 s.p[in_length] = '\0';
205 s.size_ = in_length;
206
207 return s;
208 }
209
210
211 // checked access, accessing the NUL at end is allowed
213 {
214 if ( i > MCGIDI_strlen(p) )
215 LUPI_THROW( "MCGIDI::String::at(): index out_of_range");
216
217 return p[i];
218 }
220 {
221 if ( i > MCGIDI_strlen(p) )
222 LUPI_THROW("MCGIDI::String::at(): index out_of_range");
223
224 return p[i];
225 }
226
228 {
229 if (len > 0) {
230
231 if ( pos >= size_ ) // user must not remove trailing 0
232 LUPI_THROW("MCGIDI::String::erase: pos index out_of_range");
233
234 long s2 = (long) size_;
235 long remain = s2 - (long) ( pos - len );
236
237 if (remain > 0) {
238 // erase by overwriting
239 MCGIDI_memmove(p + pos, p + pos + len, (size_t) remain);
240 }
241
242 if ( remain < 0 ) remain = 0;
243
244 // remove unused space
245 this->resize( pos + (size_t) remain );
246
247 }
248 return *this;
249 }
250
252 if (str && n > 0) {
253 size_t lens = MCGIDI_strlen(str);
254 if (n > lens)
255 n = lens;
256 size_t newlen = size_ + n;
257 this->reserve( newlen );
258 MCGIDI_memmove(p+size_, str, n); // p and s.p MAY overlap
259 p[newlen] = 0; // add NUL termination
260 size_ = newlen;
261 }
262 return *this;
263 }
264
265 LUPI_HOST_DEVICE int String::compare( size_type pos, size_type len, const String& str ) const {
266 if (pos > size_)
267 LUPI_THROW("MCGIDI::String::compare: pos index out of range");
268
269 if ( len > size_ - pos)
270 len = size_ - pos; // limit len to available length
271
272 const size_type osize = str.size();
273 const size_type len2 = MCGIDI_MIN(len, osize);
274 int r = MCGIDI_strncmp( p + pos, str.p, len2);
275 if (r==0) // equal so far, now compare sizes
276 r = len < osize ? -1 : ( len == osize ? 0 : +1 );
277 return r;
278 }
279
280 LUPI_HOST_DEVICE int String::compare( size_type pos, size_type len, const char* str ) const {
281 if (pos > size_)
282 LUPI_THROW("MCGIDI::String::compare: pos index out of range");
283
284 if ( len > size_ - pos)
285 len = size_ - pos; // limit len to available length
286
287 const size_type osize = MCGIDI_strlen(str);
288 const size_type len2 = MCGIDI_MIN(len, osize);
289 int r = MCGIDI_strncmp( p + pos, str, len2);
290 if (r==0) // equal so far, now compare sizes
291 r = len < osize ? -1 : ( len == osize ? 0 : +1 );
292 return r;
293 }
294
295
296 LUPI_HOST_DEVICE void String::my_realloc( size_type n, char ** address) {
297 if (address != nullptr && *address != nullptr) {
298 p = *address;
299 long delta = (long) ( sizeof(char) * n );
300 long sub = delta % 8;
301 if (sub != 0) delta += (8-sub);
302 *address += delta;
303 return;
304 }
305 if (n > 0 ) {
306 char* pnew = static_cast<char*>(malloc(n)); // could return nullptr
307 if (pnew) {
308 free(p);
309 p = pnew;
310 }
311 else
312 LUPI_THROW("MCGIDI::String::my_realloc out of memory");
313 }
314 }
315
316
317 LUPI_HOST_DEVICE void String::reserve( const size_type n, char ** address) {
318 if (n >= allocated_ ) {
319 this->my_realloc(n + 1, address);
320 allocated_ = n + 1;
321 }
322 }
323
324 LUPI_HOST_DEVICE void String::resize( const size_type n, char ** address) {
325 this->resize( n, 0, address );
326 }
327
328 LUPI_HOST_DEVICE void String::resize( const size_type n, const char c, char ** address) {
329 if (n < allocated_ ) {
330 p[n] = 0;
331 size_ = n;
332 }
333 else if (n >= allocated_ ) {
334 this->reserve( n, address );
335 for (size_type i=size_; i < n; ++i )
336 p[i] = c;
337 p[n] = 0;
338 size_ = n;
339 }
340 }
341
343 MCGIDI_SWAP( allocated_, s.allocated_, size_t );
344 MCGIDI_SWAP( size_, s.size_, size_t );
345 MCGIDI_SWAP( p, s.p, char * );
346 }
347
348
349 // Comparison
350 LUPI_HOST_DEVICE bool operator<( const String& s1, const String& s2 ) {
351 return MCGIDI_strcmp( s1.c_str(), s2.c_str() ) < 0;
352 }
353
354 /* Compare S1 and S2, returning less than, equal to or
355 greater than zero if S1 is lexicographically less than,
356 equal to or greater than S2. */
357 LUPI_HOST_DEVICE int MCGIDI_strcmp (const char *p1, const char *p2)
358 {
359 const unsigned char *s1 = (const unsigned char *) p1;
360 const unsigned char *s2 = (const unsigned char *) p2;
361 unsigned char c1, c2;
362
363 do
364 {
365 c1 = (unsigned char) *s1++;
366 c2 = (unsigned char) *s2++;
367 if (c1 == '\0')
368 return c1 - c2;
369 }
370 while (c1 == c2);
371
372 return c1 - c2;
373 }
374
375 LUPI_HOST_DEVICE size_t MCGIDI_strlen (const char *str) {
376 size_t len = 0;
377 while (*str != '\0') {
378 str++;
379 len++;
380 }
381 return len;
382 }
383
384 // A function to copy block of 'n' bytes from source
385 // address 'src' to destination address 'dest'.
386 LUPI_HOST_DEVICE void MCGIDI_memmove(char *dest, const char *src, size_t n)
387 {
388 // Typecast src and dest addresses to (char *)
389 char *csrc = (char *)src;
390 char *cdest = (char *)dest;
391
392 // Create a temporary array to hold data of src
393 char* temp = (char*) malloc( n);
394
395 // Copy data from csrc[] to temp[]
396 for (size_t i=0; i<n; i++)
397 temp[i] = csrc[i];
398
399 // Copy data from temp[] to cdest[]
400 for (size_t i=0; i<n; i++)
401 cdest[i] = temp[i];
402
403 free(temp);
404 }
405
406 LUPI_HOST_DEVICE int MCGIDI_strncmp( const char * s1, const char * s2, size_t n )
407 {
408 while ( n && *s1 && ( *s1 == *s2 ) )
409 {
410 ++s1;
411 ++s2;
412 --n;
413 }
414 if ( n == 0 )
415 {
416 return 0;
417 }
418 else
419 {
420 return ( *(unsigned char *)s1 - *(unsigned char *)s2 );
421 }
422 }
423
424}
#define LUPI_HOST_DEVICE
#define LUPI_THROW(arg)
#define MCGIDI_MIN(x, y)
#define MCGIDI_SWAP(a, b, type)
static const size_type npos
LUPI_HOST_DEVICE int compare(size_type pos, size_type len, const String &str) const
LUPI_HOST_DEVICE bool operator==(const char *) const
LUPI_HOST_DEVICE String & append(const char *str, size_type n)
Append n characters of a string.
LUPI_HOST_DEVICE String & erase(size_type pos, size_type len)
erase len characters at position pos
LUPI_HOST_DEVICE String & operator+=(const String &)
LUPI_HOST_DEVICE void clear()
LUPI_HOST_DEVICE char & at(const size_type i)
LUPI_HOST_DEVICE void swap(String &)
swap contents
LUPI_HOST_DEVICE String & operator=(const char *)
LUPI_HOST_DEVICE String substr(const size_type pos, size_type length) const
LUPI_HOST_DEVICE void resize(size_type n, char **address=nullptr)
LUPI_HOST_DEVICE size_type size() const
size without terminating NUL
LUPI_HOST_DEVICE const char * c_str() const
raw data
LUPI_HOST_DEVICE String()
LUPI_HOST_DEVICE void reserve(size_type n, char **address=nullptr)
LUPI_HOST_DEVICE void clearMemory()
LUPI_HOST_DEVICE ~String()
LUPI_HOST_DEVICE void push_back(char)
void free(voidpf ptr)
voidp malloc(uInt size)
Simple C++ string class, useful as replacement for std::string if this cannot be used,...
Definition MCGIDI.hpp:43
LUPI_HOST_DEVICE int MCGIDI_strcmp(const char *p1, const char *p2)
LUPI_HOST_DEVICE size_t MCGIDI_strlen(const char *str)
LUPI_HOST_DEVICE String operator+(const String &lhs, const String &rhs)
LUPI_HOST_DEVICE void MCGIDI_memmove(char *dest, const char *src, size_t n)
LUPI_HOST_DEVICE bool operator<(const String &, const String &)
LUPI_HOST_DEVICE int MCGIDI_strncmp(const char *s1, const char *s2, size_t n)