2020-04-29 22:34:28 +02:00
/*
*
2021-04-28 20:30:34 +02:00
* Created by jief in 1997.
* Copyright ( c ) 2020 Jief
* All rights reserved .
2020-04-29 22:34:28 +02:00
*
2021-04-28 20:30:34 +02:00
*/
2020-04-23 15:20:48 +02:00
# if !defined(__XSTRINGABSTRACT_H__)
# define __XSTRINGABSTRACT_H__
2020-04-24 08:36:29 +02:00
# include <XToolsConf.h>
2020-04-26 12:12:05 +02:00
# include "XToolsCommon.h"
2020-04-23 15:20:48 +02:00
# include "unicode_conversions.h"
# ifndef DEBUG_ALL
# define DEBUG_XStringAbstract 0
# else
2020-04-26 12:12:05 +02:00
# define DEBUG_XStringAbstract DEBUG_ALL
2020-04-23 15:20:48 +02:00
# endif
# if DEBUG_XStringAbstract == 0
# define DBG_XSTRING(...)
# else
# define DBG_XSTRING(...) DebugLog(DEBUG_XStringAbstract, __VA_ARGS__)
# endif
2021-04-08 17:07:05 +02:00
//#define XSTRING_CACHING_OF_SIZE
2020-04-23 15:20:48 +02:00
# define asciiToLower(ch) (((ch >= L'A') && (ch <= L'Z')) ? ((ch - L'A') + L'a') : ch)
2020-04-26 01:54:13 +02:00
# define asciiToUpper(ch) (((ch >= L'a') && (ch <= L'z')) ? ((ch - L'a') + L'A') : ch)
2020-04-23 15:20:48 +02:00
2020-04-26 12:12:05 +02:00
template < typename S , typename O >
int XStringAbstract__startWith ( const S * src , const O * other , bool ignoreCase )
{
size_t nb = 0 ;
const S * src2 = src ;
const O * other2 = other ;
char32_t src_char32 ;
char32_t other_char32 ;
other2 = get_char32_from_string ( other2 , & other_char32 ) ;
if ( ! other_char32 ) return true ; // startWith with empty string is considered true
src2 = get_char32_from_string ( src2 , & src_char32 ) ;
while ( other_char32 ) {
if ( ignoreCase ) {
src_char32 = asciiToLower ( src_char32 ) ;
other_char32 = asciiToLower ( other_char32 ) ;
}
if ( src_char32 ! = other_char32 ) return false ;
src2 = get_char32_from_string ( src2 , & src_char32 ) ;
other2 = get_char32_from_string ( other2 , & other_char32 ) ;
nb + = 1 ;
} ;
return src_char32 ! = 0 ;
}
2021-01-31 10:50:23 +01:00
template < typename S , typename O >
int XStringAbstract__startWithOrEqualTo ( const S * src , const O * other , bool ignoreCase )
{
2022-03-22 19:21:26 +01:00
// size_t nb = 0;
2021-01-31 10:50:23 +01:00
const S * src2 = src ;
const O * other2 = other ;
char32_t src_char32 ;
char32_t other_char32 ;
other2 = get_char32_from_string ( other2 , & other_char32 ) ;
if ( ! other_char32 ) return true ; // startWith with empty string is considered true
src2 = get_char32_from_string ( src2 , & src_char32 ) ;
while ( other_char32 ) {
if ( ignoreCase ) {
src_char32 = asciiToLower ( src_char32 ) ;
other_char32 = asciiToLower ( other_char32 ) ;
}
if ( src_char32 ! = other_char32 ) return false ;
src2 = get_char32_from_string ( src2 , & src_char32 ) ;
other2 = get_char32_from_string ( other2 , & other_char32 ) ;
2022-03-22 19:21:26 +01:00
// nb += 1;
2021-01-31 10:50:23 +01:00
} ;
return true ;
}
2020-08-25 17:35:19 +02:00
/*
* Returns 1 if src > other
*/
2020-04-23 15:20:48 +02:00
template < typename S , typename O >
int XStringAbstract__compare ( const S * src , const O * other , bool ignoreCase )
{
2020-08-25 17:35:19 +02:00
if ( src = = NULL | | * src = = 0 ) return other = = NULL | | * other = = 0 ? 0 : - 1 ;
if ( other = = NULL | | * other = = 0 ) return 1 ;
2020-04-23 15:20:48 +02:00
// size_t len_s = length_of_utf_string(src);
// size_t len_other = length_of_utf_string(other);
size_t nb = 0 ;
const S * src2 = src ;
const O * other2 = other ;
char32_t src_char32 ;
char32_t other_char32 ;
src2 = get_char32_from_string ( src2 , & src_char32 ) ;
other2 = get_char32_from_string ( other2 , & other_char32 ) ;
while ( src_char32 ) {
if ( ignoreCase ) {
src_char32 = asciiToLower ( src_char32 ) ;
other_char32 = asciiToLower ( other_char32 ) ;
}
if ( src_char32 ! = other_char32 ) break ;
src2 = get_char32_from_string ( src2 , & src_char32 ) ;
other2 = get_char32_from_string ( other2 , & other_char32 ) ;
nb + = 1 ;
} ;
if ( src_char32 = = other_char32 ) return 0 ;
return src_char32 > other_char32 ? 1 : - 1 ;
}
2020-04-26 13:52:10 +02:00
template < typename S , typename O >
int XStringAbstract__ncompare ( const S * src , const O * other , size_t n , bool ignoreCase )
{
if ( n = = 0 ) return 0 ; // string of 0 length are equal.
const S * src2 = src ;
const O * other2 = other ;
char32_t src_char32 ;
char32_t other_char32 ;
src2 = get_char32_from_string ( src2 , & src_char32 ) ;
other2 = get_char32_from_string ( other2 , & other_char32 ) ;
size_t nb = 1 ;
while ( src_char32 & & nb < n ) {
if ( ignoreCase ) {
src_char32 = asciiToLower ( src_char32 ) ;
other_char32 = asciiToLower ( other_char32 ) ;
}
if ( src_char32 ! = other_char32 ) break ;
src2 = get_char32_from_string ( src2 , & src_char32 ) ;
other2 = get_char32_from_string ( other2 , & other_char32 ) ;
nb + = 1 ;
} ;
if ( src_char32 = = other_char32 ) return 0 ;
return src_char32 > other_char32 ? 1 : - 1 ;
}
2020-04-23 15:20:48 +02:00
template < typename O , typename P >
size_t XStringAbstract__indexOf ( const O * * s , const P * other , size_t offsetRet , bool toLower )
{
size_t Idx = 0 ;
char32_t s_char32 ;
char32_t other_char32 ;
do
{
const O * s2 = * s ;
const P * other2 = other ;
do {
s2 = get_char32_from_string ( s2 , & s_char32 ) ;
other2 = get_char32_from_string ( other2 , & other_char32 ) ;
if ( toLower ) {
s_char32 = asciiToLower ( s_char32 ) ;
other_char32 = asciiToLower ( other_char32 ) ;
}
} while ( s_char32 & & other_char32 & & s_char32 = = other_char32 ) ;
if ( other_char32 = = 0 ) return Idx + offsetRet ;
* s = get_char32_from_string ( * s , & s_char32 ) ;
Idx + + ;
} while ( s_char32 ) ;
return MAX_XSIZE ;
}
template < typename O , typename P >
size_t XStringAbstract__indexOf ( const O * s , size_t Pos , const P * other , bool toLower )
{
if ( * other = = 0 ) return Pos ;
char32_t char32 = 1 ;
for ( size_t Idx = 0 ; Idx < Pos ; Idx + = 1 ) {
s = get_char32_from_string ( s , & char32 ) ;
}
if ( ! char32 ) return MAX_XSIZE ;
return XStringAbstract__indexOf ( & s , other , Pos , toLower ) ;
}
2020-10-03 19:02:31 +02:00
/*
* Find the last occurence of other , until pos
* NOTE : do not pass SIZE_T_MAX as pos . maximum value is SIZE_T_MAX - 1
*/
2020-04-23 15:20:48 +02:00
template < typename O , typename P >
size_t XStringAbstract__rindexOf ( const O * s , size_t Pos , const P * other , bool toLower )
{
if ( * other = = 0 ) return Pos > length_of_utf_string ( s ) ? length_of_utf_string ( s ) : Pos ;
size_t index = XStringAbstract__indexOf ( & s , other , 0 , toLower ) ;
size_t prev_index = index ; // initialize to index in case of index is already == Pos
char32_t char32 ;
s = get_char32_from_string ( s , & char32 ) ;
while ( char32 & & index < Pos ) {
prev_index = index ;
index = XStringAbstract__indexOf ( & s , other , index + 1 , toLower ) ;
s = get_char32_from_string ( s , & char32 ) ;
} ;
if ( index = = Pos ) return index ;
if ( prev_index < = Pos ) return prev_index ;
return MAX_XSIZE ;
}
template < class T , class ThisXStringClass >
2020-04-29 22:34:28 +02:00
class __String
2020-04-23 15:20:48 +02:00
{
public :
2020-04-29 22:34:28 +02:00
typedef T char_t ;
typedef ThisXStringClass xs_t ;
2020-04-23 15:20:48 +02:00
protected :
2021-04-08 17:07:05 +02:00
T * __m_data ;
protected :
# ifdef XSTRING_CACHING_OF_SIZE
size_t __m_size ;
# endif
2020-04-23 15:20:48 +02:00
// convenience method. Did it this way to avoid #define in header. They can have an impact on other headers
2020-04-25 11:59:07 +02:00
size_t Xmin ( size_t x1 , size_t x2 ) const { if ( x1 < x2 ) return x1 ; return x2 ; }
size_t Xmax ( size_t x1 , size_t x2 ) const { if ( x1 > x2 ) return x1 ; return x2 ; }
2020-04-23 15:20:48 +02:00
2021-04-08 17:07:05 +02:00
# ifdef XSTRING_CACHING_OF_SIZE
# if 1 // if 1, the size will be checked. For debug purpose.
void checkSizeCached ( ) const { // Debug method
if ( size_of_utf_string ( __m_data ) ! = __m_size ) {
panic ( " bug XString " ) ;
}
}
# define XSTRING_CHECK_SIZE __String<T, ThisXStringClass>::checkSizeCached()
# else
# define XSTRING_CHECK_SIZE
# endif
# else
# define XSTRING_CHECK_SIZE
# endif
2020-08-10 13:06:06 +02:00
// Method _data is protected intentionally. It's a const method returning non-const pointer. That's intentional, but dangerous. Do not expose to public.
// If you need a non-const pointer for low-level access, use dataSized and specify the size
// pos is counted in logical char (UTF32 char)
2020-04-23 15:20:48 +02:00
template < typename IntegralType , enable_if ( is_integral ( IntegralType ) ) >
T * _data ( IntegralType pos ) const
{
2021-04-08 17:07:05 +02:00
XSTRING_CHECK_SIZE ;
if ( pos < 0 ) {
2021-05-08 11:34:17 +02:00
log_technical_bug ( " T* data(int i) -> i < 0 " ) ;
2021-04-08 17:07:05 +02:00
return __m_data ;
}
size_t offset = size_of_utf_string_len ( __m_data , ( unsigned_type ( IntegralType ) ) pos ) ; // If pos is too big, size_of_utf_string_len returns the end of the string
return __m_data + offset ;
2020-04-23 15:20:48 +02:00
}
2020-04-29 22:34:28 +02:00
public :
2021-04-08 17:07:05 +02:00
# ifdef XSTRING_CACHING_OF_SIZE
constexpr __String ( const T * s , size_t size ) : __m_data ( ( T * ) s ) , __m_size ( size ) { } // Do NOT call with size != strlen(s). This is for litteral operator, not for public usage.
# else
constexpr __String ( const T * s ) : __m_data ( ( T * ) s ) { }
# endif
2020-04-29 22:34:28 +02:00
// constexpr __String() : m_data(&nullChar) { }
constexpr __String ( const __String & ) = delete ;
constexpr __String ( ) = delete ;
2020-04-23 15:20:48 +02:00
2020-04-29 22:34:28 +02:00
// no assignement, no destructor
2020-04-23 15:20:48 +02:00
2021-05-08 11:34:17 +02:00
constexpr const T * s ( ) const { XSTRING_CHECK_SIZE ; return __m_data ; }
constexpr const T * data ( ) const { XSTRING_CHECK_SIZE ; return __m_data ; }
2020-04-23 15:20:48 +02:00
2021-04-08 17:07:05 +02:00
template < typename IntegralType , enable_if ( is_integral ( IntegralType ) ) >
2021-05-08 11:34:17 +02:00
constexpr const T * data ( IntegralType pos ) const { return _data ( pos ) ; }
2020-04-23 15:20:48 +02:00
2021-01-31 10:50:23 +01:00
2021-04-08 17:07:05 +02:00
size_t length ( ) const { return length_of_utf_string ( data ( ) ) ; } // TODO: caching length
# ifdef XSTRING_CACHING_OF_SIZE
size_t size ( ) const { XSTRING_CHECK_SIZE ; return __m_size ; }
size_t sizeInNativeChars ( ) const { return size ( ) ; }
size_t sizeInBytes ( ) const { return size ( ) * sizeof ( T ) ; }
size_t sizeInBytesIncludingTerminator ( ) const { return ( size ( ) + 1 ) * sizeof ( T ) ; } // usefull for unit tests
# else
size_t size ( ) const { XSTRING_CHECK_SIZE ; return size_of_utf_string ( data ( ) ) ; }
size_t sizeInNativeChars ( ) const { return size_of_utf_string ( data ( ) ) ; }
size_t sizeInBytes ( ) const { return size_of_utf_string ( data ( ) ) * sizeof ( T ) ; }
size_t sizeInBytesIncludingTerminator ( ) const { return ( size_of_utf_string ( data ( ) ) + 1 ) * sizeof ( T ) ; } // usefull for unit tests
# endif
2020-04-23 15:20:48 +02:00
2021-01-31 10:50:23 +01:00
2020-04-23 15:20:48 +02:00
/* Empty ? */
2021-04-08 17:07:05 +02:00
bool isEmpty ( ) const { return data ( ) = = nullptr | | * data ( ) = = 0 ; }
2020-04-23 15:20:48 +02:00
bool notEmpty ( ) const { return ! isEmpty ( ) ; }
//--------------------------------------------------------------------- cast
// int ToInt() const;
// size_t ToUInt() const;
//--------------------------------------------------------------------- charAt, []
template < typename IntegralType , enable_if ( is_integral ( IntegralType ) ) >
char32_t char32At ( IntegralType i ) const
{
if ( i < 0 ) {
2022-01-23 13:19:15 +01:00
# ifdef JIEF_DEBUG
2021-02-21 14:49:09 +01:00
panic ( " __String<T>::char32At(size_t i) : i < 0. System halted \n " ) ;
# else
return 0 ;
# endif
2020-04-23 15:20:48 +02:00
}
size_t nb = 0 ;
2021-04-08 17:07:05 +02:00
const T * p = data ( ) ;
2020-04-23 15:20:48 +02:00
char32_t char32 ;
do {
p = get_char32_from_string ( p , & char32 ) ;
if ( ! char32 ) {
2022-01-23 13:19:15 +01:00
# ifdef JIEF_DEBUG
2021-02-21 14:49:09 +01:00
if ( ( unsigned_type ( IntegralType ) ) i = = nb ) return 0 ; // no panic if we want to access the null terminator
2020-04-29 22:34:28 +02:00
panic ( " __String::char32At(size_t i) : i >= length(). System halted \n " ) ;
2021-02-21 14:49:09 +01:00
# else
return 0 ;
# endif
2020-04-23 15:20:48 +02:00
}
nb + = 1 ;
2020-04-23 22:43:35 +02:00
} while ( nb < = ( unsigned_type ( IntegralType ) ) i ) ;
2020-04-23 15:20:48 +02:00
return char32 ;
}
template < typename IntegralType , enable_if ( is_integral ( IntegralType ) ) >
char16_t char16At ( IntegralType i ) const
{
char32_t char32 = char32At ( i ) ;
if ( char32 > = 0x10000 ) return 0xFFFD ; // <20> REPLACEMENT CHARACTER used to replace an unknown, unrecognized or unrepresentable character
return ( char16_t ) char32 ;
}
/* [] */
template < typename IntegralType , enable_if ( is_integral ( IntegralType ) ) >
char32_t operator [ ] ( IntegralType i ) const { return char32At ( i ) ; }
2020-04-25 11:59:07 +02:00
char32_t lastChar ( ) const { if ( length ( ) > 0 ) return char32At ( length ( ) - 1 ) ; else return 0 ; }
2020-04-29 22:34:28 +02:00
// /* copy ctor */
// __String<T, ThisXStringClass>(const __String<T, ThisXStringClass> &S) { Init(0); takeValueFrom(S); }
// /* ctor */
// template<typename O, class OtherXStringClass>
// explicit __String<T, ThisXStringClass>(const __String<O, OtherXStringClass>& S) { Init(0); takeValueFrom(S); }
//// template<typename O>
//// explicit __String<T, ThisXStringClass>(const O* S) { Init(0); takeValueFrom(S); }
2020-04-23 15:20:48 +02:00
/* Copy Assign */ // Only other XString, no litteral at the moment.
2020-04-29 22:34:28 +02:00
// __String<T, ThisXStringClass>& operator =(const __String<T, ThisXStringClass>& S) { strcpy(S.s()); return *this; }
// /* Assign */
// template<typename O, class OtherXStringClass>
// ThisXStringClass& operator =(const __String<O, OtherXStringClass>& S) { strcpy(S.s()); return *((ThisXStringClass*)this); }
//// template<class O>
//// ThisXStringClass& operator =(const O* S) { strcpy(S); return *this; }
2020-04-23 15:20:48 +02:00
2021-03-25 15:32:56 +01:00
//--------------------------------------------------------------------- indexOf, rindexOf, contains, subString, startWith
2020-04-23 15:20:48 +02:00
/* indexOf */
size_t indexOf ( char32_t char32Searched , size_t Pos = 0 ) const
{
char32_t buf [ 2 ] = { char32Searched , 0 } ;
2021-04-08 17:07:05 +02:00
return XStringAbstract__indexOf ( data ( ) , Pos , buf , false ) ;
2020-04-23 15:20:48 +02:00
}
template < typename O >
2021-04-08 17:07:05 +02:00
size_t indexOf ( const O * S , size_t Pos = 0 ) const { return XStringAbstract__indexOf ( data ( ) , Pos , S , false ) ; }
2020-04-23 15:20:48 +02:00
template < typename O , class OtherXStringClass >
2020-04-29 22:34:28 +02:00
size_t indexOf ( const __String < O , OtherXStringClass > & S , size_t Pos = 0 ) const { return indexOf ( S . s ( ) , Pos ) ; }
2020-04-23 15:20:48 +02:00
/* IC */
size_t indexOfIC ( char32_t char32Searched , size_t Pos = 0 ) const
{
char32_t buf [ 2 ] = { char32Searched , 0 } ;
2021-04-08 17:07:05 +02:00
return XStringAbstract__indexOf ( data ( ) , Pos , buf , true ) ;
2020-04-23 15:20:48 +02:00
}
template < typename O >
2021-04-08 17:07:05 +02:00
size_t indexOfIC ( const O * S , size_t Pos = 0 ) const { return XStringAbstract__indexOf ( data ( ) , Pos , S , true ) ; }
2020-04-23 15:20:48 +02:00
template < typename O , class OtherXStringClass >
2020-04-29 22:34:28 +02:00
size_t indexOfIC ( const __String < O , OtherXStringClass > & S , size_t Pos = 0 ) const { return indexOfIC ( S . s ( ) , Pos ) ; }
2020-04-23 15:20:48 +02:00
/* rindexOf */
size_t rindexOf ( const char32_t char32Searched , size_t Pos = MAX_XSIZE - 1 ) const
{
char32_t buf [ 2 ] = { char32Searched , 0 } ;
2021-04-08 17:07:05 +02:00
return XStringAbstract__rindexOf ( data ( ) , Pos , buf , false ) ;
2020-04-23 15:20:48 +02:00
}
template < typename O >
2021-04-08 17:07:05 +02:00
size_t rindexOf ( const O * S , size_t Pos = MAX_XSIZE - 1 ) const { return XStringAbstract__rindexOf ( data ( ) , Pos , S , false ) ; }
2020-04-23 15:20:48 +02:00
template < typename O , class OtherXStringClass >
2020-04-29 22:34:28 +02:00
size_t rindexOf ( const __String < O , OtherXStringClass > & S , size_t Pos = MAX_XSIZE - 1 ) const { return rindexOf ( S . s ( ) , Pos ) ; }
2020-04-23 15:20:48 +02:00
/* IC */
size_t rindexOfIC ( const char32_t char32Searched , size_t Pos = MAX_XSIZE - 1 ) const
{
char32_t buf [ 2 ] = { char32Searched , 0 } ;
2021-04-08 17:07:05 +02:00
return XStringAbstract__rindexOf ( data ( ) , Pos , buf , true ) ;
2020-04-23 15:20:48 +02:00
}
template < typename O >
2021-04-08 17:07:05 +02:00
size_t rindexOfIC ( const O * S , size_t Pos = MAX_XSIZE - 1 ) const { return XStringAbstract__rindexOf ( data ( ) , Pos , S , true ) ; }
2020-04-23 15:20:48 +02:00
template < typename O , class OtherXStringClass >
2020-04-29 22:34:28 +02:00
size_t rindexOfIC ( const __String < O , OtherXStringClass > & S , size_t Pos = MAX_XSIZE - 1 ) const { return rindexOf ( S . s ( ) , Pos ) ; }
2020-04-23 15:20:48 +02:00
2020-04-26 12:12:05 +02:00
template < typename O , class OtherXStringClass >
2020-04-29 22:34:28 +02:00
bool contains ( const __String < O , OtherXStringClass > & S ) const { return indexOf ( S ) ! = MAX_XSIZE ; }
2020-04-26 12:12:05 +02:00
template < typename O >
bool contains ( const O * S ) const { return indexOf ( S ) ! = MAX_XSIZE ; }
template < typename O , class OtherXStringClass >
2020-04-29 22:34:28 +02:00
size_t containsIC ( const __String < O , OtherXStringClass > & S ) const { return indexOfIC ( S ) ! = MAX_XSIZE ; }
2020-04-26 12:12:05 +02:00
template < typename O >
size_t containsIC ( const O * S ) const { return indexOfIC ( S ) ! = MAX_XSIZE ; }
2020-04-23 15:20:48 +02:00
2020-04-26 12:12:05 +02:00
ThisXStringClass subString ( size_t pos , size_t count ) const
{
2020-04-27 11:50:49 +02:00
// if ( pos > length() ) return ThisXStringClass();
// if ( count > length()-pos ) count = length()-pos;
2020-04-26 12:12:05 +02:00
ThisXStringClass ret ;
2021-04-08 17:07:05 +02:00
const T * src = data ( ) ;
2020-04-26 12:12:05 +02:00
char32_t char32 = 1 ;
while ( char32 & & pos > 0 ) {
src = get_char32_from_string ( src , & char32 ) ;
pos - = 1 ;
} ;
ret . strncat ( src , count ) ;
return ret ;
}
2020-10-03 19:02:31 +02:00
template < typename O , enable_if ( is_char ( O ) ) >
bool startWith ( O otherChar ) const {
O other [ 2 ] = { otherChar , 0 } ;
2021-04-08 17:07:05 +02:00
return XStringAbstract__startWith ( data ( ) , other , false ) ;
2020-10-03 19:02:31 +02:00
}
2020-04-26 12:12:05 +02:00
template < typename O , class OtherXStringClass >
2021-04-08 17:07:05 +02:00
bool startWith ( const __String < O , OtherXStringClass > & otherS ) const { return XStringAbstract__startWith ( data ( ) , otherS . data ( ) , false ) ; }
2020-04-26 12:12:05 +02:00
template < typename O >
2021-04-08 17:07:05 +02:00
bool startWith ( const O * other ) const { return XStringAbstract__startWith ( data ( ) , other , false ) ; }
2020-04-26 12:12:05 +02:00
template < typename O , class OtherXStringClass >
2021-04-08 17:07:05 +02:00
bool startWithIC ( const __String < O , OtherXStringClass > & otherS ) const { return XStringAbstract__startWith ( data ( ) , otherS . data ( ) , true ) ; }
2020-04-26 12:12:05 +02:00
template < typename O >
2021-04-08 17:07:05 +02:00
bool startWithIC ( const O * other ) const { return XStringAbstract__startWith ( data ( ) , other , true ) ; }
2020-04-26 12:12:05 +02:00
2021-01-31 10:50:23 +01:00
template < typename O , enable_if ( is_char ( O ) ) >
bool startWithOrEqualTo ( O otherChar ) const {
O other [ 2 ] = { otherChar , 0 } ;
2021-04-08 17:07:05 +02:00
return XStringAbstract__startWithOrEqualTo ( data ( ) , other , false ) ;
2021-01-31 10:50:23 +01:00
}
template < typename O , class OtherXStringClass >
2021-04-08 17:07:05 +02:00
bool startWithOrEqualTo ( const __String < O , OtherXStringClass > & otherS ) const { return XStringAbstract__startWithOrEqualTo ( data ( ) , otherS . data ( ) , false ) ; }
2021-01-31 10:50:23 +01:00
template < typename O >
2021-04-08 17:07:05 +02:00
bool startWithOrEqualTo ( const O * other ) const { return XStringAbstract__startWithOrEqualTo ( data ( ) , other , false ) ; }
2021-01-31 10:50:23 +01:00
template < typename O , class OtherXStringClass >
2021-04-08 17:07:05 +02:00
bool startWithOrEqualToIC ( const __String < O , OtherXStringClass > & otherS ) const { return XStringAbstract__startWithOrEqualTo ( data ( ) , otherS . data ( ) , true ) ; }
2021-01-31 10:50:23 +01:00
template < typename O >
2021-04-08 17:07:05 +02:00
bool startWithOrEqualToIC ( const O * other ) const { return XStringAbstract__startWithOrEqualTo ( data ( ) , other , true ) ; }
2021-01-31 10:50:23 +01:00
2021-04-06 15:39:55 +02:00
template < typename O , class OtherXStringClass >
2021-04-08 17:07:05 +02:00
bool endWithOrEqualToIC ( const __String < O , OtherXStringClass > & otherS ) const { if ( length ( ) < otherS . length ( ) ) return false ; return XStringAbstract__rindexOf ( data ( ) , SIZE_T_MAX - 1 , otherS . data ( ) , true ) = = length ( ) - otherS . length ( ) ; }
2021-04-06 15:39:55 +02:00
2020-04-27 11:50:49 +02:00
//---------------------------------------------------------------------
ThisXStringClass basename ( ) const
{
size_t lastSepPos = MAX_XSIZE ;
size_t pos = 0 ;
2021-04-08 17:07:05 +02:00
const T * p = data ( ) ;
2020-04-27 11:50:49 +02:00
char32_t char32 ;
p = get_char32_from_string ( p , & char32 ) ;
while ( char32 ) {
if ( char32 = = U ' / ' | | char32 = = U ' \\ ' ) lastSepPos = pos ;
pos + = 1 ;
p = get_char32_from_string ( p , & char32 ) ;
} ;
if ( lastSepPos = = MAX_XSIZE ) {
2021-04-08 17:07:05 +02:00
if ( p = = data ( ) ) return ThisXStringClass ( ) . takeValueFrom ( " . " ) ;
2020-04-27 11:50:49 +02:00
}
return subString ( lastSepPos + 1 , MAX_XSIZE ) ;
}
2021-01-22 09:35:57 +01:00
ThisXStringClass dirname ( ) const
{
size_t idx ;
idx = rindexOf ( ' \\ ' ) ;
if ( idx ! = MAX_XSIZE ) return subString ( 0 , idx ) ;
idx = rindexOf ( ' / ' ) ;
if ( idx ! = MAX_XSIZE ) return subString ( 0 , idx ) ;
return ThisXStringClass ( ) ;
}
2020-04-27 11:50:49 +02:00
2020-04-23 15:20:48 +02:00
// bool IsDigits(size_t pos, size_t count) const;
//{
// const T *p;
// const T *q;
//
// if ( pos >= size() ) {
// return false;
// }
// if ( pos+count > size() ) {
// return false;
// }
// p = data() + pos;
// q = p + count;
// for ( ; p < q ; p+=1 ) {
// if ( *p < '0' ) return false;
// if ( *p > '9' ) return false;
// }
// return true;
//}
2021-03-25 15:32:56 +01:00
//--------------------------------------------------------------------- strcmp, equal, comparison operator
2020-04-23 15:20:48 +02:00
template < typename O >
2021-04-08 17:07:05 +02:00
int strcmp ( const O * S ) const { return XStringAbstract__compare ( data ( ) , S , false ) ; }
// int Compare(const char* S) const { return ::Compare<T, char>(data(), S); }
// int Compare(const char16_t* S) const { return ::Compare<T, char16_t>(data(), S); };
// int Compare(const char32_t* S) const { return ::Compare<T, char32_t>(data(), S); };
// int Compare(const wchar_t* S) const { return ::Compare<T, wchar_t>(data(), S); };
2020-04-23 15:20:48 +02:00
//
2020-08-22 15:39:24 +02:00
template < typename O >
2021-04-08 17:07:05 +02:00
int strncmp ( const O * S , size_t n ) const { return XStringAbstract__ncompare ( data ( ) , S , n , false ) ; }
2020-08-22 15:39:24 +02:00
2020-04-26 15:07:30 +02:00
template < typename O , class OtherXStringClass >
2021-04-11 07:18:52 +02:00
bool isEqual ( const __String < O , OtherXStringClass > & S ) const { return XStringAbstract__compare ( data ( ) , S . s ( ) , false ) = = 0 ; }
2020-04-26 15:07:30 +02:00
template < typename O >
2021-04-11 07:18:52 +02:00
bool isEqual ( const O * S ) const { return XStringAbstract__compare ( data ( ) , S , false ) = = 0 ; }
2020-04-26 15:07:30 +02:00
2020-04-23 15:20:48 +02:00
template < typename O , class OtherXStringClass >
2021-04-11 07:18:52 +02:00
bool isEqualIC ( const __String < O , OtherXStringClass > & S ) const { return XStringAbstract__compare ( data ( ) , S . s ( ) , true ) = = 0 ; }
2020-04-23 15:20:48 +02:00
template < typename O >
2021-04-11 07:18:52 +02:00
bool isEqualIC ( const O * S ) const { return XStringAbstract__compare ( data ( ) , S , true ) = = 0 ; }
2020-04-26 15:07:30 +02:00
2020-04-23 15:20:48 +02:00
// bool SubStringEqual(size_t Pos, const T* S) const { return (memcmp(data(Pos), S, wcslen(S)) == 0); }
2021-02-04 15:04:31 +01:00
template < typename IntegralType , typename O , class OtherXStringClass >
2021-04-11 07:18:52 +02:00
bool isEqualAtIC ( IntegralType pos , const __String < O , OtherXStringClass > & S ) const
2021-02-04 15:04:31 +01:00
{
2021-02-21 14:49:09 +01:00
2022-01-23 13:19:15 +01:00
# ifdef JIEF_DEBUG
2021-02-04 15:04:31 +01:00
if ( pos < 0 ) panic ( " XString::equalAtIC -> i < 0 " ) ;
2021-02-21 14:49:09 +01:00
# else
if ( pos < 0 ) return false ;
# endif
2021-02-04 15:04:31 +01:00
if ( ( unsigned_type ( IntegralType ) ) pos > length ( ) - S . length ( ) ) return false ;
2021-04-08 17:07:05 +02:00
return XStringAbstract__ncompare ( data ( ) + ( unsigned_type ( IntegralType ) ) pos , S . s ( ) , S . length ( ) , true ) = = 0 ;
2021-02-04 15:04:31 +01:00
}
2020-04-23 15:20:48 +02:00
public :
// == operator
template < typename O , class OtherXStringClass >
2020-04-29 22:34:28 +02:00
bool operator = = ( const __String < O , OtherXStringClass > & s2 ) const { return ( * this ) . strcmp ( s2 . s ( ) ) = = 0 ; }
2020-04-24 11:30:09 +02:00
// template<typename O>
// bool operator == (const O* s2) const { return (*this).strcmp(s2) == 0; }
// template<typename O>
// friend bool operator == (const O* s1, ThisXStringClass& s2) { return s2.strcmp(s1) == 0; }
2020-04-23 15:20:48 +02:00
template < typename O , class OtherXStringClass >
2020-04-29 22:34:28 +02:00
bool operator ! = ( const __String < O , OtherXStringClass > & s2 ) const { return ! ( * this = = s2 ) ; }
2020-04-24 11:30:09 +02:00
// template<typename O>
// bool operator != (const O* s2) const { return !(*this == s2); }
// template<typename O>
// friend bool operator != (const O* s1, const ThisXStringClass& s2) { return s2.strcmp(s1) != 0; }
2020-04-23 15:20:48 +02:00
template < typename O , class OtherXStringClass >
2020-04-29 22:34:28 +02:00
bool operator < ( const __String < O , OtherXStringClass > & s2 ) const { return ( * this ) . strcmp ( s2 . s ( ) ) < 0 ; }
2020-04-24 11:30:09 +02:00
// template<typename O>
// bool operator < (const O* s2) const { return (*this).strcmp(s2) < 0; }
// template<typename O>
// friend bool operator < (const O* s1, const ThisXStringClass& s2) { return s2.strcmp(s1) > 0; }
2020-04-23 15:20:48 +02:00
template < typename O , class OtherXStringClass >
2020-04-29 22:34:28 +02:00
bool operator > ( const __String < O , OtherXStringClass > & s2 ) const { return ( * this ) . strcmp ( s2 . s ( ) ) > 0 ; }
2020-04-24 11:30:09 +02:00
// template<typename O>
// bool operator > (const O* s2) const { return (*this).strcmp(s2) > 0; }
// template<typename O>
// friend bool operator > (const O* s1, const ThisXStringClass& s2) { return s2.strcmp(s1) < 0; }
2020-04-23 15:20:48 +02:00
template < typename O , class OtherXStringClass >
2020-04-29 22:34:28 +02:00
bool operator < = ( const __String < O , OtherXStringClass > & s2 ) const { return ( * this ) . strcmp ( s2 . s ( ) ) < = 0 ; }
2020-04-24 11:30:09 +02:00
// template<typename O>
// bool operator <= (const O* s2) const { return (*this).strcmp(s2) <= 0; }
// template<typename O>
// friend bool operator <= (const O* s1, const ThisXStringClass& s2) { return s2.strcmp(s1) >= 0; }
2020-04-23 15:20:48 +02:00
template < typename O , class OtherXStringClass >
2020-04-29 22:34:28 +02:00
bool operator > = ( const __String < O , OtherXStringClass > & s2 ) const { return ( * this ) . strcmp ( s2 . s ( ) ) > = 0 ; }
2020-04-24 11:30:09 +02:00
// template<typename O>
// bool operator >= (const O* s2) const { return (*this).strcmp(s2) >= 0; }
// template<typename O>
// friend bool operator >= (const O* s1, const ThisXStringClass& s2) { return s2.strcmp(s1) <= 0; }
2020-04-23 15:20:48 +02:00
} ;
2021-02-04 15:04:31 +01:00
//xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx LString xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
2020-04-29 22:34:28 +02:00
2020-04-23 15:20:48 +02:00
template < class T , class ThisXStringClass >
2020-04-29 22:34:28 +02:00
class LString : public __String < T , ThisXStringClass >
{
public :
protected :
2021-04-08 17:07:05 +02:00
# ifdef XSTRING_CACHING_OF_SIZE
constexpr LString ( const T * s ) : __String < T , ThisXStringClass > ( s , 0 ) { } ;
constexpr LString ( const T * s , size_t size ) : __String < T , ThisXStringClass > ( s , size ) { } ;
constexpr LString ( const LString & L ) : __String < T , ThisXStringClass > ( L . data ( ) , L . size ( ) ) { } ;
# else
2020-04-29 22:34:28 +02:00
constexpr LString ( const T * s ) : __String < T , ThisXStringClass > ( s ) { } ;
2021-04-08 17:07:05 +02:00
constexpr LString ( const LString & L ) : __String < T , ThisXStringClass > ( L . data ( ) ) { } ;
# endif
2020-04-29 22:34:28 +02:00
constexpr LString ( ) = delete ;
// no assignement, no destructor
} ;
//xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
2020-04-23 15:20:48 +02:00
2020-08-16 15:21:12 +02:00
///* __String + char32_t */
//template<typename CharType1, class XStringClass1>
//XStringClass1 operator + (const __String<CharType1, XStringClass1>& p1, char32_t p2) { XStringClass1 s; s.takeValueFrom(p1); s.strcat(p2); return s; }
//
///* __String + __String */
//template<typename CharType1, class XStringClass1, typename CharType2, class XStringClass2>
//XStringClass1 operator + (const __String<CharType1, XStringClass1>& p1, const __String<CharType2, XStringClass2>& p2) { XStringClass1 s; s.takeValueFrom(p1); s.strcat(p2); return s; }
//
///* char* + __String */
//template<typename CharType1, typename CharType2, class XStringClass2>
//XStringClass2 operator + (const CharType1* p1, const __String<CharType2, XStringClass2>& p2) { XStringClass2 s; s.takeValueFrom(p1); s.strcat(p2); return s; }
//
///* __String + char* */
//template<typename T1, class XStringClass1, typename CharType2>
//XStringClass1 operator + (const __String<T1, XStringClass1>& p1, const CharType2* p2) { XStringClass1 s; s.takeValueFrom(p1); s.strcat(p2); return s; }
template < typename Base > _xtools__true_type is_base_of_test_func ( Base * ) ;
template < typename Base > _xtools__false_type is_base_of_test_func ( void * ) ;
template < typename B , typename D >
auto test_pre_is_base_of ( int ) - > decltype ( is_base_of_test_func < B > ( static_cast < D * > ( nullptr ) ) ) ;
template < class , class = _xtools__void_t < > , class = _xtools__void_t < > >
struct __string_type { typedef void type ; } ;
template < typename T >
struct __string_type < T , _xtools__void_t < typename T : : xs_t > , _xtools__void_t < typename T : : char_t > > { typedef __String < typename T : : char_t , typename T : : xs_t > type ; } ;
# define is___String_t(x) decltype(test_pre_is_base_of<typename __string_type<x>::type , x>(0))
# define is___String(x) is___String_t(x)::value
template < class , class = _xtools__void_t < > , class = _xtools__void_t < > >
struct __lstring_type { typedef void type ; } ;
template < typename T >
struct __lstring_type < T , _xtools__void_t < typename T : : xs_t > , _xtools__void_t < typename T : : char_t > > { typedef LString < typename T : : char_t , typename T : : xs_t > type ; } ;
# define is___LString_t(x) decltype(test_pre_is_base_of< typename __lstring_type<x>::type , x>(0))
# define is___LString(x) is___LString_t(x)::value
/* __string_class_or<T1, T2>::type is T1 is T1 is a subclass of __String. If T1 is not a subclass of __String, returns T2 if it's a subclass of __String */
template < typename T1 , typename T2 , typename Tdummy = void >
struct __string_class_or ;
template < typename T1 , typename T2 >
struct __string_class_or < T1 , T2 , enable_if_t ( ! is___String ( T1 ) & & ! is___String ( T2 ) ) > { /*typedef double type;*/ } ;
template < typename T1 , typename T2 >
struct __string_class_or < T1 , T2 , enable_if_t ( is___String ( T1 ) ) > { typedef typename T1 : : xs_t type ; } ;
template < typename T1 , typename T2 >
struct __string_class_or < T1 , T2 , enable_if_t ( ! is___String ( T1 ) & & is___String ( T2 ) ) > { typedef typename T2 : : xs_t type ; } ;
2021-02-04 15:04:31 +01:00
/* ------------ get_char_ptr(x) --------------*/
template < typename T , typename Tdummy = void >
struct _xstringarray__char_type ;
template < typename T >
struct _xstringarray__char_type < T , enable_if_t ( is___String ( T ) ) >
{
static const typename T : : char_t * getCharPtr ( const T & t ) { return t . s ( ) ; }
} ;
template < typename T >
struct _xstringarray__char_type < T * , enable_if_t ( is_char ( T ) ) >
{
static const T * getCharPtr ( T * t ) { return t ; }
} ;
//template<typename T>
//struct _xstringarray__char_type<const T*, enable_if_t(is_char(T))>
//{
// static const T* getCharPtr(const T* t) { return t; }
//};
template < typename T >
struct _xstringarray__char_type < const T [ ] >
{
static const T * getCharPtr ( T * t ) { return t ; }
} ;
template < typename T , size_t _Np >
struct _xstringarray__char_type < T [ _Np ] >
{
static const T * getCharPtr ( const T * t ) { return t ; }
} ;
# ifdef _MSC_VER
// I don't know why it's needed with VS.
template < typename T >
struct _xstringarray__char_type < T , enable_if_t ( is___LString ( T ) ) >
{
static const typename T : : char_t * getCharPtr ( const T & t ) { return t . s ( ) ; }
} ;
# endif
# define get_char_ptr(x) _xstringarray__char_type<typeof(x)>::getCharPtr(x)
2020-08-16 15:21:12 +02:00
//xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
2021-04-08 17:07:05 +02:00
//#define data() super::data()
2020-04-29 22:34:28 +02:00
2020-04-27 11:50:49 +02:00
template < class T , class ThisXStringClass >
2020-04-29 22:34:28 +02:00
class XStringAbstract : public __String < T , ThisXStringClass >
2020-04-27 11:50:49 +02:00
{
2021-04-08 17:07:05 +02:00
using super = __String < T , ThisXStringClass > ;
2020-04-29 22:34:28 +02:00
static T nullChar ;
2020-04-27 11:50:49 +02:00
2020-04-29 22:34:28 +02:00
protected :
2020-08-10 13:06:06 +02:00
size_t m_allocatedSize ; // Must include null terminator. Real memory allocated is only m_allocatedSize (not m_allocatedSize+1)
2020-04-29 22:34:28 +02:00
//xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
// Init , Alloc
//xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
/*
2020-08-10 13:06:06 +02:00
* nNewSize must include null terminator .
2020-04-29 22:34:28 +02:00
*/
2021-04-08 17:07:05 +02:00
void Alloc ( size_t nNewAllocatedSize )
2020-04-29 22:34:28 +02:00
{
2020-08-15 15:47:56 +02:00
if ( m_allocatedSize = = 0 ) {
2021-04-08 17:07:05 +02:00
super : : __m_data = ( T * ) malloc ( nNewAllocatedSize * sizeof ( T ) ) ;
2020-08-15 15:47:56 +02:00
}
else {
2021-04-08 17:07:05 +02:00
super : : __m_data = ( T * ) Xrealloc ( super : : __m_data , nNewAllocatedSize * sizeof ( T ) , m_allocatedSize * sizeof ( T ) ) ;
2020-08-15 15:47:56 +02:00
}
2021-04-08 17:07:05 +02:00
if ( ! super : : __m_data ) {
2021-05-08 11:34:17 +02:00
log_technical_bug ( " XStringAbstract::Alloc(%zu) : Xrealloc(% " PRIuPTR " , %lu, %zd) returned NULL. System halted \n " , nNewAllocatedSize , uintptr_t ( super : : __m_data ) , nNewAllocatedSize * sizeof ( T ) , m_allocatedSize * sizeof ( T ) ) ;
2021-02-21 14:49:09 +01:00
m_allocatedSize = 0 ;
return ;
2020-04-29 22:34:28 +02:00
}
2021-04-08 17:07:05 +02:00
m_allocatedSize = nNewAllocatedSize ;
2020-04-29 22:34:28 +02:00
}
2020-08-10 13:06:06 +02:00
2020-04-29 22:34:28 +02:00
// public:
2020-08-10 13:06:06 +02:00
/*
* Make sure this string has allocated size of at least nNewSize + 1.
*/
2021-04-08 17:07:05 +02:00
bool CheckSize ( size_t nNewAllocatedSize , size_t nGrowBy = XStringGrowByDefault ) // nNewSize is in number of chars, NOT bytes
2020-04-29 22:34:28 +02:00
{
//DBG_XSTRING("CheckSize: m_size=%d, nNewSize=%d\n", m_size, nNewSize);
2021-04-08 17:07:05 +02:00
if ( m_allocatedSize < nNewAllocatedSize + 1 )
2020-04-29 22:34:28 +02:00
{
2021-04-08 17:07:05 +02:00
nNewAllocatedSize + = nGrowBy ;
if ( m_allocatedSize = = 0 ) { //if ( *data() ) {
// Even if m_allocatedSize == 0, data() might not be NULL because it can points to a litteral.
// So we need to alloc and cpy the litteral in the newly allocated buffer.
size_t size = super : : size ( ) ;
if ( nNewAllocatedSize < size ) nNewAllocatedSize = size ;
const T * m_dataSav = super : : data ( ) ;
//super::__m_data = NULL; // No need, Alloc will reassign it.
Alloc ( nNewAllocatedSize + 1 ) ;
utf_string_from_utf_string ( super : : __m_data , m_allocatedSize , m_dataSav ) ;
2020-08-15 15:47:56 +02:00
return true ;
2020-04-29 22:34:28 +02:00
} else {
2021-04-08 17:07:05 +02:00
Alloc ( nNewAllocatedSize + 1 ) ;
2020-08-15 15:47:56 +02:00
return true ;
2020-04-29 22:34:28 +02:00
}
2020-08-15 15:47:56 +02:00
}
return false ;
2020-04-29 22:34:28 +02:00
}
2020-08-10 13:06:06 +02:00
public :
2020-04-29 22:34:28 +02:00
/* default ctor */
2021-04-08 17:07:05 +02:00
# ifdef XSTRING_CACHING_OF_SIZE
XStringAbstract ( ) : __String < T , ThisXStringClass > ( & nullChar , 0 ) , m_allocatedSize ( 0 ) { }
# else
2020-04-29 22:34:28 +02:00
XStringAbstract ( ) : __String < T , ThisXStringClass > ( & nullChar ) , m_allocatedSize ( 0 ) { }
2021-04-08 17:07:05 +02:00
# endif
2020-04-29 22:34:28 +02:00
/* copy ctor */
2021-04-08 17:07:05 +02:00
# ifdef XSTRING_CACHING_OF_SIZE
XStringAbstract ( const XStringAbstract & S ) : __String < T , ThisXStringClass > ( & nullChar , 0 ) , m_allocatedSize ( 0 )
# else
2020-04-29 22:34:28 +02:00
XStringAbstract ( const XStringAbstract & S ) : __String < T , ThisXStringClass > ( & nullChar ) , m_allocatedSize ( 0 )
2021-04-08 17:07:05 +02:00
# endif
2020-04-29 22:34:28 +02:00
{
2021-04-08 17:07:05 +02:00
* this = S ;
2020-04-29 22:34:28 +02:00
}
2020-04-27 11:50:49 +02:00
~ XStringAbstract ( )
{
//DBG_XSTRING("Destructor :%ls\n", data());
2021-04-08 17:07:05 +02:00
if ( m_allocatedSize > 0 ) free ( ( void * ) super : : __m_data ) ;
2020-04-29 22:34:28 +02:00
}
2021-04-08 17:07:05 +02:00
# ifdef XSTRING_CACHING_OF_SIZE
/* ctor */
template < class OtherLStringClass >
explicit XStringAbstract ( const LString < T , OtherLStringClass > & S ) : __String < T , ThisXStringClass > ( S . s ( ) , S . size ( ) ) , m_allocatedSize ( 0 ) { }
template < typename O , class OtherXStringClass >
explicit XStringAbstract < T , ThisXStringClass > ( const XStringAbstract < O , OtherXStringClass > & S ) : __String < T , ThisXStringClass > ( & nullChar , 0 ) , m_allocatedSize ( 0 ) { takeValueFrom ( S ) ; }
template < typename O , class OtherXStringClass >
explicit XStringAbstract < T , ThisXStringClass > ( const LString < O , OtherXStringClass > & S ) : __String < T , ThisXStringClass > ( & nullChar ) , m_allocatedSize ( 0 ) { takeValueFrom ( S ) ; }
// TEMPORARILY DISABLED
// template<typename O>
// explicit __String<T, ThisXStringClass>(const O* S) { Init(0); takeValueFrom(S); }
//
# else
2020-04-29 22:34:28 +02:00
/* ctor */
template < class OtherLStringClass >
explicit XStringAbstract ( const LString < T , OtherLStringClass > & S ) : __String < T , ThisXStringClass > ( S . s ( ) ) , m_allocatedSize ( 0 ) { }
template < typename O , class OtherXStringClass >
explicit XStringAbstract < T , ThisXStringClass > ( const XStringAbstract < O , OtherXStringClass > & S ) : __String < T , ThisXStringClass > ( & nullChar ) , m_allocatedSize ( 0 ) { takeValueFrom ( S ) ; }
template < typename O , class OtherXStringClass >
explicit XStringAbstract < T , ThisXStringClass > ( const LString < O , OtherXStringClass > & S ) : __String < T , ThisXStringClass > ( & nullChar ) , m_allocatedSize ( 0 ) { takeValueFrom ( S ) ; }
// TEMPORARILY DISABLED
// template<typename O>
// explicit __String<T, ThisXStringClass>(const O* S) { Init(0); takeValueFrom(S); }
//
2021-04-08 17:07:05 +02:00
# endif
/* Copy Assign */
XStringAbstract & operator = ( const XStringAbstract & S ) {
if ( S . data ( ) & & S . m_allocatedSize = = 0 ) {
// S points to a litteral
if ( m_allocatedSize > 0 ) {
delete super : : __m_data ;
m_allocatedSize = 0 ;
}
super : : __m_data = ( T * ) S . data ( ) ; // because it's a litteral, we don't copy. We need to cast, but we won't modify.
# ifdef XSTRING_CACHING_OF_SIZE
super : : __m_size = S . size ( ) ;
# endif
} else {
strsicpy ( S . s ( ) , S . size ( ) ) ;
}
return * this ;
}
2020-04-29 22:34:28 +02:00
/* Assign */
2020-11-02 14:45:11 +01:00
# ifndef _MSC_VER
2020-08-25 17:35:19 +02:00
# pragma GCC diagnostic push
2020-08-11 14:43:53 +02:00
# pragma GCC diagnostic ignored "-Weffc++"
2020-11-02 14:45:11 +01:00
# endif
2020-04-29 22:34:28 +02:00
template < typename O , class OtherXStringClass >
ThisXStringClass & operator = ( const __String < O , OtherXStringClass > & S ) { strcpy ( S . s ( ) ) ; return * ( ( ThisXStringClass * ) this ) ; }
2020-11-02 14:45:11 +01:00
# ifndef _MSC_VER
2020-08-25 17:35:19 +02:00
# pragma GCC diagnostic pop
2020-11-02 14:45:11 +01:00
# endif
2021-04-08 17:07:05 +02:00
2020-04-29 22:34:28 +02:00
// TEMPORARILY DISABLED
// template<class O>
// ThisXStringClass& operator =(const O* S) { strcpy(S); return *this; }
protected :
2021-04-08 17:07:05 +02:00
// ThisXStringClass& takeValueFromLiteral(const T* s)
// {
// if ( m_allocatedSize > 0 ) {
// panic_ask("XStringAbstract::takeValueFromLiteral -> m_allocatedSize > 0");
// }
// super::__m_data = (T*)s;
//#ifdef XSTRING_CACHING_OF_SIZE
// super::__m_size = strlen(s);
//#endif
// return *((ThisXStringClass*)this);
// }
2020-04-29 22:34:28 +02:00
public :
size_t allocatedSize ( ) const { return m_allocatedSize ; }
void setEmpty ( )
{
2021-04-08 17:07:05 +02:00
if ( m_allocatedSize < = 0 ) super : : __m_data = & nullChar ;
else super : : __m_data [ 0 ] = 0 ;
# ifdef XSTRING_CACHING_OF_SIZE
super : : __m_size = 0 ;
# endif
2020-04-29 22:34:28 +02:00
}
2021-04-08 17:07:05 +02:00
// T* data() { return data(); }
const T * data ( ) const { return super : : data ( ) ; }
2020-08-15 15:47:56 +02:00
template < typename IntegralType , enable_if ( is_integral ( IntegralType ) ) >
2021-04-08 17:07:05 +02:00
const T * data ( IntegralType pos ) const { return super : : _data ( pos ) ; }
// template<typename IntegralType, enable_if(is_integral(IntegralType))>
// T* data(IntegralType pos) { return super::_data(pos); }
2020-04-29 22:34:28 +02:00
template < typename IntegralType , enable_if ( is_integral ( IntegralType ) ) >
T * dataSized ( IntegralType size )
{
2021-04-08 17:07:05 +02:00
if ( size < 0 ) {
2021-05-08 11:34:17 +02:00
log_technical_bug ( " T* dataSized() -> i < 0 " ) ;
2021-04-08 17:07:05 +02:00
return NULL ;
}
if ( ( unsigned_type ( IntegralType ) ) size > MAX_XSIZE ) {
2021-05-08 11:34:17 +02:00
log_technical_bug ( " T* dataSized() -> i > MAX_XSIZE " ) ;
2021-04-08 17:07:05 +02:00
return NULL ;
}
CheckSize ( ( unsigned_type ( IntegralType ) ) size , 0 ) ;
return super : : _data ( 0 ) ;
2020-04-29 22:34:28 +02:00
}
2021-04-08 17:07:05 +02:00
void updateSize ( ) {
# ifdef XSTRING_CACHING_OF_SIZE
2021-07-02 17:10:10 +02:00
super : : __m_size = 0 ; // Jief, TODO
2021-04-08 17:07:05 +02:00
# endif
}
2020-04-29 22:34:28 +02:00
//
// // Pos is counted in logical char but size is counted in physical char (char, char16_t, char32_t or wchar_t)
// template<typename IntegralType1, typename IntegralType2, enable_if(is_integral(IntegralType1) && is_integral(IntegralType2))>
// T* dataSized(IntegralType1 pos, IntegralType2 size)
// {
// if ( pos<0 ) panic("T* dataSized(xisize i, size_t sizeMin, size_t nGrowBy) -> i < 0");
// if ( size<0 ) panic("T* dataSized(xisize i, size_t sizeMin, size_t nGrowBy) -> i < 0");
2021-04-08 17:07:05 +02:00
// size_t offset = size_of_utf_string_len(data(), (typename _xtools__make_unsigned<IntegralType1>::type)pos); // If pos is too big, size_of_utf_string_len returns the end of the string
2020-04-29 22:34:28 +02:00
// CheckSize(offset + (typename _xtools__make_unsigned<IntegralType2>::type)size);
// return _data(pos);
// }
T * forgetDataWithoutFreeing ( )
{
2021-04-08 17:07:05 +02:00
T * ret = super : : __m_data ;
super : : __m_data = & nullChar ;
# ifdef XSTRING_CACHING_OF_SIZE
super : : __m_size = 0 ;
# endif
2020-04-29 22:34:28 +02:00
m_allocatedSize = 0 ;
return ret ;
}
//--------------------------------------------------------------------- strcat, strcpy, operator =
/* strcpy char */
template < typename O , enable_if ( is_char ( O ) ) >
void strcpy ( O otherChar )
{
if ( otherChar ! = 0 ) {
2021-04-08 17:07:05 +02:00
size_t newSize = utf_size_of_utf_string_len ( data ( ) , & otherChar , 1 ) ;
2020-08-10 13:06:06 +02:00
CheckSize ( newSize , 0 ) ;
2021-04-08 17:07:05 +02:00
utf_string_from_utf_string_len ( super : : __m_data , m_allocatedSize , & otherChar , 1 ) ;
super : : __m_data [ newSize ] = 0 ;
# ifdef XSTRING_CACHING_OF_SIZE
super : : __m_size = newSize ;
# endif
2020-04-29 22:34:28 +02:00
} else {
setEmpty ( ) ;
}
}
/* strcpy */
template < typename O >
void strcpy ( const O * other )
{
if ( other & & * other ) {
2021-04-08 17:07:05 +02:00
size_t newSize = utf_size_of_utf_string ( data ( ) , other ) ;
2020-08-10 13:06:06 +02:00
CheckSize ( newSize , 0 ) ;
2021-04-08 17:07:05 +02:00
utf_string_from_utf_string ( super : : __m_data , m_allocatedSize , other ) ;
super : : __m_data [ newSize ] = 0 ;
# ifdef XSTRING_CACHING_OF_SIZE
super : : __m_size = newSize ;
XSTRING_CHECK_SIZE ;
# endif
2020-04-29 22:34:28 +02:00
} else {
setEmpty ( ) ;
}
2020-04-27 11:50:49 +02:00
}
2020-04-29 22:34:28 +02:00
/* strncpy */
template < typename O >
void strncpy ( const O * other , size_t other_len )
{
if ( other & & * other & & other_len > 0 ) {
2021-04-08 17:07:05 +02:00
size_t newSize = utf_size_of_utf_string_len ( data ( ) , other , other_len ) ;
2020-08-10 13:06:06 +02:00
CheckSize ( newSize , 0 ) ;
2021-04-08 17:07:05 +02:00
utf_string_from_utf_string_len ( super : : __m_data , m_allocatedSize , other , other_len ) ;
super : : __m_data [ newSize ] = 0 ;
# ifdef XSTRING_CACHING_OF_SIZE
super : : __m_size = newSize ;
XSTRING_CHECK_SIZE ;
# endif
2020-04-29 22:34:28 +02:00
} else {
setEmpty ( ) ;
}
}
2021-04-01 10:06:53 +02:00
template < typename O >
void strsicpy ( const O * other , size_t other_size )
{
if ( other & & * other & & other_size > 0 ) {
CheckSize ( other_size , 0 ) ;
2021-04-08 17:07:05 +02:00
utf_string_from_utf_string_size ( super : : __m_data , m_allocatedSize , other , other_size ) ; // TODO:utf_string_from_utf_string_SIZE
super : : __m_data [ other_size ] = 0 ;
# ifdef XSTRING_CACHING_OF_SIZE
super : : __m_size = other_size ;
# endif
2021-04-01 10:06:53 +02:00
} else {
setEmpty ( ) ;
}
}
2020-04-29 22:34:28 +02:00
/* strcat char */
template < typename O , enable_if ( is_char ( O ) ) >
void strcat ( O otherChar )
{
if ( otherChar ) {
2021-04-08 17:07:05 +02:00
size_t currentSize = super : : size ( ) ;
size_t newSize = currentSize + utf_size_of_utf_string_len ( data ( ) , & otherChar , 1 ) ;
CheckSize ( newSize ) ;
utf_string_from_utf_string_len ( super : : __m_data + currentSize , m_allocatedSize , & otherChar , 1 ) ;
super : : __m_data [ newSize ] = 0 ;
# ifdef XSTRING_CACHING_OF_SIZE
super : : __m_size = newSize ;
# endif
2020-04-29 22:34:28 +02:00
} else {
// nothing to do
}
}
2020-08-10 13:06:06 +02:00
/* strcat char* */
template < typename O >
void strcat ( const O * other )
{
if ( other & & * other ) {
2021-04-08 17:07:05 +02:00
size_t currentSize = super : : size ( ) ; // size is number of T, not in bytes
size_t newSize = currentSize + utf_size_of_utf_string ( data ( ) , other ) ; // size is number of T, not in bytes
CheckSize ( newSize ) ;
utf_string_from_utf_string ( super : : __m_data + currentSize , m_allocatedSize - currentSize , other ) ;
super : : __m_data [ newSize ] = 0 ;
# ifdef XSTRING_CACHING_OF_SIZE
super : : __m_size = newSize ;
# endif
2020-08-10 13:06:06 +02:00
} else {
// nothing to do
}
}
2020-04-29 22:34:28 +02:00
/* strcat __String */
template < typename OtherCharType , class OtherXStringClass >
void strcat ( const __String < OtherCharType , OtherXStringClass > & other )
{
2021-04-08 17:07:05 +02:00
size_t currentSize = super : : size ( ) ; // size is number of T, not in bytes
size_t newSize = currentSize + utf_size_of_utf_string ( data ( ) , other . s ( ) ) ; // size is number of T, not in bytes
CheckSize ( newSize ) ;
utf_string_from_utf_string ( super : : __m_data + currentSize , m_allocatedSize - currentSize , other . s ( ) ) ;
super : : __m_data [ newSize ] = 0 ;
# ifdef XSTRING_CACHING_OF_SIZE
super : : __m_size = newSize ;
XSTRING_CHECK_SIZE ;
# endif
2020-04-29 22:34:28 +02:00
}
/* strncat */
template < typename O >
void strncat ( const O * other , size_t other_len )
{
if ( other & & * other & & other_len > 0 ) {
2021-04-08 17:07:05 +02:00
size_t currentSize = super : : size ( ) ;
size_t other_size = utf_size_of_utf_string_len ( data ( ) , other , other_len ) ;
2021-03-25 15:32:56 +01:00
size_t newSize = currentSize + other_size ;
2021-04-08 17:07:05 +02:00
CheckSize ( newSize ) ;
utf_string_from_utf_string_len ( super : : __m_data + currentSize , m_allocatedSize , other , other_len ) ;
super : : __m_data [ newSize ] = 0 ;
# ifdef XSTRING_CACHING_OF_SIZE
super : : __m_size = newSize ;
XSTRING_CHECK_SIZE ;
# endif
2020-04-29 22:34:28 +02:00
} else {
// nothing to do
}
}
2021-03-25 15:32:56 +01:00
/* strsicat */
template < typename O >
void strsicat ( const O * other , size_t other_size )
{
if ( other & & * other & & other_size > 0 ) {
2021-04-08 17:07:05 +02:00
size_t currentSize = super : : size ( ) ;
2021-03-25 15:32:56 +01:00
size_t newSize = currentSize + other_size ;
2021-04-08 17:07:05 +02:00
CheckSize ( newSize ) ;
utf_string_from_utf_string_size ( super : : __m_data + currentSize , m_allocatedSize , other , other_size ) ;
super : : __m_data [ newSize ] = 0 ;
# ifdef XSTRING_CACHING_OF_SIZE
super : : __m_size = newSize ;
XSTRING_CHECK_SIZE ;
# endif
2021-03-25 15:32:56 +01:00
} else {
// nothing to do
}
}
2020-08-10 13:06:06 +02:00
/* insert char* */
template < typename O >
ThisXStringClass & insertAtPos ( const O * other , size_t other_len , size_t pos )
{
if ( ! other | | ! * other ) return * ( ( ThisXStringClass * ) this ) ;
2021-04-08 17:07:05 +02:00
size_t currentLength = super : : length ( ) ;
2020-08-10 13:06:06 +02:00
if ( pos > = currentLength ) {
strncat ( other , other_len ) ;
return * ( ( ThisXStringClass * ) this ) ;
}
2021-04-08 17:07:05 +02:00
size_t currentSize = super : : size ( ) ;
size_t otherSize = utf_size_of_utf_string_len ( data ( ) , other , other_len ) ;
CheckSize ( currentSize + otherSize ) ;
size_t start = size_of_utf_string_len ( data ( ) , pos ) ; // size is number of T, not in bytes
memmove ( super : : __m_data + start + otherSize , super : : __m_data + start , ( currentSize - start + 1 ) * sizeof ( T ) ) ; // memmove handles overlapping memory move
utf_stringnn_from_utf_string ( super : : __m_data + start , otherSize , other ) ;
// data()[newSize] = 0;
# ifdef XSTRING_CACHING_OF_SIZE
super : : __m_size = currentSize + otherSize ;
XSTRING_CHECK_SIZE ;
# endif
2020-08-10 13:06:06 +02:00
return * ( ( ThisXStringClass * ) this ) ;
}
/* insert char* */
template < typename O >
ThisXStringClass & insertAtPos ( const O * other , size_t pos )
{
if ( ! other | | ! * other ) return * ( ( ThisXStringClass * ) this ) ;
2021-04-08 17:07:05 +02:00
size_t currentLength = super : : length ( ) ;
2020-08-10 13:06:06 +02:00
if ( pos > = currentLength ) {
strcat ( other ) ;
return * ( ( ThisXStringClass * ) this ) ;
}
2021-04-08 17:07:05 +02:00
size_t currentSize = super : : size ( ) ;
size_t otherSize = utf_size_of_utf_string ( data ( ) , other ) ;
CheckSize ( currentSize + otherSize ) ;
size_t start = size_of_utf_string_len ( data ( ) , pos ) ; // size is number of T, not in bytes
memmove ( data ( ) + start + otherSize , data ( ) + start , ( currentSize - start + 1 ) * sizeof ( T ) ) ; // memmove handles overlapping memory move
utf_stringnn_from_utf_string ( data ( ) + start , otherSize , other ) ;
// data()[newSize] = 0;
# ifdef XSTRING_CACHING_OF_SIZE
super : : __m_size = currentSize + otherSize ;
XSTRING_CHECK_SIZE ;
# endif
2020-08-10 13:06:06 +02:00
return * ( ( ThisXStringClass * ) this ) ;
}
/* insert char */
template < typename O , enable_if ( is_char ( O ) ) >
void insertAtPos ( O otherChar , size_t pos )
{
insertAtPos ( & otherChar , 1 , pos ) ;
}
ThisXStringClass & deleteCharsAtPos ( size_t pos , size_t count = 1 )
{
2021-04-08 17:07:05 +02:00
size_t currentLength = super : : length ( ) ;
2020-08-10 13:06:06 +02:00
if ( pos > = currentLength ) return * ( ( ThisXStringClass * ) this ) ;
2021-04-08 17:07:05 +02:00
size_t currentSize = super : : size ( ) ; // size is number of T, not in bytes
2020-08-10 13:06:06 +02:00
CheckSize ( currentSize , 0 ) ; // Although we only delete, we have to CheckSize in case this string point to a litteral.
2021-04-08 17:07:05 +02:00
size_t start = size_of_utf_string_len ( data ( ) , pos ) ; // size is number of T, not in bytes
2020-08-10 13:06:06 +02:00
// if ( pos+count >= currentLength ) count = currentLength - pos;
if ( pos + count > = currentLength ) {
2021-04-08 17:07:05 +02:00
super : : __m_data [ start ] = 0 ;
# ifdef XSTRING_CACHING_OF_SIZE
super : : __m_size = start ;
# endif
2020-08-10 13:06:06 +02:00
} else {
2021-04-08 17:07:05 +02:00
size_t end = start + size_of_utf_string_len ( data ( ) + start , count ) ; // size is number of T, not in bytes
memmove ( super : : __m_data + start , super : : __m_data + end , ( currentSize - end + 1 ) * sizeof ( T ) ) ; // memmove handles overlapping memory move
# ifdef XSTRING_CACHING_OF_SIZE
super : : __m_size - = end - start ;
# endif
2020-08-10 13:06:06 +02:00
}
// Handle length change when implementing caching length feature.
2021-04-08 17:07:05 +02:00
# ifdef XSTRING_CACHING_OF_SIZE
XSTRING_CHECK_SIZE ;
# endif
2020-08-10 13:06:06 +02:00
return * ( ( ThisXStringClass * ) this ) ;
}
2020-08-15 15:47:56 +02:00
ThisXStringClass & replaceAll ( char32_t charToSearch , char32_t charToReplaceBy )
{
2021-04-08 17:07:05 +02:00
size_t currentSize = super : : sizeInNativeChars ( ) ; // size is number of T, not in bytes
size_t charToSearchSize = utf_size_of_utf_string_len ( data ( ) , & charToSearch , 1 ) ; // size is number of T, not in bytes
size_t charToReplaceBySize = utf_size_of_utf_string_len ( data ( ) , & charToReplaceBy , 1 ) ; // size is number of T, not in bytes
2020-08-15 15:47:56 +02:00
// careful because 'charToReplaceBySize - charToSearchSize' overflows when charToSearchSize > charToReplaceBySize, which happens.
char32_t char32 ;
2021-04-08 17:07:05 +02:00
T * previousData = super : : __m_data ;
T * previousP = super : : __m_data ;
2020-08-25 17:35:19 +02:00
T * p = get_char32_from_string ( previousP , & char32 ) ;
2020-08-15 15:47:56 +02:00
while ( char32 ) {
if ( ! char32 ) break ;
if ( char32 = = charToSearch ) {
if ( CheckSize ( currentSize + charToReplaceBySize - charToSearchSize ) ) {
2021-04-08 17:07:05 +02:00
previousP = super : : __m_data + ( previousP - previousData ) ; // CheckSize have reallocated. Correct previousP, p and previousData.
p = super : : __m_data + ( p - previousData ) ;
previousData = super : : __m_data ;
2020-08-15 15:47:56 +02:00
}
2021-04-08 17:07:05 +02:00
memmove ( p + charToReplaceBySize - charToSearchSize , p , uintptr_t ( super : : __m_data + currentSize - p + 1 ) * sizeof ( T ) ) ;
2020-08-15 15:47:56 +02:00
p + = charToReplaceBySize ;
p - = charToSearchSize ;
currentSize + = charToReplaceBySize ;
currentSize - = charToSearchSize ;
utf_stringnn_from_utf_string ( previousP , charToReplaceBySize , & charToReplaceBy ) ;
}
previousP = p ;
2020-08-25 17:35:19 +02:00
p = get_char32_from_string ( previousP , & char32 ) ;
2020-08-15 15:47:56 +02:00
}
2021-04-08 17:07:05 +02:00
# ifdef XSTRING_CACHING_OF_SIZE
super : : __m_size = currentSize ;
XSTRING_CHECK_SIZE ;
# endif
2020-08-15 15:47:56 +02:00
return * ( ( ThisXStringClass * ) this ) ;
}
2020-08-16 15:21:12 +02:00
template < typename OtherXStringClass1 , class OtherXStringClass2 , enable_if ( is___String ( OtherXStringClass1 ) & & is___String ( OtherXStringClass2 ) ) >
ThisXStringClass & replaceAll ( const OtherXStringClass1 & search , const OtherXStringClass2 & replaceBy )
{
2021-04-08 17:07:05 +02:00
size_t currentSize = super : : sizeInNativeChars ( ) ; // size is number of T, not in bytes
2020-08-16 15:21:12 +02:00
size_t sizeLeft = currentSize ; // size is number of T, not in bytes
2021-04-08 17:07:05 +02:00
size_t searchSize = utf_size_of_utf_string ( data ( ) , search . s ( ) ) ; // size is number of T, not in bytes
size_t replaceBySize = utf_size_of_utf_string ( data ( ) , replaceBy . s ( ) ) ; // size is number of T, not in bytes
2020-08-16 15:21:12 +02:00
// careful because 'charToReplaceBySize - charToSearchSize' overflows when charToSearchSize > charToReplaceBySize, which happens.
2021-04-08 17:07:05 +02:00
// size_t pos = super::indexOf(search);
T * previousData = super : : __m_data ;
T * previousP = super : : __m_data ;
T * p = super : : __m_data ;
2020-08-16 15:21:12 +02:00
size_t pos = XStringAbstract__indexOf ( ( const T * * ) & p , search . s ( ) , 0 , false ) ;
while ( pos ! = MAX_XSIZE ) {
if ( CheckSize ( currentSize + replaceBySize - searchSize ) ) {
2021-04-08 17:07:05 +02:00
previousP = super : : __m_data + ( previousP - previousData ) ;
p = super : : __m_data + ( p - previousData ) ;
previousData = super : : __m_data ;
2020-08-16 15:21:12 +02:00
}
2020-08-18 18:45:44 +02:00
sizeLeft - = uintptr_t ( p - previousP ) ;
2020-08-16 15:21:12 +02:00
memmove ( p + replaceBySize , p + searchSize , ( sizeLeft - searchSize + 1 ) * sizeof ( T ) ) ;
2021-04-08 17:07:05 +02:00
// memmove(data()+pos+replaceBySize-searchSize, data()+pos, (currentSize - pos + 1)*sizeof(T));
2020-08-16 15:21:12 +02:00
utf_stringnn_from_utf_string ( p , replaceBySize , replaceBy . s ( ) ) ;
p + = replaceBySize ;
currentSize + = replaceBySize ;
currentSize - = searchSize ;
sizeLeft - = searchSize ;
// sizeLeft is equal to utf_size_of_utf_string(p, p);
previousP = p ;
pos = XStringAbstract__indexOf ( ( const T * * ) & p , search . s ( ) , 0 , false ) ;
}
2021-04-08 17:07:05 +02:00
# ifdef XSTRING_CACHING_OF_SIZE
super : : __m_size = currentSize ;
XSTRING_CHECK_SIZE ;
# endif
2020-08-16 15:21:12 +02:00
return * ( ( ThisXStringClass * ) this ) ;
}
2020-08-15 15:47:56 +02:00
2020-08-10 13:06:06 +02:00
void trim ( )
{
2021-04-08 17:07:05 +02:00
size_t lengthInNativeBytes = super : : sizeInNativeChars ( ) ;
2020-08-16 11:33:41 +02:00
if ( lengthInNativeBytes = = 0 ) return ;
2020-08-10 13:06:06 +02:00
T * start = 0 ;
2021-04-08 17:07:05 +02:00
T * s = super : : __m_data ;
2020-08-10 13:06:06 +02:00
while ( * s & & unsigned_type ( T ) ( * s ) < = 32 ) s + + ;
2020-08-16 11:33:41 +02:00
if ( ! * s ) {
2021-04-08 17:07:05 +02:00
super : : __m_data [ 0 ] = 0 ;
# ifdef XSTRING_CACHING_OF_SIZE
super : : __m_size = 0 ;
XSTRING_CHECK_SIZE ;
# endif
2020-08-16 11:33:41 +02:00
return ;
}
2020-08-10 13:06:06 +02:00
start = s ;
2021-04-08 17:07:05 +02:00
s = super : : __m_data + lengthInNativeBytes - 1 ;
2020-08-16 11:33:41 +02:00
while ( * s & & unsigned_type ( T ) ( * s ) < = 32 ) s - - ;
2021-04-08 17:07:05 +02:00
size_t newSize = uintptr_t ( s - start ) + 1 ;
CheckSize ( newSize , 0 ) ; // We have to CheckSize in case this string point to a litteral.
memmove ( super : : __m_data , start , newSize * sizeof ( T ) ) ;
super : : __m_data [ newSize ] = 0 ;
# ifdef XSTRING_CACHING_OF_SIZE
super : : __m_size = newSize ;
XSTRING_CHECK_SIZE ;
# endif
2020-08-10 13:06:06 +02:00
}
void lowerAscii ( )
{
2021-04-08 17:07:05 +02:00
size_t currentSize = super : : size ( ) ; // size is number of T, not in bytes
2020-08-10 13:06:06 +02:00
CheckSize ( currentSize , 0 ) ; // We have to CheckSize in case this string point to a litteral.
2021-04-08 17:07:05 +02:00
T * s = super : : __m_data ;
2020-08-10 13:06:06 +02:00
while ( * s ) {
* s = asciiToLower ( * s ) ;
s + + ;
}
}
void upperAscii ( )
{
2021-04-08 17:07:05 +02:00
size_t currentSize = super : : size ( ) ; // size is number of T, not in bytes
2020-08-10 13:06:06 +02:00
CheckSize ( currentSize , 0 ) ; // We have to CheckSize in case this string point to a litteral.
2021-04-08 17:07:05 +02:00
T * s = super : : __m_data ;
2020-08-10 13:06:06 +02:00
while ( * s ) {
* s = asciiToUpper ( * s ) ;
s + + ;
}
}
2021-03-25 15:32:56 +01:00
/* size is in number of technical chars, NOT in bytes */
2021-04-08 17:07:05 +02:00
ThisXStringClass & stealValueFrom ( T * S , size_t allocatedSize ) {
if ( m_allocatedSize > 0 ) delete super : : __m_data ;
super : : __m_data = S ;
# ifdef XSTRING_CACHING_OF_SIZE
super : : __m_size = utf_size_of_utf_string ( super : : __m_data , super : : __m_data ) ;
# endif
m_allocatedSize = allocatedSize ;
2021-03-25 15:32:56 +01:00
return * ( ( ThisXStringClass * ) this ) ;
}
2020-08-09 17:55:30 +02:00
2021-04-08 17:07:05 +02:00
// Not sure we should keep that. We cannot know the allocated size. Therefore, a future realloc may fail as EDK want the old size.
2020-08-09 17:55:30 +02:00
ThisXStringClass & stealValueFrom ( T * S ) {
2021-04-08 17:07:05 +02:00
if ( m_allocatedSize > 0 ) delete super : : __m_data ;
super : : __m_data = S ;
# ifdef XSTRING_CACHING_OF_SIZE
super : : __m_size = utf_size_of_utf_string ( super : : __m_data , super : : __m_data ) ;
m_allocatedSize = super : : __m_size + 1 ;
# else
m_allocatedSize = super : : size ( ) + 1 ;
# endif
2020-08-09 17:55:30 +02:00
return * ( ( ThisXStringClass * ) this ) ;
}
2021-01-31 10:50:23 +01:00
ThisXStringClass & stealValueFrom ( ThisXStringClass * S ) {
2021-04-08 17:07:05 +02:00
if ( m_allocatedSize > 0 ) delete super : : __m_data ;
# ifdef XSTRING_CACHING_OF_SIZE
super : : __m_size = S - > size ( ) ;
# endif
2021-01-31 10:50:23 +01:00
m_allocatedSize = S - > m_allocatedSize ;
2021-04-08 17:07:05 +02:00
// do forgetDataWithoutFreeing() last : it'll zero the value of size and m_allocatedSize
super : : __m_data = S - > forgetDataWithoutFreeing ( ) ;
2021-01-31 10:50:23 +01:00
return * ( ( ThisXStringClass * ) this ) ;
}
2020-04-29 22:34:28 +02:00
/* takeValueFrom */
template < typename O , class OtherXStringClass >
2021-04-08 17:07:05 +02:00
ThisXStringClass & takeValueFrom ( const __String < O , OtherXStringClass > & S ) { * this = S ; return * ( ( ThisXStringClass * ) this ) ; }
2020-08-09 17:55:30 +02:00
template < typename O >
ThisXStringClass & takeValueFrom ( const O * S ) { strcpy ( S ) ; return * ( ( ThisXStringClass * ) this ) ; }
template < typename O , enable_if ( is_char ( O ) ) >
ThisXStringClass & takeValueFrom ( const O C ) { strcpy ( C ) ; return * ( ( ThisXStringClass * ) this ) ; }
2021-04-08 17:07:05 +02:00
// template<typename O, class OtherXStringClass>
// ThisXStringClass& takeValueFrom(const __String<O, OtherXStringClass>& S, size_t len) { strncpy(S.s(), len); return *((ThisXStringClass*)this); }
2020-04-29 22:34:28 +02:00
template < typename O >
ThisXStringClass & takeValueFrom ( const O * S , size_t len ) { strncpy ( S , len ) ; return * ( ( ThisXStringClass * ) this ) ; }
/* += */
template < typename O , class OtherXStringClass >
ThisXStringClass & operator + = ( const __String < O , OtherXStringClass > & S ) { strcat ( S . s ( ) ) ; return * ( ( ThisXStringClass * ) this ) ; }
template < typename O , enable_if ( is_char ( O ) ) >
ThisXStringClass & operator + = ( O S ) { strcat ( S ) ; return * ( ( ThisXStringClass * ) this ) ; }
template < typename O >
ThisXStringClass & operator + = ( const O * S ) { strcat ( S ) ; return * ( ( ThisXStringClass * ) this ) ; }
2020-04-27 11:50:49 +02:00
} ;
2020-04-29 22:34:28 +02:00
template < class T , class ThisXStringClass >
T XStringAbstract < T , ThisXStringClass > : : nullChar = 0 ;
2020-04-23 15:20:48 +02:00
2020-04-29 22:34:28 +02:00
//------------------------------------------------------- + operator
template < typename T1 , typename T2 , enable_if ( is___String ( T1 ) | | is___String ( T2 ) ) >
typename __string_class_or < T1 , T2 > : : type operator + ( T1 p1 , T2 p2 ) { typename __string_class_or < T1 , T2 > : : type s ; s . takeValueFrom ( p1 ) ; s . strcat ( p2 ) ; return s ; }
//-------------------------------------------------------
2020-04-23 15:20:48 +02:00
# undef DBG_XSTRING
# undef asciiToLower
2021-04-08 17:07:05 +02:00
//#undef data()
2020-04-23 15:20:48 +02:00
# endif // __XSTRINGABSTRACT_H__