Arcane  4.2.1.0
Developer documentation
Loading...
Searching...
No Matches
StringImpl.cc
1// -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
2//-----------------------------------------------------------------------------
3// Copyright 2000-2026 CEA (www.cea.fr) IFPEN (www.ifpenergiesnouvelles.com)
4// See the top-level COPYRIGHT file for details.
5// SPDX-License-Identifier: Apache-2.0
6//-----------------------------------------------------------------------------
7/*---------------------------------------------------------------------------*/
8/* StringImpl.cc (C) 2000-2026 */
9/* */
10/* Implementation of a UTF-8 or UTF-16 character string. */
11/*---------------------------------------------------------------------------*/
12/*---------------------------------------------------------------------------*/
13
14#include "arccore/base/internal/StringImpl.h"
15#include "arccore/base/BasicTranscoder.h"
16#include "arccore/base/CStringUtils.h"
17#include "arccore/base/StringView.h"
18
19#include <cstring>
20#include <iostream>
21
22//#define ARCCORE_DEBUG_UNISTRING
23
24/*---------------------------------------------------------------------------*/
25/*---------------------------------------------------------------------------*/
26
27namespace Arcane
28{
29
30/*---------------------------------------------------------------------------*/
31/*---------------------------------------------------------------------------*/
32
33bool global_arccore_debug_string = false;
34
35namespace
36{
37 const char* const global_empty_string = "";
38}
39
40/*---------------------------------------------------------------------------*/
41/*---------------------------------------------------------------------------*/
42
43class StringException
44: public std::exception
45{
46 public:
47
48 StringException(const char* where)
49 : m_where(where)
50 {}
51 ~StringException() ARCCORE_NOEXCEPT {}
52 virtual const char* what() const ARCCORE_NOEXCEPT
53 {
54 return m_where;
55 }
56
57 private:
58
59 const char* m_where;
60};
61
62/*---------------------------------------------------------------------------*/
63/*---------------------------------------------------------------------------*/
64
65#ifdef ARCCORE_DEBUG_UNISTRING
66static void
67_badStringImplReference(StringImpl* ptr)
68{
69 cerr << "** FATAL: Trying to use deleted StringImpl " << ptr << '\n';
70}
71#endif
72
73inline void StringImpl::
74_checkReference()
75{
76#ifdef ARCCORE_DEBUG_UNISTRING
77 if (m_nb_ref.value() <= 0) {
78 _badStringImplReference(this);
79 }
80#endif
81}
82
83/*---------------------------------------------------------------------------*/
84/*---------------------------------------------------------------------------*/
85
86inline void StringImpl::
87_finalizeUtf8Creation()
88{
89 m_flags |= eValidUtf8;
90 // \a m_utf8_array must always have a null terminator.
91 if (m_utf8_array.empty())
92 m_utf8_array.add('\0');
93 else if (m_utf8_array.back() != '\0')
94 m_utf8_array.add('\0');
95}
96
97/*---------------------------------------------------------------------------*/
98/*---------------------------------------------------------------------------*/
99
100inline void StringImpl::
101_initFromSpan(Span<const Byte> bytes)
102{
103 m_utf8_array = bytes;
104 _finalizeUtf8Creation();
105}
106
107/*---------------------------------------------------------------------------*/
108/*---------------------------------------------------------------------------*/
109
110StringImpl::
111StringImpl(std::string_view str)
112: m_nb_ref(0)
113, m_flags(0)
114{
115 auto b = reinterpret_cast<const Byte*>(str.data());
116 _initFromSpan(Span<const Byte>(b, str.size()));
117}
118
119/*---------------------------------------------------------------------------*/
120/*---------------------------------------------------------------------------*/
121
122StringImpl::
123StringImpl(Span<const UChar> uchars)
124: m_nb_ref(0)
125, m_flags(0)
126{
127 _setUtf16(uchars);
128 m_flags = eValidUtf16;
129}
130
131/*---------------------------------------------------------------------------*/
132/*---------------------------------------------------------------------------*/
133
134StringImpl::
135StringImpl(const StringImpl& str)
136: m_nb_ref(0)
137, m_flags(str.m_flags)
138, m_utf16_array(str.m_utf16_array)
139, m_utf8_array(str.m_utf8_array)
140{
141}
142
143/*---------------------------------------------------------------------------*/
144/*---------------------------------------------------------------------------*/
145
146StringImpl::
147StringImpl(Span<const Byte> bytes)
148: m_nb_ref(0)
149, m_flags(0)
150{
151 _initFromSpan(bytes);
152}
153
154/*---------------------------------------------------------------------------*/
155/*---------------------------------------------------------------------------*/
156
157StringImpl::
158StringImpl()
159: m_nb_ref(0)
160, m_flags(0)
161{
162}
163
164/*---------------------------------------------------------------------------*/
165/*---------------------------------------------------------------------------*/
166
168bytes()
169{
171 Int64 size = x.size();
172 if (size > 0)
173 return { x.data(), size - 1 };
174 // Should not normally happen, but if it does, we return
175 // a view of the empty string because this method guarantees a
176 // null terminator at the end.
177 // NOTE: No exception is thrown because this method is used in
178 // outputs via operator<< and can be used notably in
179 // destructors of objects.
180 std::cerr << "INTERNAL ERROR: Null size in StringImpl::bytes()";
181 return { reinterpret_cast<const Byte*>(global_empty_string), 0 };
182}
183
184/*---------------------------------------------------------------------------*/
185/*---------------------------------------------------------------------------*/
186
187std::string_view StringImpl::
188toStdStringView()
189{
191 return std::string_view(reinterpret_cast<const char*>(x.data()), x.size());
192}
193
194/*---------------------------------------------------------------------------*/
195/*---------------------------------------------------------------------------*/
196
197StringView StringImpl::
198view()
199{
200 return StringView(bytes());
201}
202
203/*---------------------------------------------------------------------------*/
204/*---------------------------------------------------------------------------*/
205
206void StringImpl::
207addReference()
208{
209 ++m_nb_ref;
210 _checkReference();
211}
212
213/*---------------------------------------------------------------------------*/
214/*---------------------------------------------------------------------------*/
215
216void StringImpl::
217removeReference()
218{
219 _checkReference();
220 Int32 r = --m_nb_ref;
221#ifndef ARCCORE_DEBUG_UNISTRING
222 if (r == 0)
223 delete this;
224#endif
225}
226
227/*---------------------------------------------------------------------------*/
228/*---------------------------------------------------------------------------*/
229
230ConstArrayView<UChar> StringImpl::
231utf16()
232{
233 _checkReference();
234 _createUtf16();
235 return m_utf16_array.view();
236}
237
238/*---------------------------------------------------------------------------*/
239/*---------------------------------------------------------------------------*/
240
242largeUtf8()
243{
244 _checkReference();
245 _createUtf8();
246 return m_utf8_array.view();
247}
248
249/*---------------------------------------------------------------------------*/
250/*---------------------------------------------------------------------------*/
251
252bool StringImpl::
253isEqual(StringImpl* str)
254{
255 _checkReference();
256 _createUtf8();
257 Span<const Byte> ref_array = str->largeUtf8();
258 bool v = CStringUtils::isEqual((const char*)ref_array.data(), (const char*)m_utf8_array.data());
259 return v;
260}
261
262/*---------------------------------------------------------------------------*/
263/*---------------------------------------------------------------------------*/
264
265bool StringImpl::
266isLessThan(StringImpl* str)
267{
268 _checkReference();
269 _createUtf8();
270 if (m_flags & eValidUtf8) {
271 Span<const Byte> ref_array = str->largeUtf8();
272 bool v = CStringUtils::isLess((const char*)m_utf8_array.data(), (const char*)ref_array.data());
273 return v;
274 }
275 ARCCORE_ASSERT((0), ("InternalError in StringImpl::isEqual()"));
276 return true;
277}
278
279/*---------------------------------------------------------------------------*/
280/*---------------------------------------------------------------------------*/
281
282bool StringImpl::
283isEqual(StringView str)
284{
285 _checkReference();
286 _createUtf8();
287 return str.toStdStringView() == toStdStringView();
288}
289
290/*---------------------------------------------------------------------------*/
291/*---------------------------------------------------------------------------*/
292
293bool StringImpl::
294isLessThan(StringView str)
295{
296 _checkReference();
297 _createUtf8();
298 return toStdStringView() < str.toStdStringView();
299}
300
301/*---------------------------------------------------------------------------*/
302/*---------------------------------------------------------------------------*/
303
304StringImpl* StringImpl::
305clone()
306{
307 _checkReference();
308 _createUtf8();
309 StringImpl* n = new StringImpl(*this);
310 return n;
311}
312
313/*---------------------------------------------------------------------------*/
314/*---------------------------------------------------------------------------*/
315
316bool StringImpl::
317empty()
318{
319 _checkReference();
320 if (m_flags & eValidUtf8) {
321 ARCCORE_ASSERT((!m_utf8_array.empty()), ("Not 0 terminated utf8 encoding"));
322 return m_utf8_array.size() <= 1; // Counts the terminal 0
323 }
324 if (m_flags & eValidUtf16) {
325 ARCCORE_ASSERT((!m_utf16_array.empty()), ("Not 0 terminated utf16 encoding"));
326 return m_utf16_array.size() <= 1; // Counts the terminal 0
327 }
328 ARCCORE_ASSERT((0), ("InternalError in StringImpl::empty()"));
329 return false;
330}
331
332/*---------------------------------------------------------------------------*/
333/*---------------------------------------------------------------------------*/
334
335StringImpl* StringImpl::
336append(StringImpl* str)
337{
338 _checkReference();
339 _createUtf8();
340 Span<const Byte> ref_str = str->largeUtf8();
341 _appendUtf8(ref_str);
342 return this;
343}
344
345/*---------------------------------------------------------------------------*/
346/*---------------------------------------------------------------------------*/
347
348StringImpl* StringImpl::
349append(StringView str)
350{
351 Span<const Byte> str_bytes = str.bytes();
352 if (!str_bytes.data())
353 return this;
354
355 _checkReference();
356 _createUtf8();
357
358 _appendUtf8(Span<const Byte>(str_bytes.data(), str_bytes.size() + 1));
359 ;
360 return this;
361}
362
363/*---------------------------------------------------------------------------*/
364/*---------------------------------------------------------------------------*/
365
366void StringImpl::
367_appendUtf8(Span<const Byte> ref_str)
368{
369 Int64 ref_size = ref_str.size();
370 Int64 utf8_size = m_utf8_array.size();
371 Int64 current_size = utf8_size - 1;
372
373 ARCCORE_ASSERT((ref_size > 0), ("Bad ref_size"));
374 ARCCORE_ASSERT((utf8_size > 0), ("Bad utf8_size"));
375 ARCCORE_ASSERT((ref_str[ref_size - 1] == 0), ("Bad ref null terminal"));
376 ARCCORE_ASSERT((m_utf8_array[utf8_size - 1] == 0), ("Bad ref null terminal"));
377
378 m_utf8_array.resize(current_size + ref_size);
379 std::memcpy(&m_utf8_array[current_size], ref_str.data(), ref_size);
380
381 m_flags |= eValidUtf8;
382 _invalidateUtf16();
383}
384
385/*---------------------------------------------------------------------------*/
386/*---------------------------------------------------------------------------*/
387
388StringImpl* StringImpl::
389replaceWhiteSpace()
390{
391 _createUtf8();
392 _invalidateUtf16();
393 Impl::BasicTranscoder::replaceWS(m_utf8_array);
394 return this;
395}
396
397/*---------------------------------------------------------------------------*/
398/*---------------------------------------------------------------------------*/
399
400StringImpl* StringImpl::
401collapseWhiteSpace()
402{
403 _createUtf8();
404 _invalidateUtf16();
405 Impl::BasicTranscoder::collapseWS(m_utf8_array);
406 return this;
407}
408
409/*---------------------------------------------------------------------------*/
410/*---------------------------------------------------------------------------*/
411
412StringImpl* StringImpl::
413toUpper()
414{
415 _createUtf8();
416 _invalidateUtf16();
417 Impl::BasicTranscoder::upperCase(m_utf8_array);
418 return this;
419}
420
421/*---------------------------------------------------------------------------*/
422/*---------------------------------------------------------------------------*/
423
424StringImpl* StringImpl::
425toLower()
426{
427 _createUtf8();
428 _invalidateUtf16();
429 Impl::BasicTranscoder::lowerCase(m_utf8_array);
430 return this;
431}
432
433/*---------------------------------------------------------------------------*/
434/*---------------------------------------------------------------------------*/
435
436StringImpl* StringImpl::
437substring(StringImpl* str, Int64 pos, Int64 len)
438{
439 StringImpl* s = new StringImpl();
440 Impl::BasicTranscoder::substring(s->m_utf8_array, str->largeUtf8(), pos, len);
441 s->m_flags |= eValidUtf8;
442 return s;
443}
444
445/*---------------------------------------------------------------------------*/
446/*---------------------------------------------------------------------------*/
447
448void StringImpl::
449_createUtf16()
450{
451 if (m_flags & eValidUtf16)
452 return;
453
454 if (m_flags & eValidUtf8) {
455 ARCCORE_ASSERT(m_utf16_array.empty(), ("Not empty utf16_array"));
456 Impl::BasicTranscoder::transcodeFromUtf8ToUtf16(m_utf8_array, m_utf16_array);
457 m_flags |= eValidUtf16;
458 return;
459 }
460
461 ARCCORE_ASSERT((0), ("InternalError in StringImpl::_createUtf16()"));
462}
463
464/*---------------------------------------------------------------------------*/
465/*---------------------------------------------------------------------------*/
466
467void StringImpl::
468_createUtf8()
469{
470 if (m_flags & eValidUtf8)
471 return;
472
473 if (m_flags & eValidUtf16) {
474 ARCCORE_ASSERT(m_utf8_array.empty(), ("Not empty utf8_array"));
475 Impl::BasicTranscoder::transcodeFromUtf16ToUtf8(m_utf16_array, m_utf8_array);
476 _finalizeUtf8Creation();
477 return;
478 }
479
480 ARCCORE_ASSERT((0), ("InternalError in StringImpl::_createUtf16()"));
481}
482
483/*---------------------------------------------------------------------------*/
484/*---------------------------------------------------------------------------*/
485
486void StringImpl::
487_setUtf16(Span<const UChar> src)
488{
489 m_utf16_array = src;
490 if (m_utf16_array.empty())
491 m_utf16_array.add(0);
492 else if (m_utf16_array.back() != '\0')
493 m_utf16_array.add(0);
494}
495
496/*---------------------------------------------------------------------------*/
497/*---------------------------------------------------------------------------*/
498
499void StringImpl::
500_invalidateUtf16()
501{
502 m_flags &= ~eValidUtf16;
503 m_utf16_array.clear();
504}
505
506/*---------------------------------------------------------------------------*/
507/*---------------------------------------------------------------------------*/
508
509void StringImpl::
510_invalidateUtf8()
511{
512 m_flags &= ~eValidUtf8;
513 m_utf8_array.clear();
514}
515
516/*---------------------------------------------------------------------------*/
517/*---------------------------------------------------------------------------*/
518
519void StringImpl::
520_printStrUtf16(std::ostream& o, Span<const UChar> str)
521{
522 Int64 buf_size = str.size();
523 o << "(bufsize=" << buf_size
524 << " begin=" << str.data() << " - ";
525 for (Int64 i = 0; i < buf_size; ++i)
526 o << (int)str[i] << ' ';
527 o << ")";
528}
529
530/*---------------------------------------------------------------------------*/
531/*---------------------------------------------------------------------------*/
532
533void StringImpl::
534_printStrUtf8(std::ostream& o, Span<const Byte> str)
535{
536 Int64 buf_size = str.size();
537 o << "(bufsize=" << buf_size << " - ";
538 for (Int64 i = 0; i < buf_size; ++i)
539 o << (int)str[i] << ' ';
540 o << ")";
541}
542
543/*---------------------------------------------------------------------------*/
544/*---------------------------------------------------------------------------*/
545
546void StringImpl::
547internalDump(std::ostream& ostr)
548{
549 ostr << "(utf8=valid=" << ((m_flags & eValidUtf8) != 0)
550 << ",len=" << m_utf8_array.size() << ",val=";
551 _printStrUtf8(ostr, m_utf8_array);
552 ostr << ")";
553
554 ostr << "(utf16=valid=" << ((m_flags & eValidUtf16) != 0)
555 << ",len=" << m_utf16_array.size() << ",val=";
556 _printStrUtf16(ostr, m_utf16_array);
557 ostr << ")";
558}
559
560/*---------------------------------------------------------------------------*/
561/*---------------------------------------------------------------------------*/
562
563} // namespace Arcane
564
565/*---------------------------------------------------------------------------*/
566/*---------------------------------------------------------------------------*/
Constant view of an array of type T.
static void transcodeFromUtf16ToUtf8(Span< const UChar > utf16, CoreArray< Byte > &utf8)
Translates from UTF16 to UTF8.
constexpr __host__ __device__ pointer data() const noexcept
Pointer to the start of the view.
Definition Span.h:537
constexpr __host__ __device__ SizeType size() const noexcept
Returns the size of the array.
Definition Span.h:325
View of an array of elements of type T.
Definition Span.h:633
Span< const Byte > bytes()
same as largeUtf8() but WITHOUT the null terminator
Span< const Byte > largeUtf8()
View of the UTF-8 encoding WITH null terminator.
View of a UTF-8 character string.
Definition StringView.h:44
bool isLess(const char *s1, const char *s2)
Returns true if s1 is less than (alphabetical order) s2 , false otherwise.
bool isEqual(const char *s1, const char *s2)
Returns true if s1 and s2 are identical, false otherwise.
-- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature --
std::int64_t Int64
Signed integer type of 64 bits.
unsigned char Byte
Type of a byte.
Definition BaseTypes.h:42
std::int32_t Int32
Signed integer type of 32 bits.