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