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