2024-02-05 22:25:30 -08:00
# pragma once
# include "Types.h"
# include "BaseObj.h"
# include "Util.h"
# include "Vector.h"
# include <utility>
namespace ehs
{
enum class SearchPattern
{
LEFT_RIGHT ,
RIGHT_LEFT
} ;
enum class IndexResult
{
BEGINNING ,
ENDING
} ;
/// A helper class for C-style strings.
/// @tparam T The character's data type to use.
/// @tparam N The number data type to use.
template < typename T = Char_8 , typename N = UInt_64 >
class Str : public BaseObj
{
private :
N size ;
T * data ;
public :
/// Frees any data created on the heap.
~ Str ( ) override
{
delete [ ] data ;
}
/// Default members initialization.
Str ( )
: size ( 0 ) , data ( nullptr )
{
AddType ( " Str " ) ;
}
/// Initializes members with given C-style string.
/// @param [in] str The C-style string.
/// @param [in] size The size of the given C-style string.
Str ( const T * const str , const N size )
: size ( ( size ) ? size : Len ( str ) ) , data ( nullptr )
{
data = new T [ this - > size + 1 ] ;
Util : : Copy ( data , str , Size ( true ) ) ;
data [ this - > size ] = 0 ;
AddType ( " Str " ) ;
}
/// Initializes members with given C-style string.
/// @param [in] str The C-style string.
Str ( const T * const str )
: size ( Len ( str ) ) , data ( nullptr )
{
data = new T [ size + 1 ] ;
Util : : Copy ( data , str , Size ( true ) ) ;
data [ size ] = 0 ;
AddType ( " Str " ) ;
}
/// Initializes string with the given size.
/// @param [in] size The size.
Str ( const N size )
: size ( size ) , data ( new T [ size + 1 ] )
{
data [ size ] = 0 ;
AddType ( " Str " ) ;
}
/// A move constructor.
Str ( Str & & str ) noexcept
: BaseObj ( ( BaseObj & & ) str ) , size ( str . size ) , data ( str . data )
{
str . size = 0 ;
str . data = nullptr ;
}
/// Copies all members from the given string object.
/// @param [in] str The string object to copy from.
Str ( const Str & str )
: BaseObj ( str ) , size ( str . size ) , data ( new T [ size + 1 ] )
{
Util : : Copy ( data , str . data , Size ( true ) ) ;
data [ size ] = 0 ;
}
Str & operator = ( Str & & str ) noexcept
{
if ( this = = & str )
return * this ;
BaseObj : : operator = ( ( BaseObj & & ) str ) ;
size = str . size ;
delete [ ] data ;
data = str . data ;
str . size = 0 ;
str . data = nullptr ;
return * this ;
}
/// Copies all members from the given string object.
/// @param [in] str The string object to copy from.
/// @returns The string that has been assigned to.
Str & operator = ( const Str & str )
{
if ( & str = = this )
return * this ;
BaseObj : : operator = ( str ) ;
size = str . size ;
delete [ ] data ;
data = new T [ size + 1 ] ;
Util : : Copy ( data , str . data , Size ( true ) ) ;
data [ size ] = 0 ;
return * this ;
}
/// Copies the given C-style string and retrieves the size.
/// @param [in] str The C-style string to copy from.
/// @returns The string object that has been assigned to.
Str < T , N > & operator = ( const T * const str )
{
size = Len ( str ) ;
delete [ ] data ;
data = new T [ size + 1 ] ;
Util : : Copy ( data , str , Size ( true ) ) ;
data [ size ] = 0 ;
return * this ;
}
/// Concatenates with the given C-style string.
/// @param [in] str The given C-style string.
/// @returns The resulting string object.
Str < T , N > & operator + = ( const T * const str )
{
N inputSize = Len ( str ) ;
T * result = new T [ size + inputSize + 1 ] ;
Util : : Copy ( result , data , Size ( true ) ) ;
delete [ ] data ;
Util : : Copy ( & result [ size ] , str , inputSize * sizeof ( T ) ) ;
result [ size + inputSize ] = 0 ;
size + = inputSize ;
data = result ;
return * this ;
}
/// Concatenates with the given string object.
/// @param [in] str The given string object.
/// @returns The resulting string object.
Str < T , N > & operator + = ( const Str < T , N > & str )
{
T * result = new T [ size + str . size + 1 ] ;
Util : : Copy ( result , data , Size ( true ) ) ;
delete [ ] data ;
Util : : Copy ( & result [ size ] , str , str . Size ( true ) ) ;
result [ size + str . size ] = 0 ;
size + = str . Size ( ) ;
data = result ;
return * this ;
}
/// Concatenates with the given number.
/// @param [in] num The given number to concatenate.
/// @returns The resulting string object.
Str < T , N > & operator + = ( const SInt_64 num )
{
return operator + = ( FromNum ( num ) ) ;
}
/// Concatenates with the given number.
/// @param [in] num The given number to concatenate.
/// @returns The resulting string object.
Str < T , N > & operator + = ( const UInt_64 num )
{
return operator + = ( FromNum ( num ) ) ;
}
/// Concatenates with the given number.
/// @param [in] num The given number to concatenate.
/// @returns The resulting string object.
Str < T , N > & operator + = ( const SInt_32 num )
{
return operator + = ( FromNum ( num ) ) ;
}
/// Concatenates with the given number.
/// @param [in] num The given number to concatenate.
/// @returns The resulting string object.
Str < T , N > & operator + = ( const UInt_32 num )
{
return operator + = ( FromNum ( num ) ) ;
}
/// Concatenates with the given number.
/// @param [in] num The given number to concatenate.
/// @returns The resulting string object.
Str < T , N > & operator + = ( const SInt_16 num )
{
return operator + = ( FromNum ( num ) ) ;
}
/// Concatenates with the given number.
/// @param [in] num The given number to concatenate.
/// @returns The resulting string object.
Str < T , N > & operator + = ( const UInt_16 num )
{
return operator + = ( FromNum ( num ) ) ;
}
/// Concatenates with the given number.
/// @param [in] num The given number to concatenate.
/// @returns The resulting string object.
Str < T , N > & operator + = ( const SInt_8 num )
{
return operator + = ( FromNum ( num ) ) ;
}
/// Concatenates with the given number.
/// @param [in] num The given number to concatenate.
/// @returns The resulting string object.
Str < T , N > & operator + = ( const UInt_8 num )
{
return operator + = ( FromNum ( num ) ) ;
}
# ifdef EHS_OS_WINDOWS
/// Concatenates with the given number.
/// @param [in] num The given number to concatenate.
/// @returns The result.
Str < T , N > & operator + = ( const DWORD num )
{
return operator + = ( FromNum ( num ) ) ;
}
/// Concatenates with the given number.
/// @param [in] num The given number to concatenate.
/// @returns The result.
Str < T , N > & operator + = ( const HRESULT num )
{
return operator + = ( FromNum ( num ) ) ;
}
# endif
/// Concatenates with the given number.
/// @param [in] num The given number to concatenate.
/// @returns The resulting string object.
Str < T , N > & operator + = ( const float num )
{
return operator + = ( FromNum ( num ) ) ;
}
/// Concatenates with the given number.
/// @param [in] num The given number to concatenate.
/// @returns The resulting string object.
Str < T , N > & operator + = ( const double num )
{
return operator + = ( FromNum ( num ) ) ;
}
/// Concatenates with the given number.
/// @param [in] num The given number to concatenate.
/// @returns The resulting string object.
Str < T , N > & operator + = ( const long double num )
{
return operator + = ( FromNum ( num ) ) ;
}
/// Concatenates with the given C-style string.
/// @param [in] str The given C-style string.
/// @returns The resulting string object.
Str < T , N > operator + ( const T * const str ) const
{
N inSize = Len ( str ) ;
Str < T , N > result ( size + inSize ) ;
Util : : Copy ( result . data , data , Size ( true ) ) ;
Util : : Copy ( & result . data [ size ] , str , inSize * sizeof ( T ) ) ;
result . data [ size + inSize ] = 0 ;
return result ;
}
/// Concatenates with the given string object.
/// @param [in] str The given string object.
/// @returns The resulting string object.
Str < T , N > operator + ( const Str < T , N > & str ) const
{
Str < T , N > result ( size + str . size ) ;
Util : : Copy ( result . data , data , Size ( true ) ) ;
Util : : Copy ( & result . data [ size ] , str . data , str . Size ( true ) ) ;
result . data [ size + str . size ] = 0 ;
return result ;
}
/// Concatenates with the given number.
/// @param [in] num The given number to Concatenate.
/// @returns The resulting string object.
Str < T , N > operator + ( const SInt_64 num ) const
{
return operator + ( FromNum ( num ) ) ;
}
/// Concatenates with the given number.
/// @param [in] num The given number to Concatenate.
/// @returns The resulting string object.
Str < T , N > operator + ( const UInt_64 num ) const
{
return operator + ( FromNum ( num ) ) ;
}
/// Concatenates with the given number.
/// @param [in] num The given number to Concatenate.
/// @returns The resulting string object.
Str < T , N > operator + ( const SInt_32 num ) const
{
return operator + ( FromNum ( num ) ) ;
}
/// Concatenates with the given number.
/// @param [in] num The given number to Concatenate.
/// @returns The resulting string object.
Str < T , N > operator + ( const UInt_32 num ) const
{
return operator + ( FromNum ( num ) ) ;
}
/// Concatenates with the given number.
/// @param [in] num The given number to Concatenate.
/// @returns The resulting string object.
Str < T , N > operator + ( const SInt_16 num ) const
{
return operator + ( FromNum ( num ) ) ;
}
/// Concatenates with the given number.
/// @param [in] num The given number to Concatenate.
/// @returns The resulting string object.
Str < T , N > operator + ( const UInt_16 num ) const
{
return operator + ( FromNum ( num ) ) ;
}
/// Concatenates with the given number.
/// @param [in] num The given number to Concatenate.
/// @returns The resulting string object.
Str < T , N > operator + ( const SInt_8 num ) const
{
return operator + ( FromNum ( num ) ) ;
}
/// Concatenates with the given number.
/// @param [in] num The given number to Concatenate.
/// @returns The resulting string object.
Str < T , N > operator + ( const UInt_8 num ) const
{
return operator + ( FromNum ( num ) ) ;
}
# ifdef EHS_OS_WINDOWS
/// Concatenates with the given number.
/// @param [in] str The given number to Concatenate.
/// @returns The result.
Str < T , N > operator + ( const DWORD num ) const
{
return operator + ( FromNum ( num ) ) ;
}
/// Concatenates with the given number.
/// @param [in] str The given number to Concatenate.
/// @returns The result.
Str < T , N > operator + ( const HRESULT num ) const
{
return operator + ( FromNum ( num ) ) ;
}
# endif
/// Concatenates with the given number.
/// @param [in] num The given number to Concatenate.
/// @returns The resulting string object.
Str < T , N > operator + ( const float num ) const
{
return operator + ( FromNum ( num ) ) ;
}
/// Concatenates with the given number.
/// @param [in] num The given number to Concatenate.
/// @returns The resulting string object.
Str < T , N > operator + ( const double num ) const
{
return operator + ( FromNum ( num ) ) ;
}
/// Concatenates with the given number.
/// @param [in] num The given number to Concatenate.
/// @returns The resulting string object.
Str < T , N > operator + ( const long double num ) const
{
return operator + ( FromNum ( num ) ) ;
}
/// Compares with a another string. First comparing sizes.
/// @param [in] str The string object to compare with.
/// @returns Whether or not they are equal.
bool operator = = ( T * str ) const
{
if ( size ! = Len ( str ) )
return false ;
return Util : : Compare ( data , str , Size ( true ) ) ;
}
/// Compares with a C-style string. First comparing sizes.
/// @param [in] str The C-style string to compare with.
/// @returns Whether or not they are equal.
bool operator = = ( const T * const str ) const
{
if ( size ! = Len ( str ) )
return false ;
return Util : : Compare ( data , str , Size ( true ) ) ;
}
/// Compares with a string object. First comparing sizes.
/// @param [in] str The string object to compare with.
/// @returns Whether or not they are equal.
bool operator = = ( const Str < T , N > & str ) const
{
if ( size ! = str . size )
return false ;
return Util : : Compare ( data , str , Size ( true ) ) ;
}
/// Compares with a C-style string. First comparing sizes.
/// @param [in] str The C-style string to compare with.
/// @returns Whether or not they are equal.
bool operator ! = ( const T * const str ) const
{
if ( size ! = Len ( str ) )
return true ;
return ! Util : : Compare ( data , str , Size ( true ) ) ;
}
/// Compares with a string object. First comparing sizes.
/// @param [in] str The string to compare with.
/// @returns Whether or not they are equal.
bool operator ! = ( const Str < T , N > & str ) const
{
if ( size ! = str . size )
return true ;
return ! Util : : Compare ( data , str , Size ( true ) ) ;
}
/// Retrieves the raw C-style string from casting a string object.
operator T * ( ) const
{
return data ;
}
/// Resizes the string.
/// @param [in] newSize The size to change to.
void Resize ( const N newSize )
{
if ( newSize = = size )
return ;
T * result = new T [ newSize + 1 ] ;
if ( newSize > size )
Util : : Copy ( result , data , Size ( true ) ) ;
else
Util : : Copy ( result , data , newSize * sizeof ( T ) ) ;
size = newSize ;
delete [ ] data ;
data = result ;
data [ size ] = 0 ;
}
/// Retrieves the size of the string.
/// @param [in] inBytes To retrieve the size in bytes.
/// @returns The resulting size.
N Size ( bool inBytes = false ) const
{
if ( inBytes )
return sizeof ( T ) * size ;
else
return size ;
}
/// Finds the null terminator in the string and makes it the exact size if greater than.
void ExactSize ( )
{
size = Len ( data ) ;
T * result = new T [ size + 1 ] ;
Util : : Copy ( result , data , Size ( true ) ) ;
delete [ ] data ;
result [ size ] = 0 ;
data = result ;
}
/// Copies a string object to the referenced string object.
/// @param dstOffset The offset index to copy to.
/// @param src The source string object to copy from.
void Copy ( const N dstOffset , const Str < T , N > & src )
{
if ( dstOffset + src . size > size )
{
//Log_8 log(__FUNCSIG__, LogType::ERR, 0, "The parameters \"dstOffset\" (" + Str_8::FromNum(dstOffset) + ") + \"srcSize\" (" + Str_8::FromNum(src.Size()) + ") is greater than the referenced string object's size (" + Str_8::FromNum(size) + ").");
return ;
}
Util : : Copy ( data [ dstOffset ] , src , src . Size ( true ) ) ;
}
/// Copies a C-style string to the referenced string object.
/// @param dstOffset The offset index to copy to.
/// @param src The source C-style string to copy from.
void Copy ( const N dstOffset , const T * const src )
{
N srcSize = Len ( src ) ;
if ( dstOffset + srcSize > size )
{
//Log_8 log(__FUNCSIG__, LogType::ERR, 0, "The parameters \"dstOffset\" (" + Str_8::FromNum(dstOffset) + ") + \"srcSize\" (" + Str_8::FromNum(srcSize) + ") is greater than the referenced string object's size (" + Str_8::FromNum(size) + ").");
return ;
}
Util : : Copy ( data [ dstOffset ] , src , srcSize * sizeof ( T ) ) ;
}
/// Copies a C-style string to the referenced string object.
/// @param dstOffset The offset index to copy to.
/// @param src The source C-style string to copy from.
/// @param srcSize The size of the source C-style string.
void Copy ( const N dstOffset , const T * const src , const N srcSize )
{
if ( dstOffset + srcSize > size )
{
//Log_8 log(__FUNCSIG__, LogType::ERR, 0, "The parameters \"dstOffset\" (" + Str_8::FromNum(dstOffset) + ") + \"srcSize\" (" + Str_8::FromNum(srcSize) + ") is greater than the referenced string object's size (" + Str_8::FromNum(size) + ").");
return ;
}
Util : : Copy ( data [ dstOffset ] , src , srcSize * sizeof ( T ) ) ;
}
/// Inserts a string at a specified index.
/// @param [in] index The index to insert the string at.
/// @param [in] value The string to insert.
void Insert ( const N index , const Str & value )
{
if ( ! value . size )
return ;
N newSize = size + value . size ;
T * result = new T [ newSize + 1 ] ;
Util : : Copy ( result , data , index * sizeof ( T ) ) ;
Util : : Copy ( & result [ index ] , value . data , value . Size ( true ) ) ;
Util : : Copy ( & result [ index + value . size ] , & data [ index ] , size - index ) ;
result [ newSize ] = 0 ;
delete [ ] data ;
data = result ;
size = newSize ;
}
/// Inserts a character at a specified index.
/// @param [in] index The index to insert the character at.
/// @param [in] value The character to insert.
void Insert ( const N index , const T value )
{
N newSize = 0 ;
if ( index > size - 1 )
newSize = size + ( ( index + 1 ) - size ) ;
else
newSize = size + 1 ;
T * result = new T [ newSize + 1 ] ;
for ( N i = 0 ; i < index ; + + i )
result [ i ] = data [ i ] ;
result [ index ] = value ;
for ( N i = index ; i < size ; + + i )
result [ i + 1 ] = data [ i ] ;
result [ newSize ] = 0 ;
delete [ ] data ;
data = result ;
size = newSize ;
}
/// Removes characters withing the given range.
/// @param [in] start The index to start.
/// @param [in] end The index to end.
/// @returns The removed string object.
Str Remove ( const N start , const N end )
{
if ( ! size | | start > = size | | end > size | | end < = start )
return { } ;
Str popped ( & data [ start ] , end - start ) ;
N newSize = size - popped . size ;
T * result = new T [ newSize + 1 ] ;
Util : : Copy ( result , data , start * sizeof ( T ) ) ;
Util : : Copy ( & result [ start ] , & data [ end ] , ( size - end ) * sizeof ( T ) ) ;
result [ newSize ] = 0 ;
delete [ ] data ;
data = result ;
size = newSize ;
return popped ;
}
/// Removes a character at the given index.
/// @param [in] index The index to remove a character.
/// @returns The character removed.
T Remove ( const N index )
{
T popped = { } ;
if ( ! size | | index > = size )
return popped ;
popped = data [ index ] ;
N newSize = size - 1 ;
T * result = new T [ newSize ] ;
for ( N i = 0 ; i < index ; + + i )
result [ i ] = data [ i ] ;
for ( N i = index + 1 ; i < size ; + + i )
result [ i - 1 ] = data [ i ] ;
delete [ ] data ;
data = result ;
size = newSize ;
return popped ;
}
/// Adds a value at the end of the string.
/// @param [in] value The character to push to the end of the string.
void Push ( const Str < T , N > & value )
{
T * result = new T [ size + value . size + 1 ] ;
Util : : Copy ( result , data , Size ( true ) ) ;
Util : : Copy ( & result [ size ] , value , value . Size ( true ) ) ;
result [ size + value . Size ( ) ] = 0 ;
delete [ ] data ;
data = result ;
size + = value . size ;
}
/// Adds a value at the end of the string.
/// @param [in] value The C-style string to push to the end of the string.
/// @param [in] size The size of the given C-style string.
void Push ( const T * const value , const N size )
{
T * result = new T [ this - > size + size + 1 ] ;
Util : : Copy ( result , data , Size ( true ) ) ;
Util : : Copy ( & result [ this - > size ] , value , size * sizeof ( T ) ) ;
result [ this - > size + size ] = 0 ;
delete [ ] data ;
data = result ;
this - > size + = size ;
}
/// Adds a value at the end of the string.
/// @param [in] value The C-style string to push to the end of the string.
void Push ( const T * const value )
{
N inSize = Len ( value ) ;
T * result = new T [ size + inSize + 1 ] ;
Util : : Copy ( result , data , Size ( true ) ) ;
Util : : Copy ( result [ size ] , value , inSize * sizeof ( T ) ) ;
result [ size + inSize ] = 0 ;
delete [ ] data ;
data = result ;
size + = inSize ;
}
/// Adds a value at the end of the string.
/// @param [in] value The character to push to the end of the string.
void Push ( const T value )
{
T * result = new T [ size + 2 ] ;
Util : : Copy ( result , data , Size ( true ) ) ;
result [ size ] = value ;
result [ size + 1 ] = 0 ;
delete [ ] data ;
data = result ;
+ + size ;
}
/// Removes the value at the end of the array.
/// @returns The value that was popped.
T Pop ( )
{
T * result = new T [ size - - ] ;
T value = data [ size ] ;
Util : : Copy ( result , data , Size ( true ) ) ;
result [ size ] = 0 ;
delete [ ] data ;
data = result ;
return value ;
}
/// Retrieves the string in bytes for serialization.
/// @returns The string in bytes.
const Byte * ToBytes ( ) const
{
return ( Byte * ) data ;
}
/// Retrieves the string in bytes for serialization.
/// @returns The string in bytes.
Byte * ToBytes ( )
{
return ( Byte * ) data ;
}
/// Converts all upper-case ASCII characters to lower-case.
void ToLower ( )
{
for ( N i = 0 ; i < size ; + + i )
if ( data [ i ] > 64 & & data [ i ] < 91 )
data [ i ] + = 32 ;
}
/// Converts all upper-case ASCII characters to lower-case.
/// @returns The resulting string object.
Str < T , N > GetLower ( ) const
{
Str < T , N > result ( size ) ;
for ( N i = 0 ; i < size ; + + i )
if ( data [ i ] > 64 & & data [ i ] < 91 )
result [ i ] = data [ i ] + 32 ;
else
result [ i ] = data [ i ] ;
return result ;
}
/// Converts all lower-case ASCII characters to upper-case.
void ToUpper ( )
{
for ( N i = 0 ; i < size ; + + i )
if ( data [ i ] > 96 & & data [ i ] < 123 )
data [ i ] - = 32 ;
}
/// Converts all lower-case ASCII characters to upper-case.
/// @returns The resulting string object.
Str < T , N > GetUpper ( ) const
{
Str < T , N > result ( size ) ;
for ( N i = 0 ; i < size ; + + i )
if ( data [ i ] > 96 & & data [ i ] < 123 )
result [ i ] = data [ i ] - 32 ;
else
result [ i ] = data [ i ] ;
return result ;
}
/// Reverses the entire string object.
void Reverse ( )
{
if ( size < = 1 | | ! data )
return ;
T * r = new T [ size + 1 ] ;
for ( N i = 0 ; i < size ; + + i )
r [ i ] = data [ size - 1 - i ] ;
r [ size ] = 0 ;
delete [ ] data ;
data = r ;
}
/// Reverses the entire string object.
/// @returns The resulting string object.
Str < T , N > GetReverse ( )
{
if ( size < = 1 | | ! data )
return * this ;
Str < T , N > r ( size ) ;
for ( N i = 0 ; i < size ; + + i )
r [ i ] = data [ size - 1 - i ] ;
return r ;
}
/// Clips the string at the given index and with the given size.
/// @param [in] index The index to clip at.
/// @param [in] size The size for the clip starting from the index.
/// @returns The resulting string object.
Str < T , N > Sub ( const N index , const N size = 0 ) const
{
if ( index > = this - > size )
{
//Log_8 log(__FUNCSIG__, LogType::ERR, 0, "The given index parameter, \"" + Str<T, N>::FromNum(index) + "\" is greater than the string's size, \"" + Str<T, N>::FromNum(this->size) + "\".");
return Str < T , N > ( ) ;
}
if ( size )
{
if ( size > this - > size )
{
//Log_8 log(__FUNCSIG__, LogType::ERR, 1, "The given size parameter, \"" + Str<T, N>::FromNum(size) + "\" is greater than the string's size, \"" + Str<T, N>::FromNum(this->size) + "\", at the index, \"" + Str<T, N>::FromNum(index) + "\".");
return Str < T , N > ( ) ;
}
Str < T , N > result ( size ) ;
Util : : Copy ( result , & data [ index ] , result . Size ( true ) ) ;
return result ;
}
else
{
Str < T , N > result ( this - > size - index ) ;
Util : : Copy ( result , & data [ index ] , result . Size ( true ) ) ;
return result ;
}
}
/// Splits a string into a Vector with the given separator.
/// @param [in] ide The given string as the separator.
/// @param [in] max The max amount of times to split the string.
/// @returns The resulting string object.
Vector < Str < T , N > , N > Split ( const Str < T , N > & ide , const N max = 0 ) const
{
Vector < Str < T , N > , N > result ( 0 , 5 ) ;
N b = 0 ;
for ( N i = 0 , c = 0 ; i < size ; + + i )
{
if ( data [ i ] = = ide [ c ] )
{
if ( + + c = = ide . Size ( ) )
{
N r = i - ( c - 1 ) - b ;
if ( ! r )
result . Push ( Str < T , N > ( ) ) ;
else
result . Push ( Str < T , N > ( & data [ b ] , r ) ) ;
b = i + 1 ;
c = 0 ;
if ( max & & result . Size ( ) = = max )
break ;
}
}
else
{
c = 0 ;
}
}
if ( b < size )
result . Push ( Str < T , N > ( & data [ b ] , size - b ) ) ;
return result ;
}
/// Removes all instances of the ide.
/// @param [in] ide The string to look for.
/// @returns The resulting string object.
Str < T , N > RemoveAll ( const Str < T , N > & ide ) const
{
Str < T , N > result ( size ) ;
for ( N i = 0 , b = 0 , c = 0 ; i < size ; + + i )
{
if ( data [ i ] = = ide [ c ] )
{
if ( + + c = = ide . Size ( ) )
c = 0 ;
}
else
{
if ( c )
for ( N d = c ; d < 0 ; - - d )
result [ b + + ] = data [ i - d ] ;
else
result [ b + + ] = data [ i ] ;
c = 0 ;
}
}
return result ;
}
/// Replaces all instances of ide with the replacer.
/// @param [in] ide The string to look for.
/// @param [in] replacer The string placed.
/// @returns The resulting string object.
Str ReplaceAll ( const Str & ide , const Str & replacer ) const
{
Str < T , N > result ;
for ( N i = 0 , b = 0 ; i < size ; + + i )
{
if ( data [ i ] = = ide [ b ] )
{
if ( + + b = = ide . Size ( ) )
{
result . Push ( replacer ) ;
b = 0 ;
}
}
else
{
result . Push ( data [ i ] ) ;
}
}
return result ;
}
/// Finds the first instance of the given string object.
/// @param [in] ide The string to look for.
/// @param [out] index The index of the string found. Can be a nullptr.
/// @param [in] pattern The search pattern for optimization.
/// @param [in] result What index to return where the first instance is found.
/// @returns The index where the instance was found with the result varying from the result parameter.
bool Find ( const Str < T , N > & ide , N * const index = nullptr , const SearchPattern pattern = SearchPattern : : LEFT_RIGHT , const IndexResult result = IndexResult : : BEGINNING ) const
{
if ( pattern = = SearchPattern : : LEFT_RIGHT )
{
for ( N i = 0 , c = 0 ; i < size ; + + i )
{
if ( data [ i ] = = ide [ c ] )
{
if ( + + c = = ide . Size ( ) )
{
if ( result = = IndexResult : : BEGINNING )
{
if ( index )
* index = i - ( c - 1 ) ;
return true ;
}
else
{
if ( index )
* index = i ;
return true ;
}
}
}
}
}
else if ( pattern = = SearchPattern : : RIGHT_LEFT )
{
for ( N i = size , c = ide . Size ( ) ; i > 0 ; - - i )
{
if ( data [ i - 1 ] = = ide [ c - 1 ] )
{
if ( - - c = = 0 )
{
if ( result = = IndexResult : : BEGINNING )
{
if ( index )
* index = i - ( ide . Size ( ) - 1 ) ;
return true ;
}
else
{
if ( index )
* index = i ;
return true ;
}
}
}
}
}
return false ;
}
/// Checks if the current string contains the given ide.
/// @param [in] ide The given ide to check for.
/// @param [in] pattern The search pattern to use.
/// @returns True if the current string does contain the ide.
bool Contains ( const Str < T , N > & ide , const SearchPattern pattern = SearchPattern : : LEFT_RIGHT ) const
{
if ( pattern = = SearchPattern : : LEFT_RIGHT )
{
for ( N i = 0 , c = 0 ; i < size ; + + i )
{
if ( data [ i ] = = ide [ c ] )
{
if ( + + c = = ide . Size ( ) )
{
return true ;
}
}
}
}
else if ( pattern = = SearchPattern : : RIGHT_LEFT )
{
for ( N i = size , c = ide . Size ( ) ; i > 0 ; - - i )
{
if ( data [ i - 1 ] = = ide [ c - 1 ] )
{
if ( - - c = = 0 )
{
return true ;
}
}
}
}
return false ;
}
/// Checks if the string represents a number. Must not have any alphabetical characters.
/// @returns The result.
bool IsNum ( ) const
{
if ( ! size )
return false ;
if ( ( data [ 0 ] < ' 0 ' | | data [ 0 ] > ' 9 ' ) & & data [ 0 ] ! = ' - ' & & data [ 0 ] ! = ' . ' )
return false ;
for ( N i = 1 ; i < size ; + + i )
if ( ( data [ i ] < ' 0 ' | | data [ i ] > ' 9 ' ) & & data [ i ] ! = ' . ' )
return false ;
return true ;
}
/// Converts a number into hexadecimal string representation.
/// @tparam I The data type of the number given.
/// @param [in] num The number to convert.
/// @returns The resulting hexadecimal.
template < typename I = int >
static Str NumToHex ( const I num )
{
static const T hex [ ] = " 0123456789ABCDEF " ;
Str result ( sizeof ( I ) * 2 ) ;
for ( UInt_8 i = 0 ; i < sizeof ( I ) ; + + i )
{
result [ i * 2 ] = hex [ ( ( Byte * ) & num ) [ i ] / 16 ] ;
result [ i * 2 + 1 ] = hex [ ( ( Byte * ) & num ) [ i ] % 16 ] ;
}
return result ;
}
/// Converts a string hexadecimal into a number.
/// @tparam I The data type of the number outputted.
/// @param [in] in The string to convert.
/// @returns The resulting number.
template < typename I = int >
static I HexToNum ( const Str & in )
{
N offset = 0 ;
bool neg = false ;
if ( in [ offset ] = = 45 )
{
neg = true ;
+ + offset ;
}
else if ( in [ offset ] = = 43 )
+ + offset ;
if ( in [ offset ] = = 48 & & ( in [ offset + 1 ] = = 88 | | in [ offset + 1 ] = = 120 ) )
offset + = 2 ;
N acc = 0 ;
for ( N i = offset ; i < in . Size ( ) ; + + i )
{
I value = 0 ;
if ( in [ i ] > 47 & & in [ i ] < 58 )
value = in [ i ] - 48 ;
else if ( in [ i ] > 64 & & in [ i ] < 71 )
value = in [ i ] - 55 ;
else if ( in [ i ] > 96 & & in [ i ] < 103 )
value = in [ i ] - 87 ;
if ( value > = 16 )
return 0 ;
acc * = 16 ;
acc + = value ;
}
return neg ? - acc : acc ;
}
/// Converts the current string from hexadecimal into a number.
/// @tparam I The data type of the number outputted.
/// @returns The resulting number.
template < typename I = int >
I HexToNum ( ) const
{
N offset = 0 ;
bool neg = false ;
if ( data [ offset ] = = 45 )
{
neg = true ;
+ + offset ;
}
else if ( data [ offset ] = = 43 )
+ + offset ;
if ( data [ offset ] = = 48 & & ( data [ offset + 1 ] = = 88 | | data [ offset + 1 ] = = 120 ) )
offset + = 2 ;
N acc = 0 ;
for ( N i = offset ; i < size ; + + i )
{
I value = 0 ;
if ( data [ i ] > 47 & & data [ i ] < 58 )
value = data [ i ] - 48 ;
else if ( data [ i ] > 64 & & data [ i ] < 71 )
value = data [ i ] - 55 ;
else if ( data [ i ] > 96 & & data [ i ] < 103 )
value = data [ i ] - 87 ;
if ( value > = 16 )
return 0 ;
acc * = 16 ;
acc + = value ;
}
return neg ? - acc : acc ;
}
/// Converts the string into a number.
/// @tparam I The resulting number's data type.
/// @returns The result.
/// @note Use "IsNum" before this if the string object is not guaranteed to be a number.
template < typename I = N >
I ToDecimal ( ) const
{
I r = 0 ;
if ( ! size )
return r ;
for ( N i = data [ 0 ] = = ' - ' ? 1 : 0 ; i < size ; + + i )
r = r * 10 + data [ i ] - ' 0 ' ;
if ( data [ 0 ] = = ' - ' )
r * = - 1 ;
return r ;
}
/// Converts the string into a floating point number.
/// @returns The resulting float.
/// @note Use "IsNum" before this if the string object is not guaranteed to be a number.
float ToFloat ( ) const
{
N decPoint = size ;
Find ( " . " , & decPoint ) ;
float result = 0.0f ;
float fraction = 0.0f ;
float scale = 1.0f ;
for ( N i = 0 ; i < decPoint ; + + i )
result = result * 10.0f + data [ i ] - ' 0 ' ;
for ( N i = decPoint + 1 ; i < size ; + + i )
{
fraction = fraction * 10.0f + data [ i ] - ' 0 ' ;
scale * = 10.0f ;
}
result + = fraction / scale ;
return result ;
}
/// Converts the string into a double floating point number.
/// @returns The resulting double.
/// @note Use "IsNum" before this if the string object is not guaranteed to be a number.
double ToDouble ( ) const
{
N decPoint = size ;
Find ( " . " , & decPoint ) ;
double result = 0.0f ;
double fraction = 0.0f ;
double scale = 1.0f ;
for ( N i = 0 ; i < decPoint ; + + i )
result = result * 10.0f + data [ i ] - ' 0 ' ;
for ( N i = decPoint + 1 ; i < size ; + + i )
{
fraction = fraction * 10.0f + data [ i ] - ' 0 ' ;
scale * = 10.0f ;
}
result + = fraction / scale ;
return result ;
}
/// Converts the string into a long double floating point number.
/// @returns The resulting long double.
/// @note Use "IsNum" before this if the string object is not guaranteed to be a number.
long double ToLDouble ( ) const
{
N decPoint = size ;
Find ( " . " , & decPoint ) ;
long double result = 0.0f ;
long double fraction = 0.0f ;
long double scale = 1.0f ;
for ( N i = 0 ; i < decPoint ; + + i )
result = result * 10.0f + data [ i ] - ' 0 ' ;
for ( N i = decPoint + 1 ; i < size ; + + i )
{
fraction = fraction * 10.0f + data [ i ] - ' 0 ' ;
scale * = 10.0f ;
}
result + = fraction / scale ;
return result ;
}
/// Converts the given number into a string.
/// @param [in] num The given number to convert.
/// @returns The resulting string representation.
static Str < T , N > FromNum ( const SInt_64 num )
{
if ( num = = 0 )
{
Str < T , N > z ( 1 ) ;
z [ 0 ] = 48 ;
return z ;
}
Str < T , N > r ( 21 ) ;
SInt_64 nonNeg ;
if ( num < 0 )
nonNeg = - num ;
else
nonNeg = num ;
N i = 0 ;
while ( nonNeg ! = 0 )
{
r [ i + + ] = 48 + nonNeg % 10 ;
nonNeg / = 10 ;
}
if ( num < 0 )
r [ i + + ] = 45 ;
r . Resize ( i ) ;
return r . GetReverse ( ) ;
}
/// Converts the given number into a string.
/// @param [in] num The given number to convert.
/// @returns The resulting string representation.
static Str < T , N > FromNum ( const UInt_64 num )
{
if ( num = = 0 )
{
Str < T , N > z ( 1 ) ;
z [ 0 ] = 48 ;
return z ;
}
Str < T , N > r ( 21 ) ;
UInt_64 nonNeg = num ;
N i = 0 ;
while ( nonNeg ! = 0 )
{
r [ i + + ] = 48 + nonNeg % 10 ;
nonNeg / = 10 ;
}
r . Resize ( i ) ;
return r . GetReverse ( ) ;
}
/// Converts the given number into a string.
/// @param [in] num The given number to convert.
/// @returns The resulting string representation.
static Str < T , N > FromNum ( const SInt_32 num )
{
if ( num = = 0 )
{
Str < T , N > z ( 1 ) ;
z [ 0 ] = 48 ;
return z ;
}
Str < T , N > r ( 11 ) ;
SInt_32 nonNeg ;
if ( num < 0 )
nonNeg = - num ;
else
nonNeg = num ;
N i = 0 ;
while ( nonNeg ! = 0 )
{
r [ i + + ] = 48 + nonNeg % 10 ;
nonNeg / = 10 ;
}
if ( num < 0 )
r [ i + + ] = 45 ;
r . Resize ( i ) ;
return r . GetReverse ( ) ;
}
/// Converts the given number into a string.
/// @param [in] num The given number to convert.
/// @returns The resulting string representation.
static Str < T , N > FromNum ( const UInt_32 num )
{
if ( num = = 0 )
{
Str < T , N > z ( 1 ) ;
z [ 0 ] = 48 ;
return z ;
}
Str < T , N > r ( 11 ) ;
UInt_32 nonNeg = num ;
N i = 0 ;
while ( nonNeg ! = 0 )
{
r [ i + + ] = 48 + nonNeg % 10 ;
nonNeg / = 10 ;
}
r . Resize ( i ) ;
return r . GetReverse ( ) ;
}
/// Converts the given number into a string.
/// @param [in] num The given number to convert.
/// @returns The resulting string representation.
static Str < T , N > FromNum ( const SInt_16 num )
{
if ( num = = 0 )
{
Str < T , N > z ( 1 ) ;
z [ 0 ] = 48 ;
return z ;
}
Str < T , N > r ( 6 ) ;
SInt_16 nonNeg ;
if ( num < 0 )
nonNeg = - num ;
else
nonNeg = num ;
N i = 0 ;
while ( nonNeg ! = 0 )
{
r [ i + + ] = 48 + nonNeg % 10 ;
nonNeg / = 10 ;
}
if ( num < 0 )
r [ i + + ] = 45 ;
r . Resize ( i ) ;
return r . GetReverse ( ) ;
}
/// Converts the given number into a string.
/// @param [in] num The given number to convert.
/// @returns The resulting string representation.
static Str < T , N > FromNum ( const UInt_16 num )
{
if ( num = = 0 )
{
Str < T , N > z ( 1 ) ;
z [ 0 ] = 48 ;
return z ;
}
Str < T , N > r ( 6 ) ;
UInt_16 nonNeg = num ;
N i = 0 ;
while ( nonNeg ! = 0 )
{
r [ i + + ] = 48 + nonNeg % 10 ;
nonNeg / = 10 ;
}
r . Resize ( i ) ;
return r . GetReverse ( ) ;
}
/// Converts the given number into a string.
/// @param [in] num The given number to convert.
/// @returns The resulting string representation.
static Str < T , N > FromNum ( const SInt_8 num )
{
if ( num = = 0 )
{
Str < T , N > z ( 1 ) ;
z [ 0 ] = 48 ;
return z ;
}
Str < T , N > r ( 4 ) ;
SInt_8 nonNeg ;
if ( num < 0 )
nonNeg = - num ;
else
nonNeg = num ;
N i = 0 ;
while ( nonNeg ! = 0 )
{
r [ i + + ] = 48 + nonNeg % 10 ;
nonNeg / = 10 ;
}
if ( num < 0 )
r [ i + + ] = 45 ;
r . Resize ( i ) ;
return r . GetReverse ( ) ;
}
/// Converts the given number into a string.
/// @param [in] num The given number to convert.
/// @returns The resulting string representation.
static Str < T , N > FromNum ( const UInt_8 num )
{
if ( num = = 0 )
{
Str < T , N > z ( 1 ) ;
z [ 0 ] = 48 ;
return z ;
}
Str < T , N > r ( 4 ) ;
UInt_8 nonNeg = num ;
N i = 0 ;
while ( nonNeg ! = 0 )
{
r [ i + + ] = 48 + nonNeg % 10 ;
nonNeg / = 10 ;
}
r . Resize ( i ) ;
return r . GetReverse ( ) ;
}
# ifdef EHS_OS_WINDOWS
/// Converts the given number into a string.
/// @returns The result.
static Str < T , N > FromNum ( const DWORD num )
{
if ( num = = 0 )
{
Str < T , N > z ( 1 ) ;
z [ 0 ] = 48 ;
return z ;
}
Str < T , N > r ( 11 ) ;
DWORD nonNeg = num ;
N i = 0 ;
while ( nonNeg ! = 0 )
{
r [ i + + ] = 48 + nonNeg % 10 ;
nonNeg / = 10 ;
}
r . Resize ( i ) ;
return r . GetReverse ( ) ;
}
/// Converts the given number into a string.
/// @returns The result.
static Str < T , N > FromNum ( const HRESULT num )
{
if ( num = = 0 )
{
Str < T , N > z ( 1 ) ;
z [ 0 ] = 48 ;
return z ;
}
Str < T , N > r ( 11 ) ;
HRESULT nonNeg ;
if ( num < 0 )
nonNeg = - num ;
else
nonNeg = num ;
N i = 0 ;
while ( nonNeg ! = 0 )
{
r [ i + + ] = 48 + nonNeg % 10 ;
nonNeg / = 10 ;
}
if ( num < 0 )
r [ i + + ] = 45 ;
r . Resize ( i ) ;
return r . GetReverse ( ) ;
}
# endif
/// Converts the given floating point into a string.
/// @param [in] num The given floating point to convert.
/// @param [in] maxDecimals The max decimal places to add.
/// @returns The resulting string representation.
static Str < T , N > FromNum ( const float num , const UInt_8 maxDecimals = 5 )
{
SInt_64 whole = ( SInt_64 ) num ;
Str < T , N > result ;
if ( whole < 0 )
result + = " - " ;
result + = Str < T , N > : : FromNum ( whole ) ;
UInt_64 power = 10 ;
for ( UInt_64 i = 0 ; i < ( UInt_64 ) maxDecimals - 1 ; + + i )
power * = 10 ;
SInt_64 fraction = ( SInt_64 ) ( ( num - ( float ) whole ) * ( float ) power ) ;
if ( ! fraction )
return result ;
result + = " . " ;
Str < T , N > fResult ( maxDecimals ) ;
N i = 0 ;
while ( fraction )
{
fResult [ i + + ] = 48 + fraction % 10 ;
fraction / = 10 ;
}
while ( i < maxDecimals )
fResult [ i + + ] = 48 ;
fResult . Reverse ( ) ;
result + = fResult ;
return result ;
}
/// Converts the given double floating point into a string.
/// @param [in] num The given double floating point to convert.
/// @param [in] maxDecimals The max decimal places to add.
/// @returns The resulting string representation.
static Str < T , N > FromNum ( const double num , const UInt_8 maxDecimals = 5 )
{
SInt_64 whole = ( SInt_64 ) num ;
Str < T , N > result ;
if ( whole < 0 )
result + = " - " ;
result + = Str < T , N > : : FromNum ( whole ) ;
UInt_64 power = 10 ;
for ( UInt_64 i = 0 ; i < ( UInt_64 ) maxDecimals - 1 ; + + i )
power * = 10 ;
SInt_64 fraction = ( SInt_64 ) ( ( num - ( double ) whole ) * ( double ) power ) ;
if ( ! fraction )
return result ;
result + = " . " ;
Str < T , N > fResult ( maxDecimals ) ;
N i = 0 ;
while ( fraction )
{
fResult [ i + + ] = 48 + fraction % 10 ;
fraction / = 10 ;
}
while ( i < maxDecimals )
fResult [ i + + ] = 48 ;
fResult . Reverse ( ) ;
result + = fResult ;
return result ;
}
/// Converts the given long double floating point into a string.
/// @param [in] num The given long double floating point to convert.
/// @param [in] maxDecimals The max decimal places to add.
/// @returns The resulting string representation.
static Str < T , N > FromNum ( const long double num , const UInt_8 maxDecimals = 5 )
{
SInt_64 whole = ( SInt_64 ) num ;
Str < T , N > result ;
if ( whole < 0 )
result + = " - " ;
result + = Str < T , N > : : FromNum ( whole ) ;
UInt_64 power = 10 ;
for ( UInt_64 i = 0 ; i < ( UInt_64 ) maxDecimals - 1 ; + + i )
power * = 10 ;
SInt_64 fraction = ( SInt_64 ) ( ( num - ( long double ) whole ) * ( long double ) power ) ;
if ( ! fraction )
return result ;
result + = " . " ;
Str < T , N > fResult ( maxDecimals ) ;
N i = 0 ;
while ( fraction )
{
fResult [ i + + ] = 48 + fraction % 10 ;
fraction / = 10 ;
}
while ( i < maxDecimals )
fResult [ i + + ] = 48 ;
fResult . Reverse ( ) ;
result + = fResult ;
return result ;
}
2024-06-29 22:20:53 -07:00
/// A 32-bit FNV-1a hash algorithm.
/// @param [in] str The string to hash.
/// @returns The resulting hash. Zero if string does not contain any characters.
static UInt_32 Hash_32 ( const Str < T , N > & str )
{
2024-02-05 22:25:30 -08:00
if ( ! str . Size ( ) )
return 0 ;
2024-06-29 22:20:53 -07:00
const Byte * const bytes = str . ToBytes ( ) ;
2024-02-05 22:25:30 -08:00
2024-06-29 22:20:53 -07:00
UInt_32 hash = 2166136261ul ;
2024-02-05 22:25:30 -08:00
2024-06-29 22:20:53 -07:00
for ( N i = 0 ; i < str . Size ( true ) ; + + i )
hash = ( hash ^ bytes [ i ] ) * 16777619 ;
2024-02-05 22:25:30 -08:00
2024-06-29 22:20:53 -07:00
return hash ;
}
2024-02-05 22:25:30 -08:00
/// A 32-bit FNV-1a hash algorithm.
/// @returns The resulting hash. Zero if string does not contain any characters.
UInt_32 Hash_32 ( ) const
{
if ( ! size )
return 0 ;
const Byte * const bytes = ToBytes ( ) ;
UInt_32 hash = 2166136261ul ;
for ( N i = 0 ; i < Size ( true ) ; + + i )
hash = ( hash ^ bytes [ i ] ) * 16777619 ;
return hash ;
}
2024-06-29 22:20:53 -07:00
/// A 64-bit FNV-1a hash algorithm.
/// @param [in] str The string to hash.
2024-02-05 22:25:30 -08:00
/// @returns The resulting hash. Zero if string does not contain any characters.
2024-06-29 22:20:53 -07:00
static UInt_64 Hash_64 ( const Str < T , N > & str )
{
2024-02-05 22:25:30 -08:00
if ( ! str . Size ( ) )
return 0 ;
2024-06-29 22:20:53 -07:00
const Byte * const bytes = str . ToBytes ( ) ;
2024-02-05 22:25:30 -08:00
2024-06-29 22:20:53 -07:00
UInt_64 hash = 14695981039346656037ull ;
2024-02-05 22:25:30 -08:00
2024-06-29 22:20:53 -07:00
for ( N i = 0 ; i < str . Size ( true ) ; + + i )
hash = ( hash ^ bytes [ i ] ) * 1099511628211 ;
2024-02-05 22:25:30 -08:00
2024-06-29 22:20:53 -07:00
return hash ;
}
2024-02-05 22:25:30 -08:00
/// A 64-bit FNV-1a hash algorithm.
/// @returns The resulting hash. Zero if string does not contain any characters.
UInt_64 Hash_64 ( ) const
{
if ( ! size )
return 0 ;
const Byte * const bytes = ToBytes ( ) ;
UInt_64 hash = 14695981039346656037ull ;
for ( N i = 0 ; i < Size ( true ) ; + + i )
hash = ( hash ^ bytes [ i ] ) * 1099511628211 ;
return hash ;
}
/// Calculates the length of a C-Style string.
/// @param [in] str The C-Style string to calculate.
/// @returns The character count.
static N Len ( const T * const str )
{
N count = 0 ;
while ( str [ count ] )
+ + count ;
return count ;
}
/// Compares two C-style string with each other.
/// @param [in] a The first C-style string to compare.
/// @param [in] b The second C-style string to compare.
/// @returns True if both C-style strings are equal.
static bool Cmp ( const T * const a , const T * const b )
{
N aSize = Len ( a ) ;
N bSize = Len ( b ) ;
if ( aSize ! = bSize )
return false ;
for ( UInt_64 i = 0 ; i < aSize ; + + i )
if ( a [ i ] ! = b [ i ] )
return false ;
return true ;
}
} ;
typedef Str < Char_32 , UInt_64 > Str_32 ;
typedef Str < Char_16 , UInt_64 > Str_16 ;
typedef Str < Char_8 , UInt_64 > Str_8 ;
}
template < typename T = ehs : : Char_8 , typename N = ehs : : UInt_64 >
bool operator = = ( const T * const first , const ehs : : Str < T , N > & second )
{
N inSize = ehs : : Str < T , N > : : Len ( first ) ;
if ( second . Size ( ) ! = inSize )
return false ;
return ehs : : Util : : Compare ( first , second , second . Size ( true ) ) ;
}
template < typename T = ehs : : Char_8 , typename N = ehs : : UInt_64 >
bool operator ! = ( const T * const first , const ehs : : Str < T , N > & second )
{
N inSize = ehs : : Str < T , N > : : Len ( first ) ;
if ( second . Size ( ) ! = inSize )
return true ;
return ! ehs : : Util : : Compare ( first , second , second . Size ( true ) ) ;
}
/// Concatenates a C-style string with a string.
/// @param [in] first The given C-style string.
/// @param [in] second The given string.
/// @returns The result.
template < typename T = ehs : : Char_8 , typename N = ehs : : UInt_64 >
ehs : : Str < T , N > operator + ( const T * const first , const ehs : : Str < T , N > & second )
{
N inSize = ehs : : Str < T , N > : : Len ( first ) ;
ehs : : Str < T , N > result ( inSize + second . Size ( ) ) ;
ehs : : Util : : Copy ( result , first , inSize * sizeof ( T ) ) ;
ehs : : Util : : Copy ( & result [ inSize ] , & second [ 0 ] , second . Size ( true ) ) ;
result [ inSize + second . Size ( ) ] = 0 ;
return result ;
}