ALib C++ Framework
by
Library Version: 2511 R0
Documentation generated by doxygen
Loading...
Searching...
No Matches
tastring.inl
Go to the documentation of this file.
1//==================================================================================================
2/// \file
3/// This header-file is part of module \alib_strings of the \aliblong.
4///
5/// \emoji :copyright: 2013-2025 A-Worx GmbH, Germany.
6/// Published under #"mainpage_license".
7//==================================================================================================
8ALIB_EXPORT namespace alib { namespace strings {
9
10//==================================================================================================
11/// This is a type-traits functor that allows making custom types "appendable" to objects of
12/// type \b AString.
13///
14/// Specializations of this struct have to implement
15/// #"AppendableTraits::operator()(TAString<TChar>&,const TAppendable&);operator()",
16/// which is invoked by the method #"TAString::Append(const TAppendable&)", when an instance of
17/// the type in question is passed.
18///
19/// For user-defined string-types that get adopted to \alib string system using a specialization of
20/// struct #"ArrayTraits", no specialization of this functor is needed, because
21/// the method \b AString::Append will accept such types likewise.
22///
23/// \note
24/// This struct is called a "functor" because its single member is
25/// #"AppendableTraits::operator()(TAString<TChar>&,const TAppendable&);operator()".
26/// This is different to other type traits defined by \alib, which demand to implement
27/// one or more static methods with specializations. As
28/// #"AppendableTraits::operator()(TAString<TChar>&,const TAppendable&);operator()"
29/// must not be static, the internal call to this operator is done by creating a temporary object
30/// of this "functor struct" and calling the operator on that.<br>
31/// The result in respect to the generated code is with both approaches the same. Using a functor
32/// here, is just a design decision.
33///
34/// \see
35/// For details consult chapter #"alib_strings_assembly_ttostring" of the Programmer's Manual
36/// of module \alib_strings.
37///
38/// \see
39/// The documentation of built-in specializations for \alib types are collected in
40/// sub-namespace #"alib::strings::APPENDABLES".
41///
42/// # Reference Documentation #
43/// @tparam TAppendable The type that should be made compatible with method
44/// #"Append(const TAppendable&)".
45/// @tparam TChar The character type of the target \b AString.
46/// @tparam TAllocator The allocator type of the target \b AString.
47//==================================================================================================
48template< typename TAppendable,
49 typename TChar,
50 typename TAllocator >
52{
53 #if DOXYGEN
54 //==============================================================================================
55 /// This operator is invoked on a temporary object of this type by
56 /// #"TAString::Append(const TAppendable&)", when an object of type
57 /// \p{TAppendable} is passed.
58 ///
59 /// Usually, specializations of this operator append a string representation of \p{src} to
60 /// \p{target}. Special "appendable types" might modify \p{target} in other, arbitrary ways.
61 ///
62 /// @param target The target string.
63 /// @param src The source object.
64 //==============================================================================================
65 void operator()( TAString<TChar>& target, const TAppendable& src );
66
67 #endif // doxygen
68};
69
70/// This concept tests whether for type \p{T}, a specialization of the type trait
71/// #"strings::AppendableTraits;*" exists, which has a valid call-<c>operator()</c> that accepts
72/// a target string and a \c const reference to an instance of \p{T}.
73template<typename T, typename TChar, typename TAllocator>
74concept IsAppendable = requires(TAString<TChar, TAllocator>& target, const T& value) {
75 { AppendableTraits<T, TChar, TAllocator>()(target, value) } -> std::same_as<void>;
76};
77
78//==================================================================================================
79/// Specializes base class #"TString;String" to implement mutable character strings
80/// using writable and extendable buffer memory.
81///
82/// <b>Construction:</b><br>
83/// Construction is described in Programmer's Manual, section
84/// #"alib_strings_cc_construction_astring".
85///
86/// <b>Buffer Management:</b><br>
87/// There are two possible types of buffers:
88/// - <b>Internal buffers</b><br>
89/// This is the standard case and implements a buffer that is allocated and freed using
90/// the allocator type-traits given with template parameter \p{TAllocator}.
91/// Allocation size eventually grows over time and never shrinks, unless explicitly demanded by
92/// the using code. Those buffers are deleted when objects of this type are deleted.
93/// - <b>External buffers</b><br>
94/// Set with overloaded method #".SetBuffer(TChar*, integer, integer, lang::Responsibility)".
95/// This class does not manage external buffers. However, if their capacity is exceeded, they
96/// will automatically become replaced by an internal buffer.
97/// Such a replacement, by default, #"alib_mod_assert;raises a warning" with debug-builds.
98/// In situations that buffer replacement is accepted, warnings can be disabled with the method
99/// #"DbgDisableBufferReplacementWarning".
100///
101/// The method #".SetBuffer(TChar*)" provides a boolean parameter
102/// that also allows letting an object of this class take control of a buffer provided from outside.
103/// In this case, the buffer is considered an internal buffer, hence allocated using the same
104/// allocator traits (and if not heap allocation, then also the same allocator instance!), rather
105/// than an external one.
106///
107/// The default constructor creates a \e nulled \b AString which does not dispose of an allocated
108/// buffer, yet. Destruction will free the currently allocated buffer - if internal.
109///
110/// \anchor alib_ns_strings_astring_copymove
111/// <b>Copy/Move Constructor and Assignment</b><br>
112/// The class provides the minimum equipment to be usable as member type of standard containers like
113/// \c std::vector. This includes a copy and move constructor as well as a copy assignment operator.
114/// Nevertheless, this class is not guaranteed to perform well when used with container types
115/// and such use should be avoided if possible.<br>
116/// Outside of containers, the automatic C++ copy and move construction semantics should be avoided.
117/// For example, the move constructor grabs the buffer of a given movable \b %AString, as long
118/// as this given object does not use an external buffer. If it does, the contents of the
119/// movable object is copied like in the copy constructor.
120///
121/// Consequently, objects of this class should have a well defined scope and not be copied and moved like
122/// the lightweight string-types. A move assignment operator is not given. The rationale for this
123/// design decision is that usually, a "more temporary" string would be assigned to a "less temporary"
124/// one. In this case, it would not be helpful to replace the already allocated storage of the
125/// assignee.
126///
127/// By the same token, besides the copy assignment, no other assignment operators are given. Instead,
128/// method #Reset(const TAppendable&) is to be used to clear the existing buffer and insert new
129/// string content. This helps to distinguish \b AString variables from those of the lightweight
130/// string-types as shown in the following snippet:
131///
132/// string1= "Hello"; // Can't be an AString. Rather String, Substring or CString
133/// string2.Reset("World"); // Obviously an AString. The given string is copied!
134///
135/// \anchor alib_ns_strings_astring_write_access
136/// <b>Writing directly into the Buffer:</b><br>
137/// Parent class #"TString;String" holds its protected field
138/// #"TString::buffer;buffer" in an anonymous C++ union of two pointers,
139/// one typed <em>const char*</em> and the other <em>char*</em>.
140/// This class exposes the non-constant buffer pointer of that union with method #VBuffer.
141/// This allows users of this class to <em>freely</em> operate on the buffer.
142/// Of course, it is up to the programmer that the integrity of the instance is kept intact and
143/// that also the #Capacity of the buffer must not be exceeded.
144/// In the case that the string's length is changed, method #SetLength needs to be
145/// used to notify such change with the \b AString object. The latter of course is invokable only
146/// on mutable objects, while method #VBuffer is declared \c const.
147///
148/// In addition to this, a bunch of methods allow the modification of single characters.
149/// #operator[] is extended by a non-const version that returns a reference to a character instead
150/// of just the character value.
151///
152/// \anchor alib_ns_strings_astring_appendto
153/// <b>Appending Objects to AStrings:</b><br>
154/// This class is used to provide a global concept of having a sort of <b>"ToString"</b> method
155/// with any C++ class. For this, the class provides method #Append, which uses template
156/// meta programming to accept types with a corresponding specialization of functor
157/// #"strings::AppendableTraits;*".
158///
159/// The concept is described in detail with chapter #"alib_strings_assembly_ttostring"
160/// of this module's #"alib_mod_strings;Programmer's Manual".
161///
162///
163/// @tparam TChar The character type.
164/// Alias names for specializations of this class using character types
165/// #"characters::character", #"characters::nchar", #"characters::wchar",
166/// #"characters::xchar", #"characters::complementChar" and
167/// #"characters::strangeChar" are provided in namespace #alib with type ,
168/// definitions #"AString", #"NAString" #"WAString", #"XAString",
169/// #"ComplementAString" and #"StrangeAString".
170/// @tparam TAllocator The #"lang::Allocator;allocator type" to use.
171//==================================================================================================
172template<typename TChar, typename TAllocator= lang::HeapAllocator>
174class TAString : public TString<TChar>
175 , public lang::AllocatorMember<TAllocator>
176{
177 //################################################################################################
178 // Protected fields
179 //################################################################################################
180 protected:
181 /// The base string-type.
183
184 /// The type of the base class that stores the allocator.
186
187 /// The current size of the buffer excluding the trailing <c>'\0'</c>.
188 /// If no buffer is allocated, this field is \c 0.
189 /// If an external Buffer not managed by this class is used, then the size of that buffer is
190 /// stored as a negative value. Method #Capacity therefore returns the absolute value
191 /// of this field.
193
194 #if ALIB_DEBUG_STRINGS
195 protected:
196 /// Used to check if previous grow request was exactly what is now the length.<br>
197 /// This field is available only if code selection macro #"ALIB_DEBUG_STRINGS"
198 /// is set.
200
201 public:
202 //################################################################################################
203 // Debug Features
204 //################################################################################################
205 /// Checks this object's state. This method is internally invoked with almost
206 /// every other method of this class, but only if the configuration macro
207 /// #"ALIB_DEBUG_STRINGS" is \c true.<br>
208 /// Invocations to this method should be performed using macro
209 /// #"ALIB_STRING_DBG_CHK".<br>
210 ///
211 /// \see
212 /// For (a little) more information see
213 /// #"alib_strings_details_debugging" of this module's
214 /// #"alib_mod_strings;Programmer's Manual"
215 void dbgCheck() const;
216
217 #endif
218
219 protected:
220 /// If \c true, a #"alib_mod_assert;warning is raised" when an external buffer, whose
221 /// life-cycle is not controlled by this instance gets replaced.
222 /// This field exists only with debug-compilations of this class.
223 ///
224 /// \see
225 /// See method #DbgDisableBufferReplacementWarning for more information.
226 #if ALIB_DEBUG
228 #endif
229
230 public:
231 //################################################################################################
232 // Debug Features
233 //################################################################################################
234 /// Used to disable warnings that are by default raised in debug-compilations of
235 /// method #SetBuffer.
236 ///
237 /// \note
238 /// In release-compilations this inline method is empty and will be optimized out.
239 ///
240 /// \see See method #SetBuffer for more information.
243
244 protected:
245 //################################################################################################
246 // Protected Constructors
247 //################################################################################################
248 /// Constructs an \b %AString with the given external buffer and allocator.
249 /// The given buffer's life-cycle is considered to be managed externally.<br>
250 /// This constructor is protected and provided for derived classes that dispose of
251 /// their own buffer.
252 ///
253 /// \note
254 /// Protected access was given to this method also to avoid misunderstandings that this
255 /// constructor is not for providing copyable string data. If the functionality of this
256 /// constructor is needed, it can simply be imitated by
257 /// - default construction and
258 /// - immediate invocation of #SetBuffer(TChar*, integer, integer, lang::Responsibility).
259 ///
260 /// @param pAllocator The allocator to use.
261 /// @param extBuffer The external buffer to use.
262 /// @param extBufferSize The capacity of the given buffer.
263 constexpr
264 explicit TAString( TAllocator& pAllocator, TChar* extBuffer, integer extBufferSize )
265 : base ( extBuffer, 0 )
266 , allocBase ( pAllocator )
267 , capacity (- (extBufferSize - 1))
269 ,debugLastAllocRequest(extBufferSize-1)
270 #endif
271 {}
272
273 /// Constructs an \b %AString with the given external buffer.
274 /// The given buffer's life-cycle is considered to be managed externally.<br>
275 /// This constructor is protected and provided for derived classes that dispose of
276 /// their own buffer.
277 ///
278 /// \note
279 /// Protected access was given to this method also to avoid misunderstandings that this
280 /// constructor is not for providing copyable string data. If the functionality of this
281 /// constructor is needed, it can simply be imitated by
282 /// - default construction and
283 /// - immediate invocation of #SetBuffer(TChar*, integer, integer, lang::Responsibility).
284 ///
285 /// @param extBuffer The external buffer to use.
286 /// @param extBufferSize The capacity of the given buffer.
287 constexpr
288 explicit TAString( TChar* extBuffer, integer extBufferSize )
289 : base( extBuffer, 0 )
290 , capacity (- (extBufferSize - 1))
292 ,debugLastAllocRequest(extBufferSize-1)
293 #endif
294 {}
295
296 public:
297 /// Exposes the allocator type specified by template parameter \p{TAllocator}.
298 using AllocatorType= TAllocator;
299
300 //################################################################################################
301 // Constructors, Destructor and Assignment
302 //################################################################################################
303 /// Constructs an empty, \e nulled \b %AString (does not allocate a buffer).
304 explicit constexpr TAString()
305 : base(nullptr, 0)
306 , capacity(0) {}
307
308 /// Constructs an empty, \e nulled \b %AString (does not allocate a buffer).
309 /// This constructor is to be used with template parameter \p{TAllocator} denoting an
310 /// allocation strategy that includes the need of storing an allocator type in field
311 /// #allocator. For the standard, heap-allocated type #"AString", this constructor is not
312 /// applicable.
313 /// @param pAllocator The allocator to use.
314 explicit constexpr
315 TAString(TAllocator& pAllocator)
316 : base (nullptr, 0)
317 , allocBase(pAllocator)
318 , capacity (0) {}
319
320 /// Copy constructor that allocates memory and copies the contents of the given object.
321 /// @param copy The object to copy.
322 explicit
323 TAString(const TAString& copy)
324 : base(nullptr, 0)
325 , allocBase(copy)
326 , capacity (0)
327 {
329 Append(copy);
330 }
331
332 /// Move constructor.
333 /// See #"alib_ns_strings_astring_copymove;Copy/Move Constructor and Assignment"
334 /// for details.
335 /// @param move The object to move.
336 TAString(TAString&& move) noexcept
337 : allocBase(move) {
338 // given move object has external buffer: we have to copy
339 if ( !move.HasInternalBuffer() ) {
340 base::buffer= nullptr;
341 base::length= 0;
342 capacity= 0;
343 ALIB_DBG( dbgWarnWhenExternalBufferIsReplaced= move.dbgWarnWhenExternalBufferIsReplaced; )
344 Append( move );
345 return;
346 }
347
348 // copy values
349 base::buffer= move.buffer;
350 base::length= move.length;
351 capacity= move.capacity;
352
353 // clean moved object (buffer does not need to be nulled)
354 move.length=
355 move.capacity= 0;
356
357 // in debug mode, more copying and more destructor prevention is needed
358 #if ALIB_DEBUG
359 dbgWarnWhenExternalBufferIsReplaced= move.dbgWarnWhenExternalBufferIsReplaced;
360 #if ALIB_DEBUG_STRINGS
361 debugLastAllocRequest= move.debugLastAllocRequest;
362 move.buffer= nullptr;
363 #endif
364 #endif
365 }
366
367
368 /// Constructs the object and uses #Append to create a string representation of the given
369 /// object.
370 ///
371 /// @tparam TAppendable The type of parameter \p{source} that has a specialization of
372 /// functor #"strings::AppendableTraits;*".
373 /// @param src The source object to append to this string.
374 template <typename TAppendable>
375 explicit
376 TAString (const TAppendable& src )
377 : base(nullptr, 0)
378 , capacity(0) { Append( src ); }
379
380 /// Destructs an \b %AString object. An internally allocated buffer will be deleted.
381 ~TAString() noexcept {
383 if ( HasInternalBuffer() )
384 allocBase::GetAllocator().free( base::vbuffer
386 - 16
387 #endif
388 , size_t(capacity + 1) * sizeof(TChar)
390 + 32* sizeof(TChar)
391 #endif
392 );
393 }
394
395 //######################################### casting back ########################################
396 // Doxygen (V1.15) would create identical entries in its tag-file, so those are not reachable.
397 // On the other hand, it complains if the methods are not doxed. So, we hide them from doxygen.
398 #if DOXYGEN
399 /// Templated \b implicit <c>cast operator</c> constructing an instance of type \p{T} from
400 /// this string instance.
401 ///
402 /// Custom types can be enabled for this operator by specializing the traits-type
403 /// #"ArrayTraits", which is used for both;
404 /// the implementation of the concept, and
405 /// the implementation of this operator itself.
406 ///
407 /// @tparam T The type to implicitly cast this instance to.
408 /// Deduced by the compiler.
409 /// @return A value of type \p{T}.
410 template< typename T>
411 constexpr operator T() const;
412 #else
413 template< typename T>
417 std::remove_cv_t<T> >::value)
418 constexpr operator T() const
420
421
422 template< typename T>
423 requires ( alib::characters::IsExplicitArrayCast <T, TChar>
427 std::remove_cv_t<T> >::value )
428 constexpr explicit operator T() const
430
431 template< typename T>
432 requires ( !alib::characters::IsImplicitArrayCast <T, TChar>
436 std::remove_cv_t<T> >::value )
437 constexpr operator T() const {
438 Terminate();
440 }
441
442 template< typename T>
443 requires ( !alib::characters::IsExplicitArrayCast <T, TChar>
447 std::remove_cv_t<T> >::value )
448 constexpr explicit operator T() const {
449 Terminate();
451 }
452 #endif
453 /// Copy assign operator.
454 /// If the given other \b AString is \e nulled, this object becomes \e nulled. Otherwise,
455 /// this string is cleared and the given other string is appended.
456 ///
457 /// \see
458 /// For details why no other assignment operators exists for this class, note paragraph
459 /// #"alib_ns_strings_astring_copymove;Copy/Move Constructor and Assignment"
460 /// of this class's reference documentation.
461 ///
462 /// @param copy The object to copy the contents from.
463 /// @return \c *this to allow concatenated calls.
465 if ( copy.IsNull() ) {
466 SetNull();
467 return *this;
468 }
469
470 return Reset().Append( copy.Buffer(), copy.Length() );
471 }
472
473 //################################################################################################
474 // Memory allocation and buffer access
475 //################################################################################################
476
477 /// Resizes the buffer to meet exactly the given size.
478 ///
479 /// The following rules apply:
480 /// - The string represented by this instance is copied to the new buffer.
481 /// If this is larger than the new buffer size, the string is cut at the end to fit.
482 /// - If the desired new size is \c 0, then the currently allocated buffer will be disposed
483 /// and the object's state is \e nulled.
484 /// - If the current buffer's life-cycle is managed externally (e.g., was set using
485 /// #SetBuffer(TChar*,integer,integer,lang::Responsibility)
486 /// with parameter \p{responsibility} being \c Responsibility::KeepWithSender), this method
487 /// will replace the buffer by a new one, even if the new requested size is the same as
488 /// the external buffer's size. In other words, the only case when this method does not
489 /// replace the current buffer is when the current buffer's life-cycle is (already)
490 /// internally managed and it has the same size than what is requested.
491 /// - In this C++ version of \alib, the true allocation size is one character larger than
492 /// what is given with parameter \p{newCapacity}.
493 /// This allows method #Terminate to add a termination character without checking
494 /// (and eventually reallocating and copying) an internally managed buffer.
495 ///
496 /// Any method of this class that extends the length of the string will directly or
497 /// indirectly invoke this method, when the current buffer size is not sufficient.
498 /// If a future string length, which is the result of more than one concatenation of data
499 /// to an \b %AString is predictable, then it is advisable to reserve the allocated size
500 /// before performing the planned concatenations, by invoking this method.
501 /// This is to avoid unnecessary allocations and data copy operations.
502 ///
503 /// If an #"SetBuffer(TChar*);external buffer" is set, in debug-compilations a
504 /// #"alib_mod_assert;warning is raised", because usually it
505 /// is not wanted that an external buffer becomes replaced during the growth of a string.<br>
506 /// Such warnings can be switched off using the method #DbgDisableBufferReplacementWarning.
507 /// For example, in some situations it might be taken into account that instances of derived
508 /// type #"TLocalString;LocalString" sometimes may grow more than average and
509 /// in such a case, a heap-allocated buffer replaces a local one. By placing a call
510 /// to method #DbgDisableBufferReplacementWarning, the code explicitly hints to that
511 /// possibility and is well-readable. In release-compilations no warnings are issued
512 /// and method \b %DbgDisableBufferReplacementWarning is optimized out.
513 ///
514 /// @param newCapacity The new capacity of the internal buffer.
515 ALIB_DLL void SetBuffer( integer newCapacity );
516
517 /// This method replaces the current buffer with the one provided.
518 ///
519 /// The following rules apply:
520 /// - If a \c nullptr is provided, the current buffer is released.
521 /// - If the provided buffer is not \c nullptr, its size given with parameter
522 /// \p{extBufferSize} has to be at least \c 1 for providing the space for a termination
523 /// character.
524 /// - After the operation, #Capacity will report \p{extBufferSize} <c>- 1</c>.
525 /// - Optional parameter \p{responsibility} can be used to pass the responsibility for the
526 /// deletion of the buffer to this object.
527 /// - The length of the content provided with parameter \p{extLength} must not exceed
528 /// the value of parameter \p{extBufferSize} \c -1.
529 /// - In no event any data of an existing buffer is copied into the new one. The rationale
530 /// here is that in most use cases, this is not needed. Should this be desired,
531 /// then the contents has to be copied "manually" before invoking this method.
532 ///
533 /// The internal buffer allocation is performed with methods #"Allocator::allocate;*",
534 /// #"Allocator::reallocate;*" and #"Allocator::free;*". The latter two are
535 /// also used on external buffers that are provided with this method in case parameter
536 /// \p{responsibility} is given as \b Responsibility::Transfer, because in this case such
537 /// an externally created buffer is considered to have been allocated using the same
538 /// instance of template type \p{TAllocator}. Consequently, it has to be ensured that the
539 /// given piece of memory is "compatible" in this respect.
540 ///
541 /// @param extBuffer The external buffer to use.
542 /// @param extBufferSize The size of the given buffer.
543 /// @param extLength The length of any content located in the given buffer that should
544 /// be used.
545 /// Has to be smaller or equal to extBufferSize -1 to preserve
546 /// space for a trailing '\0'.
547 /// @param responsibility If \c Responsibility::Transfer, the given buffer will be deleted
548 /// by this object when a new buffer is set or it is deleted itself.
549 /// Defaults to \c Responsibility::KeepWithSender which denotes that
550 /// the life-cycle of the given external buffer is managed elsewhere.
552 void SetBuffer( TChar* extBuffer,
553 integer extBufferSize,
554 integer extLength = 0,
556
557 /// Ensures that the capacity of the internal buffer meets or exceeds the actual length
558 /// plus the given growth value.
559 ///
560 /// @param spaceNeeded The desired growth of the length of the string represented by this.
561 void EnsureRemainingCapacity( integer spaceNeeded ) {
562 #if ALIB_DEBUG_STRINGS
564 "STRINGS", "Previous allocation request was too short: {} >= {}",
566 #endif
567
568 if ( Capacity() < base::length + spaceNeeded )
569 GrowBufferAtLeastBy( spaceNeeded );
570
571 #if ALIB_DEBUG_STRINGS
572 debugLastAllocRequest= base::length + spaceNeeded;
573 #endif
574 }
575
576 /// Increases the allocation size by either 50% of the current capacity or by the value
577 /// provided, whichever is higher.
578 ///
579 /// @param minimumGrowth The desired minimum growth of length.
581 void GrowBufferAtLeastBy( integer minimumGrowth );
582
583 /// The size of the internal buffer (this is excluding the trailing \c '\0' character)
584 /// which is reserved to terminate the string if needed.
585 /// In other words, the internal memory available is the size returned here plus one.
586 ///
587 /// @return The size of the allocated buffer.
588 integer Capacity() const { return capacity >= 0 ? capacity : -capacity; }
589
590 /// Returns \c true, if the buffer was allocated by this class itself. If the buffer was
591 /// set using #SetBuffer(TChar*,integer,integer,lang::Responsibility) with parameter
592 /// \p{responsibility} given as \c Responsibility::KeepWithSender (and not automatically
593 /// replaced, yet, because it became too small) then \c false is returned.
594 /// \note Derived class
595 /// #"TLocalString;LocalString" will report \c false here.
596 /// This sounds wrong on the first sight, as the buffer is allocated by an 'internal'
597 /// member. But from an AString's perspective, class <em>LocalString</em> works on
598 /// an 'external' buffer.
599 ///
600 /// @return \c true if the buffer is internally allocated and will be deleted with the
601 /// deletion of this object. False otherwise.
602 bool HasInternalBuffer() const { return capacity > 0; }
603
604 /// Invokes #"SetBuffer(integer);SetBuffer(0)".
605 void SetNull() { SetBuffer( 0 ); }
606
607 /// Writes a zero-termination character <c>'\0'</c> to the end of the used part of the
608 /// internal string buffer and returns the pointer to the start.
609 /// In other words, this function returns the represented string as a \e "cstring".
610 ///
611 /// One implementation detail of this class is that it always ensures that the internal
612 /// buffer's capacity is sufficient for a termination character. This way, using this
613 /// method will not reallocate the string and the method can be invoked on constant objects.
614 ///
615 /// The explicit invocation of this method can often be omitted, due to the availability
616 /// of the definition of an implicit cast operator to <c>const TChar</c>, which inlines
617 /// a call to this method.
618 ///
619 /// @return The pointer to the zero-terminated character buffer.
620 constexpr const TChar* Terminate() const {
621 if ( base::vbuffer )
622 base::vbuffer[ base::length ]= '\0';
623
624 return base::buffer;
625 }
626
627 //################################################################################################
628 // Writable Buffer Access
629 //################################################################################################
630
631 /// The internal buffer character array provided as non constant character pointer.
632 /// \see Chapter
633 /// #"alib_ns_strings_astring_write_access;Write Access to the Buffer"
634 /// of the reference documentation of this class.
635 ///
636 /// @return The internal buffer array.
637 TChar* VBuffer() const { return base::vbuffer; }
638
639 /// Sets the character at the given index. A range check is performed. If this fails,
640 /// nothing is done.
641 ///
642 /// \note
643 /// The C++ language would allow to declare this method \c const, as it does not
644 /// manipulate the data of the class itself but a character in the buffer pointer.<br>
645 /// In exceptional cases, to manipulate the contents of <em>const %AString</em>, use
646 /// method VBuffer() like in the following sample:
647 /// \snippet "DOX_STRINGS.cpp" DOX_ASTRING_MODIFY_CONST_BUFFER
648 /// <p>
649 ///
650 /// @tparam TCheck Performs a range check on the given index and a check for illegal setting
651 /// of termination character '\0' anywhere else but at idx==length.
652 /// @param idx The index of the character to write.
653 /// @param c The character to write.
654 template<typename TCheck =CHK>
655 void SetCharAt( integer idx, TChar c ) {
656 ALIB_ASSERT_ERROR( c != '\0' || idx==base::length,
657 "STRINGS", "Can't write character '\0'" )
658 if constexpr ( TCheck::value ) {
659 if( (idx >= 0 && idx < base::length )
660 || ( c =='\0' && idx == base::length ) )
661 *(base::vbuffer + idx )= c;
662 } else {
663 ALIB_ASSERT_ERROR( idx >= 0 && idx < base::length, "STRINGS",
664 "Non-checking invocation: ","Index out of range: 0 <= {} < {}", idx, base::length )
665 *(base::vbuffer + idx )= c;
666 } }
667
668 /// Provides read/write access to single characters. Overrides #"TString::operator[]"
669 /// returning a reference to
670 /// a \p{TChar} value, which allows changing the character stored.
671 ///
672 /// \attention
673 /// No parameter check is performed (other than an assertions in debug-compilation of
674 /// \alib). See #"TString::operator[];String::operator[]" for details.
675 ///
676 /// @param idx The index of the character within this object's buffer.
677 /// @returns If the character contained (or, if lvalue the one to set).
678 TChar& operator[] (integer idx) {
679 ALIB_ASSERT_ERROR( idx >= 0 && idx < base::length , "STRINGS",
680 "Index out of range: 0 <= {} < {}", idx, base::length )
681 return base::vbuffer[idx];
682 }
683
684 using base::operator[];
685
686 /// Sets a new length for this string.
687 ///
688 /// In debug-compilations, given \p{newLength} is checked to be positive and smaller or
689 /// equal to the buffer's capacity.
690 ///
691 /// In the (frequent) situation that the given length is shorter (or equal) to the current
692 /// length, for better readability, the use of the method #ShortenTo instead of this method is
693 /// recommended. Extending the length of the string should be done only in rare cases,
694 /// when the string buffer was modified "externally" after retrieving it using
695 /// #VBuffer.
696 ///
697 /// @param newLength The new length of the \b %AString. Must be between 0 and
698 /// #Capacity.
699 void SetLength( integer newLength ) {
700 ALIB_ASSERT_ERROR( newLength >= 0 ,
701 "STRINGS", "Negative AString length {} requested", newLength )
702 ALIB_ASSERT_ERROR( newLength <= Capacity(),
703 "STRINGS", "Requested AString length {} exceeds capacity {}",
704 newLength, Capacity() )
705 base::length= newLength;
707 }
708
709 /// Searches termination character <c>'\0'</c> and sets the corresponding length of the
710 /// string.
711 /// In debug-compilations, the detected length is smaller or equal to the buffer's capacity.
712 ///
713 /// This method may be used in situations, where the strings's buffer is
714 /// exposed to other libraries (for example, many operating system calls), which internally
715 /// fill a given character buffer, zero-terminate it, but just do not return it's length.
716 /// @param offset The offset for searching the termination byte \c '\0'.
717 /// Defaults to \c 0. Using this parameter allows faster detection in the case
718 /// a minimum length is known.
719 /// @return Returns the new length of this string for convenience.
721 base::length= characters::Length( base::Buffer() + offset ) + offset;
723 "STRINGS", "Detected AString length {} exceeds capacity {}",
726 return base::length;
727 }
728
729 /// Sets the length of the string to a shorter (or equal) value.
730 ///
731 /// In release-compilations, this method has the same simple inline implementation as
732 /// #SetLength, it just sets the internal field \b length to the given value.
733 /// The reason for the method's existence is primarily readability of the code: The name
734 /// expresses that the given \p{newLength} is shorter than the current length.
735 ///
736 /// In debug-compilations, an #"alib_mod_assert;error is raised" if the length provided
737 /// is longer than the current length. An equal value is accepted.
738 ///
739 /// In situations when it is sure that a new length is equal or shorter to the existing
740 /// one, the use of this method is recommended over the use of #SetLength.
741 /// This is especially true for the frequent use case where a "base string" should be
742 /// restored after one or more concatenations had been performed.
743 ///
744 /// @param newLength The new length of this \b %AString. Must be between 0 and the current
745 /// length.
746 /// @return \c *this to allow concatenated calls.
747 TAString& ShortenTo( integer newLength ) {
748 ALIB_ASSERT_ERROR( newLength >= 0,
749 "STRINGS", "Negative AString length {} requested", newLength )
750 ALIB_ASSERT_ERROR( newLength <= base::length,
751 "STRINGS", "Increase from {} to {} of AString length requested",
752 base::Length(), newLength )
753 #if ALIB_DEBUG_STRINGS
754 // Avoid analyser warnings with UT when above assertions are switched off.
755 if ( newLength >= 0 && newLength < base::length )
756 #endif
757 base::length= newLength;
759 return *this;
760 }
761
762 /// Same as #ShortenTo, but accepts a value interpreted as the difference to the current length.
763 /// @param charsToRemove The number of characters to remove.
764 /// @return \c *this to allow concatenated calls.
765 TAString& ShortenBy( integer charsToRemove ) {
766 return ShortenTo( base::Length() - charsToRemove );
767 }
768
769
770 //################################################################################################
771 // Append-Methods
772 //################################################################################################
773
774 /// Appends an array of an incompatible character type.
775 ///
776 /// @tparam TCharSrc The character type of the given array.
777 /// @tparam TCheck Defaults to #"CHK", which is the normal invocation mode.
778 /// If \c <false>, no nullptr check is done on parameter \p{src}.
779 /// Also, this object would not lose a \e nulled state when the given
780 /// cstring portion is empty.
781 /// @param src A pointer to the start of the array to append.
782 /// @param srcLength The length of the string.
783 ///
784 /// @return \c *this to allow concatenated calls.
785 template <typename TCheck= CHK, typename TCharSrc >
787 && !std::same_as<TCharSrc,TChar> )
788 TAString& Append( const TCharSrc* src, integer srcLength ) {
789
790 if constexpr ( std::same_as<TCheck, alib::CHK> ) {
791 if( !src ) return *this;
792 if ( srcLength <= 0 ) {
793 if ( base::IsNull() )
794 SetBuffer( 15 );
795 return *this;
796 } }
797
798 // We have to know what the "real" types are.
799 #if !DOXYGEN
800 #if ALIB_CHARACTERS_NATIVE_WCHAR
801 # define REAL_WCHAR wchar
802 # define REAL_XCHAR xchar
803 #else
804 # define REAL_WCHAR xchar
805 # define REAL_XCHAR wchar
806 #endif
807 #endif
808
809 // TAString<nchar>
810 if constexpr ( std::same_as<TChar, nchar> ) {
811
812 // wchar -> nchar
813 if constexpr ( std::same_as<TCharSrc, REAL_WCHAR> ) {
814 //---------------------------------- Windows Version ---------------------------------
815 #if defined( _WIN32 )
816
817 // loop until reserved size is big enough
818 for(integer bufSizeFactor= 2; bufSizeFactor < 8; ++bufSizeFactor) {
819 EnsureRemainingCapacity( srcLength * bufSizeFactor );
820 int conversionSize= WideCharToMultiByte( CP_UTF8, 0,
821 src, int( srcLength),
822 base::vbuffer + base::length, int( Capacity() - base::length ),
823 NULL, NULL );
824 if ( conversionSize > 0 ) {
825 base::length+= conversionSize;
826 return *this;
827 }
828
829 // not enough space?
830 int error= GetLastError();
831 if (error == ERROR_INSUFFICIENT_BUFFER ) {
832 EnsureRemainingCapacity( srcLength );
833 continue;
834 }
835
836 // quit on other errors
837 ALIB_WARNING( "STRINGS",
838 "AString: Cannot convert wide character string to UTF-8. Error: {} ({})",
839 ( error == ERROR_INVALID_FLAGS ? "ERROR_INVALID_FLAGS."
840 : error == ERROR_INVALID_PARAMETER ? "ERROR_INVALID_PARAMETER"
841 : error == ERROR_NO_UNICODE_TRANSLATION ? "ERROR_NO_UNICODE_TRANSLATION"
842 : "<unknown>" ),
843 error )
844 return *this;
845 }
846 // Error: not enough space
847 ALIB_ERROR( "STRINGS", "AString: Cannot convert wide character string to "
848 "UTF-8. Error: ERROR_INSUFFICIENT_BUFFER" )
849 return *this;
850
851 //-------------------------------- __GLIBCXX__ Version -------------------------------
852 #elif defined (__GLIBCXX__) || defined(_LIBCPP_VERSION) || defined(__APPLE__) || defined(__ANDROID_NDK__)
853
854 integer maxConversionSize= integer(MB_CUR_MAX) * srcLength;
855
856 mbstate_t ps;
857 EnsureRemainingCapacity( maxConversionSize );
858 memset( &ps, 0, sizeof(mbstate_t) );
859 const REAL_WCHAR* srcp= src;
860 size_t conversionSize= wcsnrtombs( base::vbuffer + base::length, &srcp, size_t(srcLength), size_t(maxConversionSize), &ps);
861 if ( conversionSize == size_t( -1 ) ) {
862 ALIB_WARNING( "STRINGS", "Cannot convert WCS to MBCS. "
863 "Check locale settings (should be UTF-8)" )
864 return *this;
865 }
866
867 if ( conversionSize < 1 ) {
868 ALIB_ERROR( "STRINGS", "Error converting WCS to MBCS." )
869 return *this;
870 }
871
872 TString<TChar>::length+= conversionSize;
873 return *this;
874
875 #else
876 #pragma message ("Unknown Platform in file: " __FILE__ )
877 return *this;
878 #endif
879 } // wchar -> nchar
880
881 // xchar -> nchar
882 if constexpr ( std::same_as<TCharSrc, REAL_XCHAR> ) {
883 // convert to REAL_WCHAR and invoke REAL_WCHAR version
885 REAL_WCHAR externalBuffer[2048];
886 converter.SetBuffer( externalBuffer, 2048 );
888 converter.Append<NC>( src, srcLength );
889 Append<NC>( converter.Buffer(), converter.Length() );
890 }
891
892 } // TAString<nchar>
893
894 // TAString<wchar_t>
895 if constexpr ( std::same_as<TChar, wchar_t> ) {
896 // nchar -> wchar_t
897 if constexpr ( std::same_as<TCharSrc, nchar> ) {
898 EnsureRemainingCapacity( srcLength );
899 //---------------------------------- Windows Version ---------------------------------
900 #if defined( _WIN32 )
901 if( srcLength == 0)
902 return *this;
903 integer conversionSize= MultiByteToWideChar( CP_UTF8, 9,
904 src, int( srcLength ),
905 base::vbuffer + base::length,
906 int( Capacity() - base::length ) );
907 // check for errors
908 #if ALIB_DEBUG
909 if ( conversionSize == 0 ) {
910 // not enough space?
911 int error= GetLastError();
912
913 ALIB_WARNING( "STRINGS",
914 "MBCS to WCS conversion failed. Error: {} ({})",
915 ( error == ERROR_INSUFFICIENT_BUFFER ? "ERROR_INSUFFICIENT_BUFFER."
916 : error == ERROR_INVALID_FLAGS ? "ERROR_INVALID_FLAGS."
917 : error == ERROR_INVALID_PARAMETER ? "ERROR_INVALID_PARAMETER"
918 : error == ERROR_NO_UNICODE_TRANSLATION ? "ERROR_NO_UNICODE_TRANSLATION"
919 : "<unknown>" ),
920 error )
921
922 }
923
924 ALIB_ASSERT_ERROR( conversionSize <= srcLength, "STRINGS",
925 "MBCS to WCS conversion failed. Requested length={}, conversion length=",
926 srcLength, conversionSize )
927 #endif
928
929 base::length+= conversionSize;
930 return *this;
931
932
933 //-------------------------------- __GLIBCXX__ Version -------------------------------
934 #elif defined (__GLIBCXX__) || defined(_LIBCPP_VERSION) || defined(__APPLE__) || defined(__ANDROID_NDK__)
935
936 // copy loop
937 while(srcLength > 0 ) {
938 integer actConversionLenght= srcLength;
939 for( int pass= 0 ; pass < 2 ; ++pass ) {
940
941 mbstate_t ps; memset( &ps, 0, sizeof(mbstate_t) );
942 const nchar* srcp= src;
943 size_t wcWritten= mbsnrtowcs( base::vbuffer + base::length, &srcp,
944 size_t(actConversionLenght),
945 size_t(Capacity() - base::length), &ps );
946
947 // single character failed?
948 if( wcWritten == static_cast<size_t >(-1) ) {
949 // already repeated?
950 // This can't (must not) happen! If it did, release code does infinite loop!
951 ALIB_ASSERT( pass == 0, "STRINGS" )
952
953 // first character that failed?
954 if( srcp == src ) {
955 ++src;
956 --srcLength;
957 *(base::vbuffer + base::length++)= '?';
958 break; // break try loop, continue with next character
959 }
960
961 // retry those characters that succeeded
962 actConversionLenght= srcp - src;
963 continue;
964 }
965
966 base::length+= wcWritten;
967 src+= wcWritten;
968 srcLength-= actConversionLenght;
969 break;
970 } }
971 return *this;
972
973 #else
974 #pragma message ("Unknown Platform in file: " __FILE__ )
975 return *this;
976 #endif
977
978 } // nchar -> wchar_t
979
980 // xchar -> wchar_t
981 if constexpr ( std::same_as<TCharSrc, REAL_XCHAR> ) {
982 #if ALIB_SIZEOF_WCHAR_T == 4
983 EnsureRemainingCapacity( srcLength );
984
985 // convert UTF16 to UTF32
986 const char16_t* srcEnd= src + srcLength;
987 while (src < srcEnd) {
988 const char32_t uc = char32_t(*src++);
989 if ((uc - 0xd800) >= 2048) { // not surrogate
990 base::vbuffer[base::length++] = static_cast<wchar_t>(uc);
991 } else {
992 ALIB_ASSERT_ERROR( src < srcEnd // has one more?
993 && ((uc & 0xfffffc00) == 0xd800) // is low
994 && ((*src & 0xfffffc00) == 0xdc00), // is high
995 "STRINGS", "Error decoding UTF16" )
996 base::vbuffer[base::length++]= static_cast<wchar_t>( (uc << 10)
997 + ((*src++) - 0x35fdc00 ) );
998 } }
999
1000 #else
1001 // convert UTF32 to UTF16
1002 EnsureRemainingCapacity( srcLength * 2 );
1003
1004 const char32_t* srcEnd= src + srcLength;
1005 while (src < srcEnd) {
1006 uinteger uc= *src++;
1007 ALIB_ASSERT_ERROR( uc < 0xd800
1008 || ( uc >= 0xe000 && uc <= 0x10ffff ),
1009 "STRINGS", "Illegal unicode 32 bit codepoint" )
1010
1011 if( uc < 0x10000 ) {
1012 base::vbuffer[base::length++]= static_cast<wchar_t>( uc );
1013 } else {
1014 uc-= 0x10000;
1015 base::vbuffer[base::length++]= static_cast<wchar_t>( ( uc >> 10 ) + 0xd800 );
1016 base::vbuffer[base::length++]= static_cast<wchar_t>( ( uc & 0x3ff ) + 0xdc00 );
1017 } }
1018
1019 return *this;
1020 #endif
1021 } // nchar -> wchar_t
1022 } //wchar_t
1023
1024 // TAString<REAL_XCHAR>
1025 if constexpr ( std::same_as<TChar, REAL_XCHAR> ) {
1026 // wchar_t -> REAL_XCHAR
1027 if constexpr ( std::same_as<TCharSrc, wchar_t> ) {
1028 #if ALIB_SIZEOF_WCHAR_T == 2
1029 EnsureRemainingCapacity( srcLength );
1030
1031 // convert UTF16 to UTF32
1032 const wchar_t* srcEnd= src + srcLength;
1033 while (src < srcEnd) {
1034 const char32_t uc = *src++;
1035 if ((uc - 0xd800) >= 2048) { // not surrogate
1036 base::vbuffer[base::length++] = static_cast<REAL_XCHAR>(uc);
1037 } else {
1038 ALIB_ASSERT_ERROR( src < srcEnd // has one more?
1039 && ((uc & 0xfffffc00) == 0xd800) // is low
1040 && ((*src & 0xfffffc00) == 0xdc00), // is high
1041 "STRINGS", "Error decoding UTF16" )
1042
1043 base::vbuffer[base::length++]= static_cast<REAL_XCHAR>( (uc << 10)
1044 + ((*src++) - 0x35fdc00 ) );
1045 } }
1046
1047 #else
1048 // convert UTF32 to UTF16
1049 EnsureRemainingCapacity( srcLength * 2 ); // can potentially double!
1050
1051 const wchar_t* srcEnd= src + srcLength;
1052 while (src < srcEnd) {
1053 uinteger uc= uinteger( *src++ );
1054 ALIB_ASSERT_ERROR( uc < 0xd800
1055 || ( uc >= 0xe000 && uc <= 0x10ffff ),
1056 "STRINGS", "Illegal unicode 32 bit codepoint" )
1057
1058 if( uc < 0x10000 ) {
1059 base::vbuffer[base::length++]= static_cast<REAL_XCHAR>( uc );
1060 } else {
1061 uc-= 0x10000;
1062 base::vbuffer[base::length++]= static_cast<REAL_XCHAR>( ( uc >> 10 ) + 0xd800 );
1063 base::vbuffer[base::length++]= static_cast<REAL_XCHAR>( ( uc & 0x3ff ) + 0xdc00 );
1064 } }
1065 #endif
1066 } // wchar_t -> REAL_XCHAR
1067
1068 // nchar -> REAL_XCHAR
1069 if constexpr ( std::same_as<TCharSrc, nchar> ) {
1070 ALIB_STRING_DBG_CHK( this )
1071
1072 // We are using a WAString to do the job. Not efficient, but for today, this should be all we do!
1074 REAL_WCHAR externalBuffer[8192];
1075 externalBuffer[0]= 0;
1076 converter.SetBuffer( externalBuffer, 8192 );
1077 converter.Append<NC>( src, srcLength );
1079 return Append<NC>( converter.Buffer(), converter.Length() );
1080 } // nchar -> REAL_XCHAR
1081
1082
1083 } //wchar_t
1084
1085 return *this;
1086 }
1087
1088
1089 /// Appends an array of the same character type.
1090 ///
1091 /// @tparam TCheck Defaults to #"CHK", which is the normal invocation mode.
1092 /// If \c <false>, no nullptr check is done on parameter \p{src}.
1093 /// Also, this object would not lose a \e nulled state when the given
1094 /// cstring portion is empty.
1095 /// @param src A pointer to the start of the array to append.
1096 /// @param srcLength The length of the string.
1097 ///
1098 /// @return \c *this to allow concatenated calls.
1099 template <typename TCheck= CHK>
1100 TAString&
1101 Append( const TChar* src, integer srcLength ) {
1103
1104 if constexpr ( TCheck::value ) {
1105 if (!src)
1106 return *this;
1107
1108 // check empty
1109 if ( srcLength <= 0 ) {
1110 // set "un-nulled"
1111 if ( base::IsNull() )
1112 SetBuffer( 15 );
1113
1114 return *this;
1115 }
1116 } else {
1118 ALIB_ASSERT_ERROR( src || srcLength == 0, "STRINGS",
1119 "Nullptr passed with non-checking method version." )
1120 }
1121
1122 EnsureRemainingCapacity( srcLength );
1123 characters::Copy( src, srcLength, base::vbuffer + base::length );
1124 base::length+= srcLength;
1125
1126 return *this;
1127 }
1128
1129 /// Appends a region of another #"TString;String".
1130 /// The checking version adjusts the given region to the bounds of the source string.
1131 ///
1132 /// \note When using the non-checking version, parameter \p{regionLength} must be set
1133 /// explicitly to the correct value (instead of using the default value).
1134 ///
1135 /// @tparam TCheck Chooses checking or non-checking implementation.
1136 /// Defaults to #"CHK".
1137 /// @param src The \b %String to append.
1138 /// @param regionStart The start of the region in \p{src} to append.
1139 /// @param regionLength The maximum length of the region in \p{src} to append.
1140 /// Defaults to \b %MAX_LEN
1141 ///
1142 /// @return \c *this to allow concatenated calls.
1143 template <typename TCheck= CHK>
1144 TAString& Append(const TString<TChar>& src, integer regionStart, integer regionLength =MAX_LEN){
1145 if constexpr ( TCheck::value ) {
1146 if ( src.IsNull() )
1147 return *this;
1148 if ( src.base::AdjustRegion( regionStart, regionLength ) ) {
1149 // special treatment if currently nothing is allocated and a blank string ("") is added:
1150 // we allocate, which means, we are not a nulled object anymore!
1151 // (...also, in this case we check the src parameter)
1152 if ( base::IsNull() )
1153 SetBuffer( 15 );
1154 return *this;
1155 }
1156 } else {
1157 //---- non-checking version ----
1158 ALIB_ASSERT_ERROR( regionStart >= 0 && regionLength >= 0
1159 && regionLength !=strings::MAX_LEN
1160 && regionStart + regionLength <= src.Length(), "STRINGS",
1161 "Non-checking invocation: ","Invalid region [{} {}] given. AString length: {}",
1162 regionStart, regionLength, src.Length() )
1163 }
1164
1165 // both versions
1166 return Append<NC>( src.Buffer() + regionStart, regionLength );
1167 }
1168
1169 /// Appends a string-representation of the given object \p{src} of template type \p{T} to
1170 /// this \b %AString.
1171 /// Type \p{T} needs to satisfy the concept #"str IsAppendable", which is achieved by
1172 /// specializing the type trait \p{AppendableTraits} accordingly.
1173 ///
1174 /// \see
1175 /// See chapter #"alib_strings_assembly_ttostring" of this module's
1176 /// #"alib_mod_strings;Programmer's Manual" for more information.
1177 ///
1178 /// @tparam TCheck Defaults to #"CHK", which is the normal invocation mode.
1179 /// If after the append operation this string is still \e nulled,
1180 /// an initial buffer is allocated and the state of this instance
1181 /// changes to \e empty.
1182 /// If #"NC" is given, a \e nulled string may remain \e nulled.
1183 /// @tparam TAppendable The type of parameter \p{src}.
1184 /// @param src The object to "stringify" and append.
1185 /// @return \c *this to allow concatenated calls.
1186 template<typename TCheck= CHK, typename TAppendable>
1188 TAString& Append(const TAppendable& src ) {
1190
1191 if ( TCheck::value && base::IsNull() )
1192 SetBuffer( 15 );
1193 return *this;
1194 }
1195
1196 /// Appends string-like types which satisfy either of the concepts
1197 /// #"IsImplicitArraySource" #"IsImplicitZTArraySource".
1198 ///
1199 /// @tparam TCheck Defaults to #"CHK", which is the normal invocation mode.
1200 /// If #"NC" is given, a \e nulled string may remain \e nulled,
1201 /// and if the character buffer received from \p{src} is \c nullptr,
1202 /// this method has undefined behavior.
1203 /// @tparam TStringSource The type of parameter \p{src}.
1204 /// @param src The string-type object to append.
1205 /// @return \c *this to allow concatenated calls.
1206 template< typename TCheck= CHK, typename TStringSource>
1207 requires ( alib::characters::IsImplicitZTArraySource<TStringSource,
1211 TAString& Append(const TStringSource& src ) {
1212 // implicit
1216 const TSrc* buf= TCA::Buffer( src );
1217 return Append<TCheck>( buf, TCA::Length( src ) );
1218 // explicit
1219 } else {
1222 const TSrc* buf= TCA::Buffer( src );
1223 return Append<TCheck>( buf, TCA::Length( src ) );
1224 } }
1225
1226 /// Appends platform-specific new line character(s) by appending literal string
1227 /// #"NEW_LINE".
1228 /// @return \c *this to allow concatenated calls.
1230
1231
1232 /// Appends a single character of compatible type.
1233 /// @tparam TCheck Defaults to #"CHK", which is the normal invocation mode.
1234 /// Here, nothing is appended if the given character is \c 0, but still
1235 /// this instance will switch to \e empty state if it was \e nulled before.
1236 /// If #"NC" is given, \p{src} is \b not checked for being \c 0.
1237 /// @param src The character object to append.
1238 /// @return \c *this to allow concatenated calls.
1239 template<typename TCheck= CHK>
1240 TAString& Append(TChar src ) {
1241 if constexpr ( TCheck::value ) {
1242 if ( src == 0 ) {
1243 if (base::IsNull() )
1244 SetBuffer( 15 );
1245 }
1246 else {
1248 base::vbuffer[ base::length++ ]= src;
1249 }
1250 return *this;
1251 }
1252
1254 base::vbuffer[ base::length++ ]= src;
1255 return *this;
1256 }
1257
1258 /// Appends a single character of a different type.
1259 /// If this string is narrow, the given character is UTF-8 encoded.
1260 /// @tparam TCheck Defaults to #"CHK", which is the normal invocation mode.
1261 /// Here, nothing is appended if the given character is \c 0, but still
1262 /// this instance will switch to \e empty state if it was \e nulled before.
1263 /// If #"NC" is given, \p{src} is \b not checked for being \c 0.
1264 /// @param src The character value to append. Only values of types that satisfy
1265 /// the concept #"ch IsCharacter" are accepted.
1266 /// @return \c *this to allow concatenated calls.
1267 template< typename TCheck= CHK>
1269 // check for 0
1270 if ( TCheck::value && src == 0 ) {
1271 if (base::IsNull() )
1272 SetBuffer( 15 );
1273 return *this;
1274 }
1275
1276
1277 // this is an AString<nchar>?
1278 if constexpr ( std::same_as< TChar, nchar > ) {
1279 wchar wc= static_cast<wchar>( src );
1280 int mbLength;
1281 #if defined(_WIN32)
1282 EnsureRemainingCapacity( MB_LEN_MAX * 2);
1283 mbLength= WideCharToMultiByte( CP_UTF8, 0, &wc, 1,
1284 ((nchar*) base::vbuffer) + base::length,
1285 MB_LEN_MAX * 2, NULL, NULL );
1286 if ( mbLength <= 0 ) {
1287 ALIB_DBG( DWORD error= GetLastError(); )
1288 ALIB_WARNING( "STRINGS", "Cannot convert wide character string to UTF-8. Error: {} ({})",
1289 ( error == ERROR_INSUFFICIENT_BUFFER ? "ERROR_INSUFFICIENT_BUFFER"
1290 : error == ERROR_INVALID_FLAGS ? "ERROR_INVALID_FLAGS."
1291 : error == ERROR_INVALID_PARAMETER ? "ERROR_INVALID_PARAMETER"
1292 : error == ERROR_NO_UNICODE_TRANSLATION ? "ERROR_NO_UNICODE_TRANSLATION"
1293 : "<unknown>" ),
1294 error )
1295 }
1296 #else
1297 EnsureRemainingCapacity( integer(MB_CUR_MAX) + 1);
1298 mbLength= wctomb( reinterpret_cast<nchar*>(base::vbuffer)
1299 + base::length, wc );
1300 #endif
1301
1302 if ( mbLength <= 0 ) {
1303 ALIB_WARNING( "STRINGS", "Cannot convert WC to MBC." )
1304 return *this;
1305 }
1306
1307 base::length+= mbLength;
1308 return *this;
1309 }
1310
1311 // AString<wchar>/<xchar>? (we are just casting)
1313 base::vbuffer[ base::length++ ]= static_cast<TChar>( src );
1314 return *this;
1315 }
1316
1317 /// Alias to overloaded methods #Append.<br>
1318 /// @tparam TCheck Defaults to #"CHK", which is the normal invocation mode.
1319 /// If #"NC" is given, checks are omitted.
1320 /// (The specific behavior depends on the overloaded \b %Append method
1321 /// that is called.)
1322 /// @tparam TAppendable The type of parameter \p{source}.
1323 /// @param src The source object to append a string representation for.
1324 ///
1325 /// @return \c *this to allow concatenated calls.
1326 template <typename TCheck= CHK, class TAppendable >
1327 TAString& _(const TAppendable& src ) { return Append<TCheck>( src ); }
1328
1329 /// Alias method of #Append(const TString<TChar>&, integer, integer).<br>
1330 /// Provided for compatibility with C# and Java versions of \alib.
1331 ///
1332 /// @tparam TCheck Chooses checking or non-checking implementation.
1333 /// Defaults to #"CHK".
1334 /// @param src The \b %String to append.
1335 /// @param regionStart The start of the region in \p{src} to append.
1336 /// @param regionLength The maximum length of the region in \p{src} to append.
1337 /// Defaults to \b %MAX_LEN
1338 ///
1339 /// @return \c *this to allow concatenated calls.
1340 template <typename TCheck= CHK>
1341 TAString& _( const TString<TChar>& src, integer regionStart, integer regionLength =MAX_LEN )
1342 { return Append( src, regionStart, regionLength ); }
1343
1344
1345 /// Alias to overloaded methods #Append.<br>
1346 /// When this operator is used, template parameter \p{TCheck} of the <b>Append</b>-method
1347 /// called is set to #"CHK".
1348 ///
1349 /// @tparam TAppendable The type of parameter \p{source}.
1350 /// @param src The object of type T to append.
1351 /// @return \c *this to allow concatenated calls.
1352 template <typename TAppendable>
1353 TAString& operator<< (const TAppendable& src ) { return Append<CHK>(src); }
1354
1355 /// Alias to overloaded methods #Append.<br>
1356 /// When this operator is used, template parameter \p{TCheck} of the <b>Append</b>-method
1357 /// called is set to #"CHK".
1358 /// \note
1359 /// According to the C++ idiom, this class is considered a _container_ rather than a
1360 /// _stream_.
1361 /// Therefore, this operator is included for the sake of completeness and compatibiltiy with
1362 /// class <c>std::string</c> which (only!) defines this operator.
1363 /// However, the differences in operator **associativity** and **precedence rules** in C++
1364 /// affect how <c>operator+=</c> behaves in chained expressions.
1365 /// Specifically, this operator is left-associative, meaning expressions are evaluated from
1366 /// left to right.
1367 /// As a result, chaining multiple <c>+=</c> operations requires explicit parentheses to avoid
1368 /// compilation errors and ensure the correct evaluation order.
1369 ///
1370 /// \note
1371 /// For example:
1372 /// \code{.cpp}
1373 /// myString += "hello" += "world"; // Compilation error: parentheses are required
1374 /// (myString += "hello") += "world"; // Correct.
1375 /// myString << "hello" << "world"; // Correct without parentheses
1376 /// \endcode
1377 /// \note
1378 /// Because <c>operator<<</c> typically expresses a streaming-like behavior, it avoids such
1379 /// ambiguity or precedence issues and is more straightforward for chaining multiple append
1380 /// operations. Hence, it is recommended to prefer <c><<</c> over <c>+=</c> when performing
1381 /// multiple appends within a single expression.
1382 ///
1383 /// @tparam TAppendable The type of parameter \p{source}.
1384 /// @param src The object of type T to append.
1385 /// @return \c *this to allow concatenated calls.
1386 template <typename TAppendable>
1387 TAString& operator+= (const TAppendable& src ) { return Append<CHK>(src); }
1388
1389 //################################################################################################
1390 // Insert and Delete
1391 //################################################################################################
1392
1393 /// Sets the length of this string to zero. A \e nulled object remains \e nulled.
1394 /// @return \c *this to allow concatenated calls.
1395 TAString& Reset() { ALIB_STRING_DBG_CHK(this) base::length= 0; return *this; }
1396
1397 /// Sets the length of the string to zero and then invokes one of the overloaded methods
1398 /// #Append.
1399 ///
1400 /// @tparam TCheck Defaults to #"CHK", which is the normal invocation mode.
1401 /// The value is used with the invocation of method \b Append.
1402 /// @tparam TAppendable The type of parameter \p{source}.
1403 /// @param src The source of type \p{TAppendable} to append.
1404 ///
1405 /// @return \c *this to allow concatenated calls.
1406 template <typename TCheck= CHK, typename TAppendable>
1407 TAString& Reset(const TAppendable& src ) {
1409 base::length= 0;
1410 Append<TCheck>( src );
1411 return *this;
1412 }
1413
1414 /// Sets the length of the string to zero. Same as method #Reset.
1415 /// Provided for compatibility with C# and Java versions of \alib.
1416 /// @return \c *this to allow concatenated calls.
1419 base::length= 0;
1420 return *this;
1421 }
1422
1423 /// Inserts the given string at the given position.
1424 /// If the position is not between \c 0 and the length of the target, nothing is inserted.
1425 /// The latter is only asserted in case the template parameter \p{TCheck} is not set to
1426 /// #"NC".
1427 /// \note
1428 /// To insert a string with replacing a different one at the same time, use the method
1429 /// #ReplaceSubstring".
1430 ///
1431 /// @tparam TCheck Chooses checking or non-checking implementation. Defaults to #"CHK".
1432 /// @param src The \b %String to insert.
1433 /// @param pos The position to insert \p{src}.
1434 /// @return \c *this to allow concatenated calls.
1435 template <typename TCheck= CHK>
1438 integer srcLength= src.Length();
1439 if constexpr ( TCheck::value ) {
1440 if ( srcLength == 0 || pos < 0 || pos > base::length )
1441 return *this;
1442 } else {
1443 ALIB_ASSERT_ERROR( srcLength > 0 && pos >=0 && pos <= base::length, "STRINGS",
1444 "Non-checking invocation: ","Illegal insertion position 0 <= {} < {}.",
1445 pos, base::length )
1446 }
1447
1448 EnsureRemainingCapacity( srcLength );
1449
1450 // move content and copy string new region
1451 if ( pos != base::length )
1452 characters::Move( base::vbuffer + pos,
1453 base::length - pos,
1454 base::vbuffer + pos + srcLength );
1455 base::length+= src.CopyTo( base::vbuffer + pos );
1456
1457 return *this;
1458 }
1459
1460 /// Inserts the given number of \b uninitialized characters at the given position.
1461 /// If the position is not between \c 0 and the length of the target, nothing is inserted.
1462 /// The latter is only asserted in case the template parameter \p{TCheck} is not set to
1463 /// #"NC".
1464 ///
1465 /// \note
1466 /// The usage of other <b>Insert</b>-methods is preferred. This method is efficient in cases
1467 /// when the replacement consists of different parts and external assembly prior to the
1468 /// replacement should be avoided.
1469 ///
1470 /// @tparam TCheck Chooses checking or non-checking implementation. Defaults to #"CHK".
1471 /// @param pos The position to insert \p{src}.
1472 /// @param size The number of characters to insert.
1473 /// @return \c *this to allow concatenated calls.
1474 template <typename TCheck= CHK>
1477 if constexpr ( TCheck::value ) {
1478 if ( size == 0 || pos < 0 || pos > base::length )
1479 return *this;
1480 } else {
1481 ALIB_ASSERT_ERROR( size > 0 && pos >=0 && pos <= base::length, "STRINGS",
1482 "Non-checking invocation: ","Illegal insertion position 0 <= {} < {}. or size {}",
1483 pos, base::length, size )
1484 }
1485
1487
1488 // move content
1489 if ( pos != base::length )
1490 characters::Move( base::vbuffer + pos,
1491 base::length - pos,
1492 base::vbuffer + pos + size );
1493 return *this;
1494 }
1495
1496 /// Appends the given character \p{c} \p{qty}-times.
1497 /// The non-checking version does not check parameter \p{qty} to be greater than zero.
1498 ///
1499 /// @tparam TCheck Defaults to #"CHK", which chooses the checking version of the method.
1500 /// @param c The character to insert \p{qty} times.
1501 /// @param qty The quantity of characters to insert.
1502 /// @return \c *this to allow concatenated calls.
1503 template <typename TCheck= CHK>
1504 TAString& InsertChars( TChar c, integer qty ) {
1505 if constexpr ( TCheck::value ) {
1506 if ( qty <= 0 )
1507 return *this;
1508 }
1509 else
1510 ALIB_ASSERT_ERROR( qty >= 0, "STRINGS",
1511 "Non-checking invocation: ", "Negative quantity {} given", qty )
1512
1514 characters::Fill( base::vbuffer + base::length, qty, c );
1515 base::length+= qty;
1516 return *this;
1517 }
1518
1519 /// Inserts the given character \p{c} \p{qty}-times at a given position.
1520 /// If the given position is out of range, nothing is inserted.
1521 ///
1522 /// The non-checking version does not check the position to be in a valid range and
1523 /// the \p{qty} to be greater than zero.
1524 ///
1525 /// @tparam TCheck Defaults to #"CHK", which chooses the checking version of the method.
1526 /// @param c The character to insert \p{qty} times.
1527 /// @param qty The quantity of characters to insert.
1528 /// @param pos The index in this object where \p{c} is inserted \p{qty} times.
1529 /// @return \c *this to allow concatenated calls.
1530 template <typename TCheck= CHK>
1531 TAString& InsertChars( TChar c, integer qty, integer pos ) {
1532 if constexpr ( TCheck::value ) {
1533 if ( qty <= 0 || pos < 0 || pos > base::length )
1534 return *this;
1535 } else {
1536 ALIB_ASSERT_ERROR( qty >= 0, "STRINGS",
1537 "Non-checking invocation: ", "Negative quantity {} given", qty )
1538 ALIB_ASSERT_ERROR( pos >= 0 && pos <= base::length, "STRINGS",
1539 "Non-checking invocation: ","Illegal position given: 0 <= {} < {}.", pos,base::length )
1540 }
1541
1543
1544 // move content ?
1545 if ( pos != base::length )
1546 characters::Move( base::vbuffer + pos,
1547 base::length - pos,
1548 base::vbuffer + pos + qty );
1549
1550 // set
1551 characters::Fill( base::vbuffer + pos, qty, c );
1552 base::length+= qty;
1553
1554 return *this;
1555 }
1556
1557 /// Removes a region from the string by moving the remaining string behind the region to
1558 /// the region start and adjusting the string's length.
1559 ///
1560 /// A range check is performed and the region is cut to fit to the string.
1561 /// The non-checking version (\p{TCheck} = #"NC") omits the check, but still allows
1562 /// leaving parameter \p{regionLength} as default (respectively allows the sum of parameters
1563 /// \p{regionStart} and \p{regionLength} to be longer than the length of this \b %AString).
1564 /// In this case, this string is cut starting from index \p{regionStart}.
1565 ///
1566 /// \note See also methods #Reset, #DeleteStart and #DeleteEnd.
1567 ///
1568 /// @tparam TCheck Defaults to #"CHK", which is the normal invocation mode.
1569 /// If \c <false> is added to the method name, the start of the region
1570 /// is not adjusted to the string's bounds.
1571 /// @param regionStart The start of the region to delete.
1572 /// @param regionLength The length of the region to delete. Defaults to \b %MAX_LEN.
1573 /// @return \c *this to allow concatenated calls.
1574 template <typename TCheck= CHK >
1575 TAString& Delete( integer regionStart, integer regionLength =MAX_LEN ) {
1577
1578 integer regionEnd;
1579
1580 if constexpr ( TCheck::value ) {
1581 if ( base::AdjustRegion( regionStart, regionLength ) )
1582 return *this;
1583
1584 // delete over the end?
1585 if ( (regionEnd= regionStart + regionLength) >= base::length ) {
1586 base::length= regionStart;
1587 return *this;
1588 }
1589 } else {
1590 ALIB_ASSERT_ERROR( regionStart >= 0
1591 && regionStart <= base::length , "STRINGS",
1592 "Non-checking invocation: ", "Illegal arguments. Region start: 0 <= {} < {}.",
1593 regionStart, base::length )
1594 ALIB_ASSERT_ERROR( regionLength >= 0 , "STRINGS",
1595 "Non-checking invocation: ", "Illegal arguments. Negative region length {} given.",
1596 regionLength )
1597
1598 // delete over the end?
1599 if ( (regionEnd= regionStart + regionLength) >= base::length ) {
1600 base::length= regionStart;
1601 return *this;
1602 } }
1603
1604 // both versions
1605 characters::Move( base::vbuffer + regionEnd,
1606 base::length - regionEnd + 1,
1607 base::vbuffer + regionStart );
1608 base::length-= regionLength;
1609
1610 return *this;
1611 }
1612
1613 /// Deletes the given number of characters from the start of the string by moving the
1614 /// rest of the string to the start and adjusting the string's length.
1615 ///
1616 /// @tparam TCheck Defaults to #"CHK", which is the normal invocation mode.
1617 /// If \c <false> is added to the method name, no parameter checks are
1618 /// performed.
1619 ///
1620 /// @param regionLength The length of the region at the start to delete.
1621 ///
1622 /// @return \c *this to allow concatenated calls.
1623 template <typename TCheck= CHK >
1624 TAString& DeleteStart( integer regionLength ) {
1626
1627 if constexpr ( TCheck::value ) {
1628 if ( regionLength <= 0 ) {
1630 return *this;
1631 }
1632 if ( regionLength >= base::length )
1633 return Reset();
1634 } else {
1635 ALIB_ASSERT_ERROR( regionLength >=0 && regionLength <= base::length, "STRINGS",
1636 "Non-checking invocation: ", "Region length out of range: 0 <= {} < {}.",
1637 regionLength, base::length )
1638 }
1639
1640 characters::Move( base::buffer + regionLength,
1641 base::length - regionLength + 1,
1642 base::vbuffer );
1643 base::length-= regionLength;
1644 return *this;
1645 }
1646
1647 /// Deletes the given string from the start of this string. If this string does not start
1648 /// with the given string, nothing is done.
1649 ///
1650 /// @param deleteIfMatch The string to be deleted at the start.
1651 ///
1652 /// @return \c *this to allow concatenated calls.
1653 TAString& DeleteStart( const TString<TChar>& deleteIfMatch ) {
1655 if( deleteIfMatch.IsNotEmpty() && base::StartsWith(deleteIfMatch) )
1656 return DeleteStart(deleteIfMatch.Length());
1657 return *this;
1658 }
1659
1660 /// Reduces the length of the string by the given number of characters.
1661 ///
1662 /// @tparam TCheck Defaults to #"CHK", which is the normal invocation mode.
1663 /// If \c <false> is added to the method name, no parameter checks are
1664 /// performed and any given value is just subtracted from the
1665 /// current length.
1666 /// @param regionLength The length of the region at the end to delete.
1667 ///
1668 /// @return \c *this to allow concatenated calls.
1669 template <typename TCheck= CHK >
1670 TAString& DeleteEnd( integer regionLength ) {
1672
1673 if constexpr ( TCheck::value ) {
1674 if ( regionLength > 0 ) {
1675 if ( regionLength >= base::length )
1676 base::length= 0;
1677 else
1678 base::length-= regionLength;
1679 }
1680 } else {
1681 ALIB_ASSERT_ERROR( regionLength >=0 && regionLength <= base::length, "STRINGS",
1682 "Non-checking invocation: ", "Region length out of range: 0 <= {} < {}.",
1683 regionLength, base::length )
1684 base::length-= regionLength;
1685 }
1686
1687 return *this;
1688 }
1689
1690 /// Deletes the given string from the end of this string. If this string does not end with
1691 /// the given string, nothing is done.
1692 ///
1693 /// @param deleteIfMatch The string to be deleted at the end.
1694 ///
1695 /// @return \c *this to allow concatenated calls.
1696 TAString& DeleteEnd( const TString<TChar>& deleteIfMatch ) {
1698 if( deleteIfMatch.IsNotEmpty() && base::EndsWith(deleteIfMatch) )
1699 return DeleteEnd(deleteIfMatch.Length());
1700 return *this;
1701 }
1702
1703 /// All characters defined in given set are removed at the beginning and at the end of this
1704 /// string.
1705 ///
1706 /// \see Method #TrimAt to remove whitespaces at arbitrary places in the string.
1707 ///
1708 /// @param trimChars Pointer to a zero-terminated set of characters to be omitted.
1709 /// Defaults to #"DEFAULT_WHITESPACES".
1710 /// @return \c *this to allow concatenated calls.
1711 ALIB_DLL
1712 TAString& Trim( const TCString<TChar>& trimChars
1714
1715 /// All characters defined in given set at, left of and right of the given index
1716 /// are removed from the string.<br>
1717 /// The method returns index of the first character of those characters that were behind the
1718 /// trimmed region. With legal \p{idx} given, this value can only be smaller or equal to
1719 /// \p{idx}. If \p{idx} is out of bounds, the length of the string is returned.
1720 ///
1721 /// @param idx The index to perform the trim operation at. Has to be between zero
1722 /// and <em>Length() -1</em>.
1723 /// @param trimChars Pointer to a zero-terminated set of characters to be omitted.
1724 /// Defaults to #"DEFAULT_WHITESPACES".
1725 /// @return The index of the first character of those characters that were behind the
1726 /// trimmed region.
1727 ALIB_DLL
1728 integer TrimAt( integer idx, const TCString<TChar>& trimChars
1730
1731 /// All characters defined in given set are removed at the beginning of this string.
1732 ///
1733 /// \see Method #TrimAt to remove whitespaces at arbitrary places in the string.
1734 ///
1735 /// @param trimChars Pointer to a zero-terminated set of characters to be omitted.
1736 /// Defaults to #"DEFAULT_WHITESPACES".
1737 /// @return \c *this to allow concatenated calls.
1740 if (base::length == 0 || trimChars.IsEmpty() )
1741 return *this;
1742
1743 integer idx= base::template IndexOfAny<lang::Inclusion::Exclude, NC>( trimChars );
1744 if ( idx > 0 )
1745 Delete<NC>( 0, idx );
1746 else if ( idx < 0 )
1747 base::length= 0;
1748
1749 return *this;
1750 }
1751
1752 /// All characters defined in given set are removed at the end of this string.
1753 ///
1754 /// \see Method #TrimAt to remove whitespaces at arbitrary places in the string.
1755 ///
1756 /// @param trimChars Pointer to a zero-terminated set of characters to be omitted.
1757 /// Defaults to #"DEFAULT_WHITESPACES".
1758 /// @return \c *this to allow concatenated calls.
1761 if( base::length > 0 && trimChars.IsNotEmpty() )
1764 trimChars, base::length - 1 ) + 1;
1765 return *this;
1766 }
1767
1768 //##################################################################################################
1769 // Replace
1770 //##################################################################################################
1771
1772 /// Replaces a region in this object with a given string.
1773 /// The given region is adjusted to this string's bounds.
1774 ///
1775 /// The non-checking version does not adjust the region and
1776 /// #"alib_mod_assert;raises an ALib error" in debug-compilations if the given region is
1777 /// out of bounds.
1778 ///
1779 /// @tparam TCheck Chooses checking or non-checking implementation.
1780 /// Defaults to #"CHK".
1781 /// @param src The replacement string.
1782 /// @param regionStart The start of the region.
1783 /// @param regionLength The length of the region.
1784 /// @return \c *this to allow concatenated calls.
1785 template <typename TCheck= CHK>
1787 integer regionStart, integer regionLength ) {
1789 if constexpr ( TCheck::value ) {
1790 base::AdjustRegion( regionStart, regionLength );
1791 } else {
1792 ALIB_ASSERT_ERROR( src.IsNotNull(), "STRINGS",
1793 "Non-checking invocation: ", "Source string is nulled" )
1794 #if ALIB_DEBUG
1795 integer rs= regionStart;
1796 integer rl= regionLength;
1797 base::AdjustRegion( rs, rl );
1798 ALIB_ASSERT_ERROR( rs == regionStart && rl == regionLength, "STRINGS",
1799 "Non-checking invocation: ", "Invalid region {}/{} given. Adjusted: {}/{}",
1800 regionStart, regionLength, rs, rl )
1801
1802 #endif
1803 }
1804
1805 integer lenDiff= src.Length() - regionLength;
1806
1807 // check buffer size
1808 if ( lenDiff > 0 )
1809 EnsureRemainingCapacity( lenDiff );
1810
1811 // move content
1812 if ( lenDiff != 0 )
1813 characters::Move( base::vbuffer + regionStart + regionLength,
1814 base::length - (regionStart + regionLength),
1815 base::vbuffer + regionStart + src.Length() );
1816
1817 // copy the source
1818 src.CopyTo( base::vbuffer + regionStart );
1819 base::length+= lenDiff;
1820
1821 return *this;
1822 }
1823
1824 /// Replaces a region in the string with the given character.
1825 /// The given region is adjusted to this string's bounds. If the adjusted region is empty,
1826 /// nothing is done.
1827 ///
1828 /// The non-checking version does not adjust the region.
1829 ///
1830 /// @tparam TCheck Chooses checking or non-checking implementation.
1831 /// Defaults to #"CHK".
1832 /// @param regionStart The start of the region
1833 /// @param regionLength The length of the region
1834 /// @param c The character to set in the region.
1835 /// @return \c *this to allow concatenated calls.
1836 template <typename TCheck= CHK>
1837 TAString& ReplaceRegion( TChar c, integer regionStart, integer regionLength ) {
1838 if constexpr ( TCheck::value ) {
1839 if ( base::AdjustRegion( regionStart, regionLength ) )
1840 return *this;
1841 } else {
1842 #if ALIB_DEBUG
1843 integer rs= regionStart;
1844 integer rl= regionLength;
1845 base::AdjustRegion( rs, rl );
1846 ALIB_ASSERT_ERROR( rs == regionStart && rl == regionLength, "STRINGS",
1847 "Non-checking invocation: ", "Invalid region {}/{} given. Adjusted: {}/{}",
1848 regionStart, regionLength, rs, rl )
1849 #endif
1850 }
1851
1852 characters::Fill( base::vbuffer + regionStart, regionLength, c );
1853 return *this;
1854 }
1855
1856 /// Replaces all occurrences of character \p{needle} found at or behind position \p{startIdx}
1857 /// by character \p{replacement}.
1858 ///
1859 /// @param needle The character to search.
1860 /// @param replacement The replacement character.
1861 /// @param startIdx The index where the search ends. Optional and defaults to \c 0.
1862 /// @param endIdx The index where the search ends. Precisely, the index of the
1863 /// first character that is not replaced.
1864 /// Defaults to #"str MAX_LEN".
1865 ///
1866 /// @return The number of replacements that where performed.
1867 ALIB_DLL
1869 TChar replacement,
1870 integer startIdx = 0,
1871 integer endIdx =strings::MAX_LEN );
1872
1873 /// Replaces up to \p{maxReplacements} occurrences of string \p{needle} found
1874 /// at or behind position \p{startIdx} by string \p{replacement} .
1875 ///
1876 /// @param needle The string to be searched and replaced.
1877 /// @param replacement The replacement string.
1878 /// @param startIdx The index where the search starts. Optional and defaults 0.
1879 /// @param maxReplacements The maximum number of replacements to perform.
1880 /// Optional and defaults to \b %MAX_LEN.
1881 /// @param sensitivity Case sensitivity of the comparison.
1882 /// Optional and defaults to Case::Sensitive.
1883 /// @param endIdx The index where the search ends. Precisely, the index of the
1884 /// first character that is not tested to be the start of
1885 /// \p{replacement}.
1886 /// Defaults to #"str MAX_LEN".
1887 ///
1888 /// @return The number of replacements that where performed.
1889 ALIB_DLL
1891 const TString<TChar>& replacement,
1892 integer startIdx = 0,
1893 integer maxReplacements =strings::MAX_LEN,
1894 lang::Case sensitivity = lang::Case::Sensitive,
1895 integer endIdx =strings::MAX_LEN );
1896
1897 //##################################################################################################
1898 // Conversion
1899 //##################################################################################################
1900
1901 /// Converts all or a region of characters in the Buffer to upper case.
1902 ///
1903 /// @param regionStart Start of the region to be converted. Defaults to 0
1904 /// @param regionLength Length of the region to be converted. Defaults to \b %MAX_LEN.
1905 ///
1906 /// @return \c *this to allow concatenated calls.
1907 template <typename TCheck= CHK>
1908 TAString& ToUpper( integer regionStart= 0, integer regionLength =MAX_LEN ) {
1909 if constexpr ( TCheck::value ) {
1910 if ( base::AdjustRegion( regionStart, regionLength ) )
1911 return *this;
1912 } else {
1913 #if ALIB_DEBUG
1914 integer rs= regionStart;
1915 integer rl= regionLength;
1916 base::AdjustRegion( rs, rl );
1917 ALIB_ASSERT_ERROR( rs == regionStart && rl == regionLength, "STRINGS",
1918 "Non-checking invocation: ", "Invalid region {}/{} given. Adjusted: {}/{}",
1919 regionStart, regionLength, rs, rl )
1920 #endif
1921 }
1922
1923 characters::ToUpper( base::vbuffer + regionStart, regionLength );
1924 return *this;
1925 }
1926
1927
1928 /// Converts all or a region of characters in the Buffer to lower case.
1929 ///
1930 /// @param regionStart Start of the region to be converted. Defaults to 0
1931 /// @param regionLength Length of the region to be converted. Defaults to \b %MAX_LEN.
1932 ///
1933 /// @return \c *this to allow concatenated calls.
1934 template <typename TCheck= CHK>
1935 TAString& ToLower( integer regionStart= 0, integer regionLength =MAX_LEN ) {
1936 if constexpr ( TCheck::value ) {
1937 if ( base::AdjustRegion( regionStart, regionLength ) )
1938 return *this;
1939 } else {
1940 #if ALIB_DEBUG
1941 integer rs= regionStart;
1942 integer rl= regionLength;
1943 base::AdjustRegion( rs, rl );
1944 ALIB_ASSERT_ERROR( rs == regionStart && rl == regionLength, "STRINGS",
1945 "Non-checking invocation: ", "Invalid region {}/{} given. Adjusted: {}/{}",
1946 regionStart, regionLength, rs, rl )
1947 #endif
1948 }
1949
1950 characters::ToLower( base::vbuffer + regionStart, regionLength );
1951 return *this;
1952 }
1953
1954 /// Reverses the order of the characters of this string (or a region hereof).
1955 ///
1956 /// @param regionStart Start of the region to be reversed. Defaults to 0
1957 /// @param regionLength Length of the region to be reversed. Defaults to \b %MAX_LEN.
1958 ///
1959 /// @return \c *this to allow concatenated calls.
1960 template <typename TCheck= CHK>
1961 TAString& Reverse( integer regionStart= 0, integer regionLength =MAX_LEN ) {
1962 if constexpr ( TCheck::value ) {
1963 if ( base::AdjustRegion( regionStart, regionLength ) )
1964 return *this;
1965 } else {
1966 #if ALIB_DEBUG
1967 integer rs= regionStart;
1968 integer rl= regionLength;
1969 base::AdjustRegion( rs, rl );
1970 ALIB_ASSERT_ERROR( rs == regionStart && rl == regionLength, "STRINGS",
1971 "Non-checking invocation: ", "Invalid region {}/{} given. Adjusted: {}/{}",
1972 regionStart, regionLength, rs, rl )
1973 #endif
1974 }
1975
1976 characters::Reverse( base::vbuffer + regionStart, regionLength );
1977 return *this;
1978 }
1979
1980 //################################################################################################
1981 // Iteration (std::iterator_traits)
1982 //################################################################################################
1983
1984 public:
1985 using base::begin;
1986 using base::end;
1987 using base::rbegin;
1988 using base::rend;
1989
1990 /// A \c std::iterator_traits type, implementing the standard library concept of
1991 /// \https{RandomAccessIterator,en.cppreference.com/w/cpp/concept/RandomAccessIterator}.
1992 /// While parent class \b %String provides a constant iterator only, this class exposes
1993 /// an iterator that allows the modification of the character an iterator references.
1994 using iterator= typename base::template TRandomAccessIterator<TChar>;
1995
1996 /// Same as #iterator, but working from the end to the start of the string.
1997 using reverse_iterator = std::reverse_iterator<iterator>;
1998
1999 /// Returns an iterator pointing to a constant character at the start of this string.
2000 /// @return The start of this string.
2001 iterator begin() { return iterator( base::vbuffer ); }
2002
2003 /// Returns an iterator pointing behind this string.
2004 /// @return The end of this string.
2005 iterator end() { return iterator( base::vbuffer + base::length ); }
2006
2007 /// Returns a reverse iterator pointing to a constant character at the end of this string.
2008 /// @return The last character of this string.
2010
2011 /// Returns a reverse iterator pointing before the start of this string.
2012 /// @return The character before this string.
2014
2015 /// Appends the given character to this \b AString.<br>
2016 /// Needed, for example, to make this type compatible with <c>std::back_insert_iterator</c>.
2017 /// @param ch The character to append to the end of this string.
2018 constexpr void push_back( TChar ch ) { Append( ch ); }
2019
2020 /// Pops one character from the end of this string.<br>
2021 /// With debug-compilations, an assertion is raised in case this string is empty.
2022 /// @return The character that got removed.
2023 constexpr TChar pop_back() {
2024 ALIB_ASSERT_ERROR( base::length > 0, "STRINGS", "pop_back called on empty string" )
2025 return base::vbuffer[ --base::length ];
2026 }
2027
2028}; // class TAString
2029
2030//##################################################################################################
2031// TAString type aliases
2032//##################################################################################################
2033} // namespace alib[::strings]
2034
2035DOX_MARKER( [DOX_MONOMEM_ALLOCMEMBER])
2036/// Type alias in namespace \b alib.
2038DOX_MARKER( [DOX_MONOMEM_ALLOCMEMBER])
2039
2040/// Type alias in namespace \b alib.
2042
2043/// Type alias in namespace \b alib.
2045
2046/// Type alias in namespace \b alib.
2047using NAString = strings::TAString <nchar , lang::HeapAllocator>;
2048
2049/// Type alias in namespace \b alib.
2050using WAString = strings::TAString <wchar , lang::HeapAllocator>;
2051
2052/// Type alias in namespace \b alib.
2053using XAString = strings::TAString <xchar , lang::HeapAllocator>;
2054
2055//##################################################################################################
2056// Specializations of ArrayTraits for this class String
2057//##################################################################################################
2058#if !DOXYGEN
2059namespace strings {
2060template<typename TChar, typename TAlloc>
2061struct NoAutoCastTraits< TAString<TChar,TAlloc>,
2062 characters::Policy::ExplicitOnly,
2063 std::basic_string<TChar> > : std::true_type {};
2064}
2065
2066namespace characters {
2067
2068template<typename TChar, typename TAllocator>
2069struct ArrayTraits<strings::TAString<TChar,TAllocator>, TChar>
2070{
2071 using T= strings::TAString<TChar,TAllocator>;
2072 static constexpr Policy Access = Policy::Implicit;
2073 static constexpr Policy Construction = Policy::ExplicitOnly;
2074 static constexpr const TChar* Buffer (const T& src) { return src.Buffer(); }
2075 static constexpr integer Length (const T& src) { return src.Length(); }
2076 static constexpr T Construct(const TChar* b, integer l) { return T().Append(b, l); }
2077};
2078
2079template<typename TChar, typename TAllocator>
2080struct ZTArrayTraits<strings::TAString<TChar,TAllocator>, TChar>
2081{
2082 using T= strings::TAString<TChar,TAllocator>;
2083 static constexpr Policy Access = Policy::Implicit;
2084 static constexpr Policy Construction = Policy::ExplicitOnly;
2085 static constexpr const TChar* Buffer (const T& src) { return src.Terminate(); }
2086 static constexpr integer Length (const T& src) { return src.Length(); }
2087 static constexpr T Construct(const TChar* b, integer l) { return T().Append(b, l); }
2088};
2089}
2090#endif // !DOXYGEN
2091namespace strings {
2092
2093
2094/// This is a simple utility class that can be used in situations where a #"TAString;AString"
2095/// is intermediately extended and later shortened back to its original length.
2096/// With the use of this class, C++ stack-unwinding is used to ensure that the length is reset
2097/// in all execution paths including exception handling, etc.
2098///
2099/// \see Macro #"ALIB_STRING_RESETTER" which automatically creates a unique identifier for
2100/// the otherwise unused instances of this type.
2101///
2102/// @tparam TChar The character type of the \b %AString that is to be reset.<br>
2103/// @tparam TAllocator The allocator type of the \b %AString, as prototyped with the class
2104/// #"lang::Allocator".
2105template<typename TChar, typename TAllocator>
2107{
2108 protected:
2109 TAString<TChar,TAllocator>& aString; ///< The \b AString to reset.
2110 integer originalLength; ///< The \b The original length of the string.
2111
2112 private:
2113 /// Private new to disallow heap allocation.
2114 /// @return Never called.
2115 void* operator new (size_t);
2116 /// Private new to disallow heap allocation.
2117 /// @return Never called.
2118 void* operator new (size_t, void*);
2119 /// Private new to disallow heap allocation.
2120 /// @return Never called.
2121 void* operator new[](size_t);
2122 /// Private new to disallow heap allocation.
2123 /// @return Never called.
2124 void* operator new[](size_t, void*);
2125 /// Private assignment operator.
2127
2128 public:
2129 /// Constructor taking the string. Stores the current length in field #originalLength.
2130 /// @param pAString The String to take the length of and reset on destruction.
2132 : aString(pAString)
2133 , originalLength(pAString.Length()) {}
2134
2135 /// Destructor. Restores the string's original length.
2137
2138 /// Resets the strings to the original length before destruction of this object.
2139 /// \note With using macro #"ALIB_STRING_RESETTER", this method is not invocable, because
2140 /// the name of the object is not available in this case. But this method is not
2141 /// a true member of the usual use case of this class.
2142 void ResetNow() { aString.ShortenTo(originalLength); }
2143
2144 /// Returns the original length.
2145 /// @return The length of the \b AString when this object was constructed.
2147}; // class TStringLengthResetter
2148
2149}
2150/// Type alias in namespace \b alib.
2152
2153/// Type alias in namespace \b alib.
2155
2156/// Type alias in namespace \b alib.
2158
2159/// Type alias in namespace \b alib.
2161
2162/// Type alias in namespace \b alib.
2164
2165/// Type alias in namespace \b alib.
2167
2168} // namespace [alib::strings]
2169
2170// Note(25/01/17):
2171// Clang strangely did not find the following templated operators when they resided in an
2172// exported namespace.
2173// The workaround was to not export the namespace but export each operator instead.
2174// We think this is wrong behavior and not aligned with the language specification.
2175#if !DOXYGEN
2176namespace alib::strings {
2177
2179template<typename TChar, typename TAllocator>
2180bool operator== (const TAString<TChar, TAllocator>& lhs, const TAString<TChar,TAllocator>& rhs)
2181{ return lhs. template Equals <CHK, lang::Case::Sensitive>(rhs); }
2182
2184template<typename TChar, typename TAllocator, typename T>
2185requires (!std::is_same_v<T, TAString<TChar,TAllocator>>)
2186bool operator== (const TAString<TChar,TAllocator>& lhs, const T& rhs)
2187{ return lhs. template Equals <CHK, lang::Case::Sensitive>(rhs); }
2188
2190template<typename TChar, typename TAllocator>
2192{ return lhs. template CompareTo<CHK, lang::Case::Sensitive>(rhs); }
2193
2195template<typename TChar, typename TAllocator, typename T>
2196requires (!std::same_as<TAString<TChar,TAllocator>, T>)
2197auto operator<=> (const TAString<TChar,TAllocator>& lhs, const T& rhs)
2198{ return lhs. template CompareTo<CHK, lang::Case::Sensitive>(rhs); }
2199
2200} // namespace [alib::strings]
2201#endif // !DOXYGEN
#define ALIB_DLL
Definition alib.inl:573
#define ALIB_ASSERT(cond, domain)
Definition alib.inl:1143
#define ALIB_WARNING(domain,...)
Definition alib.inl:1141
#define ALIB_ERROR(domain,...)
Definition alib.inl:1140
#define ALIB_EXPORT
Definition alib.inl:562
#define ALIB_DBG(...)
Definition alib.inl:931
#define ALIB_ASSERT_ERROR(cond, domain,...)
Definition alib.inl:1144
#define ALIB_DEBUG_STRINGS
Definition alib.inl:56
reverse_iterator rend()
integer TrimAt(integer idx, const TCString< TChar > &trimChars=CStringConstantsTraits< TChar >::DefaultWhitespaces())
TAString & Delete(integer regionStart, integer regionLength=MAX_LEN)
integer SearchAndReplace(TChar needle, TChar replacement, integer startIdx=0, integer endIdx=strings::MAX_LEN)
TAString & ReplaceSubstring(const TString< TChar > &src, integer regionStart, integer regionLength)
TString< TChar > base
The base string-type.
Definition tastring.inl:182
TChar & operator[](integer idx)
Definition tastring.inl:678
constexpr TChar pop_back()
TAString & Append(const TStringSource &src)
constexpr TAString(TAllocator &pAllocator, TChar *extBuffer, integer extBufferSize)
Definition tastring.inl:264
TAString & Append(const TChar *src, integer srcLength)
TAString & InsertAt(const TString< TChar > &src, integer pos)
TAString & Reverse(integer regionStart=0, integer regionLength=MAX_LEN)
constexpr const TChar * Terminate() const
Definition tastring.inl:620
TAString & DeleteEnd(integer regionLength)
TAString & Reset(const TAppendable &src)
void SetBuffer(integer newCapacity)
integer Capacity() const
Definition tastring.inl:588
TAllocator AllocatorType
Exposes the allocator type specified by template parameter TAllocator.
Definition tastring.inl:298
TAString & DeleteEnd(const TString< TChar > &deleteIfMatch)
TAString & DeleteStart(const TString< TChar > &deleteIfMatch)
TAString & InsertChars(TChar c, integer qty)
TAString & Append(characters::IsCharacter auto src)
TAString(TAString &&move) noexcept
Definition tastring.inl:336
TAString & ReplaceRegion(TChar c, integer regionStart, integer regionLength)
TAString & operator+=(const TAppendable &src)
void SetNull()
Invokes #"SetBuffer(integer);SetBuffer(0)".
Definition tastring.inl:605
TAString & DeleteStart(integer regionLength)
integer SearchAndReplace(const TString< TChar > &needle, const TString< TChar > &replacement, integer startIdx=0, integer maxReplacements=strings::MAX_LEN, lang::Case sensitivity=lang::Case::Sensitive, integer endIdx=strings::MAX_LEN)
TAString & ShortenTo(integer newLength)
Definition tastring.inl:747
void SetBuffer(TChar *extBuffer, integer extBufferSize, integer extLength=0, lang::Responsibility responsibility=lang::Responsibility::KeepWithSender)
TAString & ToUpper(integer regionStart=0, integer regionLength=MAX_LEN)
typename base::template TRandomAccessIterator< TChar > iterator
TAString & TrimStart(const TCString< TChar > &trimChars=CStringConstantsTraits< TChar >::DefaultWhitespaces())
TAString & Append(const TString< TChar > &src, integer regionStart, integer regionLength=MAX_LEN)
TAString & ShortenBy(integer charsToRemove)
Definition tastring.inl:765
lang::AllocatorMember< TAllocator > allocBase
The type of the base class that stores the allocator.
Definition tastring.inl:185
constexpr TAString(TAllocator &pAllocator)
Definition tastring.inl:315
TAString & InsertUninitialized(integer pos, integer size)
integer DetectLength(integer offset=0)
Definition tastring.inl:720
TAString & _(const TAppendable &src)
reverse_iterator rbegin()
TChar * VBuffer() const
Definition tastring.inl:637
void GrowBufferAtLeastBy(integer minimumGrowth)
bool HasInternalBuffer() const
Definition tastring.inl:602
TAString & operator<<(const TAppendable &src)
TAString(const TAString &copy)
Definition tastring.inl:323
TAString & ToLower(integer regionStart=0, integer regionLength=MAX_LEN)
TAString & operator=(const TAString &copy)
Definition tastring.inl:464
TAString & InsertChars(TChar c, integer qty, integer pos)
TAString & Append(const TCharSrc *src, integer srcLength)
Definition tastring.inl:788
TAString & _(const TString< TChar > &src, integer regionStart, integer regionLength=MAX_LEN)
constexpr TAString(TChar *extBuffer, integer extBufferSize)
Definition tastring.inl:288
~TAString() noexcept
Destructs an AString object. An internally allocated buffer will be deleted.
Definition tastring.inl:381
TAString & Trim(const TCString< TChar > &trimChars=CStringConstantsTraits< TChar >::DefaultWhitespaces())
TAString(const TAppendable &src)
Definition tastring.inl:376
void EnsureRemainingCapacity(integer spaceNeeded)
Definition tastring.inl:561
constexpr void push_back(TChar ch)
void DbgDisableBufferReplacementWarning()
Definition tastring.inl:241
void SetLength(integer newLength)
Definition tastring.inl:699
TAString & Append(const TAppendable &src)
void SetCharAt(integer idx, TChar c)
Definition tastring.inl:655
TAString & TrimEnd(const TCString< TChar > &trimChars=CStringConstantsTraits< TChar >::DefaultWhitespaces())
std::reverse_iterator< iterator > reverse_iterator
Same as iterator, but working from the end to the start of the string.
TAString & Append(TChar src)
constexpr TAString()
Constructs an empty, nulled AString (does not allocate a buffer).
Definition tastring.inl:304
~TStringLengthResetter()
Destructor. Restores the string's original length.
TStringLengthResetter(TAString< TChar, TAllocator > &pAString)
void operator=(const TStringLengthResetter &)
Private assignment operator.
integer CopyTo(TChar *dest) const
Definition string.inl:1714
const_reverse_iterator rend() const
Definition string.inl:1972
constexpr integer Length() const
Definition string.inl:304
bool EndsWith(const TString &needle) const
Definition string.inl:768
constexpr bool IsNotNull() const
Definition string.inl:343
const_reverse_iterator rbegin() const
Definition string.inl:1968
constexpr bool IsNotEmpty() const
Definition string.inl:357
const_iterator end() const
Definition string.inl:1960
bool AdjustRegion(integer &regionStart, integer &regionLength) const
Definition string.inl:1780
integer IndexOfAny(const TString &needles, integer startIdx=0) const
Definition string.inl:961
constexpr const TChar * Buffer() const
Definition string.inl:299
const_iterator begin() const
Definition string.inl:1952
constexpr TString() noexcept=default
constexpr bool IsNull() const
Definition string.inl:338
bool StartsWith(const TString &needle) const
Definition string.inl:739
integer LastIndexOfAny(const TString &needles, integer startIdx=MAX_LEN) const
Definition string.inl:1001
void Copy(const TChar *src, integer length, TChar *dest)
integer Length(const TChar *cstring)
Definition functions.inl:89
void Reverse(TChar *src, integer length)
std::conditional_t< ArrayTraits< T, nchar >::Access !=Policy::NONE, nchar, std::conditional_t< ArrayTraits< T, wchar >::Access !=Policy::NONE, wchar, std::conditional_t< ArrayTraits< T, xchar >::Access !=Policy::NONE, xchar, void > > > Type
TChar ToUpper(TChar c)
void Move(const TChar *src, integer length, TChar *dest)
std::conditional_t< ZTArrayTraits< T, nchar >::Access !=Policy::NONE, nchar, std::conditional_t< ZTArrayTraits< T, wchar >::Access !=Policy::NONE, wchar, std::conditional_t< ZTArrayTraits< T, xchar >::Access !=Policy::NONE, xchar, void > > > ZTType
void Fill(TChar *dest, integer length, TChar value)
TChar ToLower(TChar c)
Case
Denotes upper and lower case character treatment.
@ KeepWithSender
Keeps responsibility, e.g., when passing an object.
constexpr integer MAX_LEN
The maximum length of an ALib string.
Definition string.inl:51
auto operator<=>(const String &lhs, const String &rhs)
characters::strangeChar strangeChar
Type alias in namespace alib.
characters::complementChar complementChar
Type alias in namespace alib.
lang::HeapAllocator HeapAllocator
Type alias in namespace alib.
strings::TStringLengthResetter< nchar,lang::HeapAllocator > NStringLengthResetter
Type alias in namespace alib.
strings::TAString< nchar, lang::HeapAllocator > NAString
Type alias in namespace alib.
characters::wchar wchar
Type alias in namespace alib.
lang::integer integer
Type alias in namespace alib.
Definition integers.inl:149
strings::TStringLengthResetter< complementChar, lang::HeapAllocator > ComplementStringLengthResetter
Type alias in namespace alib.
strings::TAString< xchar, lang::HeapAllocator > XAString
Type alias in namespace alib.
characters::nchar nchar
Type alias in namespace alib.
strings::TAString< strangeChar, lang::HeapAllocator > StrangeAString
Type alias in namespace alib.
strings::TStringLengthResetter< xchar,lang::HeapAllocator > XStringLengthResetter
Type alias in namespace alib.
characters::xchar xchar
Type alias in namespace alib.
strings::TStringLengthResetter< wchar,lang::HeapAllocator > WStringLengthResetter
Type alias in namespace alib.
strings::TAString< wchar, lang::HeapAllocator > WAString
Type alias in namespace alib.
strings::TStringLengthResetter< strangeChar,lang::HeapAllocator > StrangeStringLengthResetter
Type alias in namespace alib.
strings::TAString< complementChar, lang::HeapAllocator > ComplementAString
Type alias in namespace alib.
strings::TAString< character, lang::HeapAllocator > AString
Type alias in namespace alib.
characters::character character
Type alias in namespace alib.
lang::uinteger uinteger
Type alias in namespace alib.
Definition integers.inl:152
strings::TStringLengthResetter< character,lang::HeapAllocator > StringLengthResetter
Type alias in namespace alib.
#define ALIB_STRING_DBG_CHK(instance)
static constexpr Policy Access
static integer Length(const TStringSource &src)
static TStringSource Construct(const TChar *array, integer length)
static constexpr Policy Construction
static const TChar * Buffer(const TStringSource &src)
static constexpr Policy Construction
static constexpr Policy Access
static const TChar * Buffer(const TStringSource &src)
static TStringSource Construct(const TChar *array, integer length)
static integer Length(const TStringSource &src)
TAllocator & GetAllocator() const noexcept
void operator()(TAString< TChar > &target, const TAppendable &src)
static constexpr CString< TChar > DefaultWhitespaces())
"carriage return" and "tabulator", hence " \n\r\t".
static constexpr CString< TChar > NewLine
Definition cstring.inl:464