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