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