#pragma once
#ifndef __HWINSTRING_H__
#define __HWINSTRING_H__
#include "hwindef.h"
#include "hwinexception.h"
#ifdef _MANAGED
#pragma managed(push,off)
#endif
#pragma pack(push,8)
namespace harlinn
{
namespace windows
{
class Guid;
class DateTime;
class TimeSpan;
class AnsiString
{
public:
typedef unsigned long long size_type;
typedef char value_type;
typedef std::string stdstring;
static const size_type npos = MAXDWORD64;
static const char defaultPadCharacter = '\x20';
typedef value_type* iterator;
typedef const value_type* const_iterator;
typedef std::basic_regex<value_type> Regex;
typedef std::match_results<const_iterator> MatchResults;
friend HWIN_EXPORT std::ostream& operator << ( std::ostream& os, const AnsiString& s );
private:
HWIN_EXPORT static char* empty;
struct Buffer
{
size_type referenceCount;
size_type length;
char data[128];
};
char* data_;
Buffer* toBuffer( ) const
{
if ( data_ )
{
return ( Buffer* )( ( ( char* )data_ ) - offsetof( Buffer, data ) );
}
return nullptr;
}
static Buffer* toBuffer( const char* data )
{
if ( data )
{
return ( Buffer* )( ( ( char* )data ) - offsetof( Buffer, data ) );
}
return nullptr;
}
static const size_type nonTextBufferByteCount = offsetof( Buffer, data ) + sizeof( char );
static const size_type minBufferByteCount = 64;
static const size_type minReservedCharacters = ( minBufferByteCount - nonTextBufferByteCount ) / sizeof( char );
static size_type allocationByteCount( size_type length )
{
if ( length )
{
if ( length < minReservedCharacters )
{
return minBufferByteCount;
}
size_type bytesRequired = nonTextBufferByteCount + length*sizeof( char );
size_type remainder = bytesRequired % minBufferByteCount;
if ( remainder != 0 )
{
bytesRequired += minBufferByteCount - remainder;
}
return bytesRequired;
}
return 0;
}
static Buffer* allocate( size_type length )
{
if ( length )
{
size_type byteCount = allocationByteCount( length );
Buffer* result = ( Buffer* )new char[byteCount];
result->referenceCount = 1;
result->length = length;
result->data[length] = 0;
return result;
}
return nullptr;
}
Buffer* EnsureUnique( )
{
Buffer* buffer = toBuffer( );
if ( buffer )
{
if ( buffer->referenceCount > 1 )
{
auto byteCount = allocationByteCount( buffer->length );
Buffer* newBuffer = ( Buffer* )new char[byteCount];
newBuffer->referenceCount = 1;
newBuffer->length = buffer->length;
memcpy( newBuffer->data, buffer->data, buffer->length*sizeof( char ) );
newBuffer->data[buffer->length] = 0;
Release( );
data_ = newBuffer->data;
return newBuffer;
}
}
return buffer;
}
Buffer* ReallocateUnique( size_type length )
{
Buffer* buffer = toBuffer( );
if ( buffer )
{
auto currentByteCount = allocationByteCount( buffer->length );
auto newByteCount = allocationByteCount( length );
if ( !newByteCount )
{
Release( );
return nullptr;
}
else
{
if ( ( buffer->referenceCount > 1 ) || ( currentByteCount != newByteCount ) )
{
Buffer* newBuffer = ( Buffer* )new char[newByteCount];
newBuffer->referenceCount = 1;
newBuffer->length = length;
size_type copyCount = std::min( buffer->length, length ) + 2;
memcpy( newBuffer->data, buffer->data, copyCount*sizeof( char ) );
newBuffer->data[length] = 0;
Release( );
data_ = newBuffer->data;
return newBuffer;
}
buffer->length = length;
buffer->data[length] = 0;
}
}
else
{
buffer = allocate( length );
data_ = buffer->data;
}
return buffer;
}
void Release( )
{
Buffer* buffer = toBuffer( );
if ( buffer )
{
LONG64 res = InterlockedDecrement64( ( LONG64* )&( buffer->referenceCount ) );
if ( res == 0 )
{
char* bytes = ( char* )buffer;
delete bytes;
}
data_ = nullptr;
}
}
void AddRef( const AnsiString& other )
{
if ( other.data_ != data_ )
{
Release( );
if ( other.data_ )
{
data_ = other.data_;
Buffer* buffer = toBuffer( );
InterlockedIncrement64( ( LONG64* )&( buffer->referenceCount ) );
}
}
}
static int Compare( Buffer* buffer1, Buffer* buffer2 )
{
if ( buffer1 == buffer2 )
{
return 0;
}
if ( buffer1 && buffer2 )
{
size_type compareLength = std::min( buffer1->length, buffer2->length );
for ( size_type i = 0; i < compareLength; i++ )
{
int res = int( buffer1->data[i] ) - int( buffer2->data[i] );
if ( res != 0 )
{
return res;
}
}
if ( buffer1->length > buffer2->length )
{
return 1;
}
if ( buffer1->length < buffer2->length )
{
return -1;
}
return 0;
}
else if ( buffer1 )
{
return 1;
}
else if ( buffer2 )
{
return -1;
}
return 0;
}
static int Compare( Buffer* buffer1, const char* str )
{
if ( buffer1 && str && str[0] != 0 )
{
size_type length = strlen( str );
size_type compareLength = std::min( buffer1->length, length );
for ( size_type i = 0; i < compareLength; i++ )
{
int res = int( buffer1->data[i] ) - int( str[i] );
if ( res != 0 )
{
return res;
}
}
if ( buffer1->length > length )
{
return 1;
}
if ( buffer1->length < length )
{
return -1;
}
return 0;
}
else if ( buffer1 )
{
return 1;
}
else if ( str && str[0] != 0 )
{
return -1;
}
return 0;
}
static int ICompare( Buffer* buffer1, Buffer* buffer2 )
{
if ( buffer1 == buffer2 )
{
return 0;
}
if ( buffer1 && buffer2 )
{
auto result = CompareStringA( LOCALE_USER_DEFAULT, NORM_IGNORECASE, buffer1->data, static_cast<int>( buffer1->length ), buffer2->data, static_cast<int>( buffer2->length ) );
if ( !result )
{
ThrowLastOSError( );
}
return result - 2;
}
else if ( buffer1 )
{
return 1;
}
else if ( buffer2 )
{
return -1;
}
return 0;
}
static int ICompare( Buffer* buffer1, const char* buffer2 )
{
if ( buffer1 && buffer2 )
{
auto result = CompareStringA( LOCALE_USER_DEFAULT, NORM_IGNORECASE, buffer1->data, static_cast<int>( buffer1->length ), buffer2, -1 );
if ( !result )
{
ThrowLastOSError( );
}
return result - 2;
}
else if ( buffer1 )
{
return 1;
}
else if ( buffer2 )
{
return -1;
}
return 0;
}
static void* memichr( const void * buf, int chr, size_t cnt )
{
chr = toupper( chr );
while ( cnt && ( toupper( *( char * )buf ) != chr ) )
{
buf = ( char * )buf + 1;
cnt--;
}
return( cnt ? ( void * )buf : nullptr );
}
public:
HWIN_EXPORT static AnsiString From( const std::string& s );
HWIN_EXPORT static AnsiString From( const char* s );
HWIN_EXPORT static AnsiString From( const char* s, size_type theLength );
static AnsiString From( const AnsiString& s )
{
return s;
}
HWIN_EXPORT static AnsiString From( const WideString& s );
HWIN_EXPORT static AnsiString From( const std::wstring& s );
HWIN_EXPORT static AnsiString From( const wchar_t* s );
HWIN_EXPORT static AnsiString From( const wchar_t* s, size_type theLength );
HWIN_EXPORT static AnsiString From( char value, int radix = 10 );
HWIN_EXPORT static AnsiString From( unsigned char value, int radix = 10 );
HWIN_EXPORT static AnsiString From( short value, int radix = 10 );
HWIN_EXPORT static AnsiString From( unsigned short value, int radix = 10 );
HWIN_EXPORT static AnsiString From( int value, int radix = 10 );
HWIN_EXPORT static AnsiString From( unsigned int value, int radix = 10 );
HWIN_EXPORT static AnsiString From( long long value, int radix = 10 );
HWIN_EXPORT static AnsiString From( unsigned long long value, int radix = 10 );
HWIN_EXPORT static AnsiString From( float value, char* fmt = "%g" );
HWIN_EXPORT static AnsiString From( double value, char* fmt = "%g" );
HWIN_EXPORT static AnsiString From( DateTime value );
// Default constructor
AnsiString( )
: data_( nullptr )
{
}
// Copy constructor
AnsiString( const AnsiString& other )
: data_( nullptr )
{
if ( other.data_ )
{
data_ = other.data_;
Buffer* buffer = toBuffer( );
InterlockedIncrement64( ( LONG64* )&( buffer->referenceCount ) );
}
}
// Move constructor
AnsiString( AnsiString&& other )
: data_( nullptr )
{
data_ = other.data_;
other.data_ = nullptr;
}
// Constructs a string filled with length instances of the character c
AnsiString( size_type length, char c )
: data_( nullptr )
{
if ( length )
{
ReallocateUnique( length );
std::fill( data_, data_ + length, c );
}
}
// Constructs a string with size == length, and if str != nullptr copies
// length number of characters from str, if str == nullptr the string is
// filled with length instances of the character padCharacter
AnsiString( const char* str, size_type length, char padCharacter = defaultPadCharacter )
: data_( nullptr )
{
if ( length )
{
ReallocateUnique( length );
if ( str )
{
memcpy( data_, str, length );
}
else
{
memset( data_, padCharacter, length );
}
}
}
AnsiString( const char* str1, size_type length1, const char* str2, size_type length2, char padCharacter = defaultPadCharacter )
: data_( nullptr )
{
size_type totalLength = length1 + length2;
if ( totalLength )
{
ReallocateUnique( totalLength );
if ( str1 )
{
memcpy( data_, str1, length1 );
}
else
{
memset( data_, padCharacter, length1 );
}
if ( str2 )
{
memcpy( &data_[length1], str2, length2 );
}
else
{
memset( data_ + length1, padCharacter, length2 );
}
}
}
AnsiString( const char* str1, size_type length1, const char* str2, size_type length2, const char* str3, size_type length3, char padCharacter = defaultPadCharacter )
: data_( nullptr )
{
size_type totalLength = length1 + length2 + length3;
if ( totalLength )
{
ReallocateUnique( totalLength );
if ( str1 )
{
memcpy_s( data_, length1, str1, length1 );
}
else
{
memset( data_, padCharacter, length1 );
}
if ( str2 )
{
memcpy_s( &data_[length1], length2, str2, length2 );
}
else
{
memset( data_ + length1, padCharacter, length2 );
}
if ( str3 )
{
memcpy_s( &data_[length2], length3, str3, length3 );
}
else
{
memset( data_ + length1 + length2, padCharacter, length3 );
}
}
}
AnsiString( const std::string& str )
: data_( nullptr )
{
if ( str.length( ) )
{
ReallocateUnique( str.length( ) );
memcpy( data_, str.c_str( ), str.length( ) );
}
}
AnsiString( const std::string& str1, const std::string& str2 )
: data_( nullptr )
{
if ( str1.length( ) && str2.length( ) )
{
ReallocateUnique( str1.length( ) + str2.length( ) );
memcpy( data_, str1.c_str( ), str1.length( ) );
memcpy( &data_[str1.length( )], str2.c_str( ), str2.length( ) );
}
else if ( str1.length( ) && str2.length( ) == 0 )
{
ReallocateUnique( str1.length( ) );
memcpy( data_, str1.c_str( ), str1.length( ) );
}
else if ( str2.length( ) && str1.length( ) == 0 )
{
ReallocateUnique( str2.length( ) );
memcpy( data_, str2.c_str( ), str2.length( ) );
}
}
AnsiString( const AnsiString& str1, const AnsiString& str2 )
: data_( nullptr )
{
if ( str1.length( ) && str2.length( ) )
{
ReallocateUnique( str1.length( ) + str2.length( ) );
memcpy( data_, str1.c_str( ), str1.length( ) );
memcpy( &data_[str1.length( )], str2.c_str( ), str2.length( ) );
}
else if ( str1.length( ) && str2.length( ) == 0 )
{
ReallocateUnique( str1.length( ) );
memcpy( data_, str1.c_str( ), str1.length( ) );
}
else if ( str2.length( ) && str1.length( ) == 0 )
{
ReallocateUnique( str2.length( ) );
memcpy( data_, str2.c_str( ), str2.length( ) );
}
}
AnsiString( const char* str )
: data_( nullptr )
{
if ( str )
{
size_type length = strlen( str );
if ( length )
{
ReallocateUnique( length );
memcpy_s( data_, length, str, length );
}
}
}
explicit AnsiString( char c )
: data_( nullptr )
{
ReallocateUnique( 1 );
data_[0] = c;
}
~AnsiString( )
{
if ( data_ )
{
Release( );
}
}
AnsiString& operator = ( const AnsiString& other )
{
AddRef( other );
return *this;
}
AnsiString& operator = ( const char* str )
{
if ( !str || str[0] == 0 )
{
Release( );
}
else
{
if ( str != data_ )
{
Buffer* thisBuffer = toBuffer( );
if ( thisBuffer && str >= data_ && str < data_ + thisBuffer->length )
{
size_type offset = str - data_;
size_type length = thisBuffer->length - offset;
EnsureUnique( );
str = data_ + offset;
memmove( data_, str, length*sizeof( char ) );
ReallocateUnique( length );
}
else
{
size_type length = strlen( str );
thisBuffer = ReallocateUnique( length );
memcpy( data_, str, length );
}
}
}
return *this;
}
AnsiString& operator = ( AnsiString&& other )
{
if ( this != &other )
{
data_ = other.data_;
other.data_ = nullptr;
}
return *this;
}
AnsiString& operator = ( const std::string& str )
{
if ( str.length( ) )
{
ReallocateUnique( str.length( ) );
memcpy( data_, str.c_str( ), str.length( ) );
}
return *this;
}
AnsiString& operator = ( char c )
{
ReallocateUnique( 1 );
data_[0] = c;
}
int CompareTo( const AnsiString& other ) const
{
return Compare( toBuffer( ), other.toBuffer( ) );
}
int CompareTo( const char* str ) const
{
return Compare( toBuffer( ), str );
}
int CompareTo( const AnsiString& other, bool ignoreCase ) const
{
if ( ignoreCase )
{
return ICompare( toBuffer( ), other.toBuffer( ) );
}
else
{
return Compare( toBuffer( ), other.toBuffer( ) );
}
}
int CompareTo( const char* str, bool ignoreCase ) const
{
if ( ignoreCase )
{
return ICompare( toBuffer( ), str );
}
else
{
return Compare( toBuffer( ), str );
}
}
int ICompareTo( const AnsiString& other ) const
{
return ICompare( toBuffer( ), other.toBuffer( ) );
}
int ICompareTo( const char* str ) const
{
return ICompare( toBuffer( ), str );
}
int compare( const AnsiString& other ) const
{
return Compare( toBuffer( ), other.toBuffer( ) );
}
int compare( const char* str ) const
{
return Compare( toBuffer( ), str );
}
int icompare( const AnsiString& other ) const
{
return ICompare( toBuffer( ), other.toBuffer( ) );
}
int icompare( const char* str ) const
{
return ICompare( toBuffer( ), str );
}
size_t hash( ) const
{
size_t result = 0;
if ( data_ )
{
auto theBuffer = toBuffer( );
switch ( theBuffer->length )
{
case 0:
break;
case 1:
result = *( unsigned char* )data_;
break;
case 2:
case 3:
result = *( unsigned short* )data_;
break;
case 4:
case 5:
case 6:
case 7:
result = *( unsigned int* )data_;
break;
default:
result = *( size_t* )data_;
break;
}
}
return result;
}
bool operator == ( const AnsiString& other ) const
{
return CompareTo( other ) == 0;
}
bool operator != ( const AnsiString& other ) const
{
return CompareTo( other ) != 0;
}
bool operator <= ( const AnsiString& other ) const
{
return CompareTo( other ) <= 0;
}
bool operator < ( const AnsiString& other ) const
{
return CompareTo( other ) < 0;
}
bool operator >= ( const AnsiString& other ) const
{
return CompareTo( other ) >= 0;
}
bool operator > ( const AnsiString& other ) const
{
return CompareTo( other ) > 0;
}
bool operator == ( const char* str ) const
{
return CompareTo( str ) == 0;
}
bool operator != ( const char* str ) const
{
return CompareTo( str ) != 0;
}
bool operator <= ( const char* str ) const
{
return CompareTo( str ) <= 0;
}
bool operator < ( const char* str ) const
{
return CompareTo( str ) < 0;
}
bool operator >= ( const char* str ) const
{
return CompareTo( str ) >= 0;
}
bool operator > ( const char* str ) const
{
return CompareTo( str ) > 0;
}
AnsiString& Append( const AnsiString& other )
{
Buffer* otherBuffer = other.toBuffer( );
if ( otherBuffer && otherBuffer->length )
{
Buffer* thisBuffer = toBuffer( );
if ( !thisBuffer )
{
data_ = otherBuffer->data;
InterlockedIncrement64( ( LONG64* )&( otherBuffer->referenceCount ) );
}
else
{
size_type oldLength = thisBuffer->length;
if ( thisBuffer == otherBuffer )
{
thisBuffer = ReallocateUnique( thisBuffer->length + thisBuffer->length );
memcpy( &thisBuffer->data[oldLength], thisBuffer->data, oldLength );
}
else
{
thisBuffer = ReallocateUnique( thisBuffer->length + otherBuffer->length );
memcpy( &thisBuffer->data[oldLength], otherBuffer->data, otherBuffer->length );
}
}
}
return *this;
}
AnsiString& Append( const char* str, size_type length )
{
if ( str )
{
Buffer* thisBuffer = toBuffer( );
if ( !thisBuffer )
{
if ( length )
{
ReallocateUnique( length );
memcpy_s( data_, length, str, length );
}
}
else if ( ( str == data_ ) && ( length >= thisBuffer->length ) )
{
size_type oldLength = thisBuffer->length;
thisBuffer = ReallocateUnique( thisBuffer->length + thisBuffer->length );
memmove_s( &thisBuffer->data[oldLength], oldLength, thisBuffer->data, oldLength );
}
else if ( str > data_ && str < ( data_ + thisBuffer->length ) )
{
size_type offset = str - data_;
if ( length >( thisBuffer->length - offset ) )
{
length = thisBuffer->length - offset;
}
size_type oldLength = thisBuffer->length;
thisBuffer = ReallocateUnique( oldLength + length );
str = data_ + offset;
memmove_s( &thisBuffer->data[oldLength], length, str, length );
}
else
{
Buffer* thisBuffer = toBuffer( );
size_type oldLength = thisBuffer->length;
thisBuffer = ReallocateUnique( oldLength + length );
memmove_s( &thisBuffer->data[oldLength], length, str, length );
}
}
return *this;
}
AnsiString& append( const char* str, size_type length )
{
Append( str, length );
return *this;
}
AnsiString& Append( const char* str )
{
if ( str && str[0] )
{
Buffer* thisBuffer = toBuffer( );
if ( !thisBuffer )
{
size_type length = strlen( str );
if ( length )
{
ReallocateUnique( length );
memmove_s( data_, length, str, length );
}
}
else if ( str == data_ )
{
size_type oldLength = thisBuffer->length;
thisBuffer = ReallocateUnique( thisBuffer->length + thisBuffer->length );
memmove_s( &thisBuffer->data[oldLength], oldLength, thisBuffer->data, oldLength );
}
else if ( str > data_ && str < ( data_ + thisBuffer->length ) )
{
size_type offset = str - data_;
size_type length = thisBuffer->length - offset;
size_type oldLength = thisBuffer->length;
thisBuffer = ReallocateUnique( thisBuffer->length + length );
str = data_ + offset;
memmove_s( &thisBuffer->data[oldLength], length, str, length );
}
else
{
size_type length = strlen( str );
Buffer* thisBuffer = toBuffer( );
size_type oldLength = thisBuffer->length;
thisBuffer = ReallocateUnique( thisBuffer->length + length );
memmove_s( &thisBuffer->data[oldLength], length, str, length );
}
}
return *this;
}
AnsiString& Append( char c, size_type numberOfTimes )
{
Buffer* thisBuffer = toBuffer( );
if ( !thisBuffer )
{
thisBuffer = ReallocateUnique( numberOfTimes );
memset( thisBuffer->data, c, numberOfTimes );
}
else
{
size_type oldLength = thisBuffer->length;
thisBuffer = ReallocateUnique( oldLength + numberOfTimes );
memset( &thisBuffer->data[oldLength], c, numberOfTimes );
}
return *this;
}
AnsiString& Append( char c )
{
Buffer* thisBuffer = toBuffer( );
if ( !thisBuffer )
{
thisBuffer = ReallocateUnique( 1 );
data_[0] = c;
}
else
{
size_type oldLength = thisBuffer->length;
thisBuffer = ReallocateUnique( oldLength + 1 );
data_[oldLength] = c;
}
return *this;
}
AnsiString Appended( const AnsiString& other ) const
{
Buffer* thisBuffer = toBuffer( );
Buffer* otherBuffer = other.toBuffer( );
if ( thisBuffer && otherBuffer )
{
AnsiString result( thisBuffer->data, thisBuffer->length, otherBuffer->data, otherBuffer->length );
return result;
}
else if ( thisBuffer )
{
AnsiString result( *this );
return result;
}
return other;
}
AnsiString Appended( const char* str ) const
{
Buffer* thisBuffer = toBuffer( );
if ( thisBuffer && str && str[0] )
{
size_type length = strlen( str );
AnsiString result( thisBuffer->data, thisBuffer->length, str, length );
return result;
}
else if ( thisBuffer )
{
AnsiString result( *this );
return result;
}
else if ( str && str[0] )
{
return AnsiString( str );
}
return AnsiString( );
}
AnsiString Appended( char c, size_type numberOfTimes ) const
{
Buffer* thisBuffer = toBuffer( );
if ( thisBuffer )
{
AnsiString result( thisBuffer->data, thisBuffer->length, nullptr, numberOfTimes, c );
return result;
}
else
{
AnsiString result( nullptr, numberOfTimes, c );
return result;
}
}
AnsiString& assign( const char* s, size_t length )
{
if ( length == 0 )
{
this->Release( );
}
else
{
Buffer* thisBuffer = ReallocateUnique( length );
memcpy_s( thisBuffer->data, length + 1, s, length );
}
return *this;
}
AnsiString& operator += ( const AnsiString& other )
{
return Append( other );
}
AnsiString& operator += ( const char* str )
{
return Append( str );
}
AnsiString& operator += ( const char c )
{
return Append( c );
}
friend AnsiString operator + ( const AnsiString& str1, const AnsiString& str2 )
{
return str1.Appended( str2 );
}
friend AnsiString operator + ( const AnsiString& str1, const char* str2 )
{
return str1.Appended( str2 );
}
friend AnsiString operator + ( const AnsiString& str, const char c )
{
return str.Appended( c, 1 );
}
char& operator[]( size_type index )
{
#ifdef _DEBUG
Buffer* buffer = EnsureUnique( );
if ( !buffer || index >= buffer->length )
{
throw ArgumentOutOfRangeException( "index" );
}
return data_[index];
#else
return data_[index];
#endif
}
char operator[]( size_type index ) const
{
#ifdef _DEBUG
Buffer* buffer = toBuffer( );
if ( !buffer || index >= buffer->length )
{
throw ArgumentOutOfRangeException( "index" );
}
return data_[index];
#else
return data_[index];
#endif
}
AnsiString& SetLength( size_type newLength )
{
Buffer* buffer = toBuffer( );
if ( buffer && buffer->length != newLength )
{
ReallocateUnique( newLength );
}
else if ( newLength )
{
ReallocateUnique( newLength );
}
return *this;
}
AnsiString& SetString( const char* text, size_type textLength )
{
Buffer* buffer = ReallocateUnique( textLength );
if ( buffer )
{
memcpy( buffer->data, text, textLength );
}
return *this;
}
size_type size( ) const
{
Buffer* buffer = toBuffer( );
if ( buffer )
{
return buffer->length;
}
return 0;
}
size_type length( ) const
{
Buffer* buffer = toBuffer( );
if ( buffer )
{
return buffer->length;
}
return 0;
}
size_type Length( ) const
{
Buffer* buffer = toBuffer( );
if ( buffer )
{
return buffer->length;
}
return 0;
}
const char* c_str( ) const
{
if ( !data_ )
{
return empty;
}
return data_;
}
char* c_str( )
{
EnsureUnique( );
if ( !data_ )
{
return empty;
}
return data_;
}
const char* data( ) const
{
return data_;
}
char* data( )
{
EnsureUnique( );
return data_;
}
bool IsEmpty( ) const
{
return size( ) == 0;
}
explicit operator bool( ) const
{
return size( ) != 0;
}
const char* begin( ) const
{
return data_;
}
const char* end( ) const
{
if ( data_ )
{
Buffer* buffer = toBuffer( );
return data_ + buffer->length;
}
else
{
return data_;
}
}
const char* cbegin( ) const
{
return data_;
}
const char* cend( ) const
{
if ( data_ )
{
Buffer* buffer = toBuffer( );
return data_ + buffer->length;
}
else
{
return data_;
}
}
char* begin( )
{
EnsureUnique( ); return data_;
}
char* end( )
{
if ( data_ )
{
Buffer* buffer = EnsureUnique( );
return data_ + buffer->length;
}
else
{
return data_;
}
}
size_type IndexOfAnyOf( const char *searchChars, size_type numberOfSearchChars, size_type start ) const
{
Buffer* thisBuffer = toBuffer( );
if ( thisBuffer && searchChars && numberOfSearchChars )
{
while ( start < thisBuffer->length )
{
const value_type *p = ( const value_type * )memchr( searchChars, thisBuffer->data[start], numberOfSearchChars );
if ( p )
{
return start;
}
start++;
}
}
return npos;
}
size_type IIndexOfAnyOf( const char *searchChars, size_type numberOfSearchChars, size_type start ) const
{
Buffer* thisBuffer = toBuffer( );
if ( thisBuffer && searchChars && numberOfSearchChars )
{
while ( start < thisBuffer->length )
{
value_type c = toupper( thisBuffer->data[start] );
for ( size_t i = 0; i < numberOfSearchChars; i++ )
{
value_type sc = toupper( searchChars[i] );
if ( c == sc )
{
return start;
}
}
start++;
}
}
return npos;
}
size_type IndexOfAnyOf( const AnsiString& searchChars, size_type start = 0 ) const
{
Buffer* searchCharBuffer = searchChars.toBuffer( );
if ( searchCharBuffer )
{
return IndexOfAnyOf( searchCharBuffer->data, searchCharBuffer->length, start );
}
return npos;
}
size_type IIndexOfAnyOf( const AnsiString& searchChars, size_type start = 0 ) const
{
Buffer* searchCharBuffer = searchChars.toBuffer( );
if ( searchCharBuffer )
{
return IIndexOfAnyOf( searchCharBuffer->data, searchCharBuffer->length, start );
}
return npos;
}
size_type IndexOfAnyOf( const char* searchChars, size_type start = 0 ) const
{
if ( searchChars && searchChars[0] )
{
size_type length = strlen( searchChars );
return IndexOfAnyOf( searchChars, length, start );
}
return npos;
}
size_type IIndexOfAnyOf( const char* searchChars, size_type start = 0 ) const
{
if ( searchChars && searchChars[0] )
{
size_type length = strlen( searchChars );
return IIndexOfAnyOf( searchChars, length, start );
}
return npos;
}
size_type IndexOfAnyBut( const char *searchChars, size_type numberOfSearchChars, size_type start ) const
{
Buffer* thisBuffer = toBuffer( );
if ( thisBuffer && searchChars && numberOfSearchChars )
{
while ( start < thisBuffer->length )
{
const value_type *p = ( const value_type * )memchr( searchChars, thisBuffer->data[start], numberOfSearchChars );
if ( !p )
{
return start;
}
start++;
}
}
return npos;
}
size_type IIndexOfAnyBut( const char *searchChars, size_type numberOfSearchChars, size_type start ) const
{
Buffer* thisBuffer = toBuffer( );
if ( thisBuffer && searchChars && numberOfSearchChars )
{
while ( start < thisBuffer->length )
{
value_type c = toupper( thisBuffer->data[start] );
size_t i = 0;
for ( ; i < numberOfSearchChars; i++ )
{
value_type sc = toupper( searchChars[i] );
if ( c == sc )
{
break;
}
}
if ( i == numberOfSearchChars )
{
return start;
}
start++;
}
}
return npos;
}
size_type IndexOfAnyBut( const AnsiString& searchChars, size_type start = 0 ) const
{
Buffer* searchCharBuffer = searchChars.toBuffer( );
if ( searchCharBuffer )
{
return IndexOfAnyBut( searchCharBuffer->data, searchCharBuffer->length, start );
}
return npos;
}
size_type IIndexOfAnyBut( const AnsiString& searchChars, size_type start = 0 ) const
{
Buffer* searchCharBuffer = searchChars.toBuffer( );
if ( searchCharBuffer )
{
return IIndexOfAnyBut( searchCharBuffer->data, searchCharBuffer->length, start );
}
return npos;
}
size_type IndexOfAnyBut( const char* searchChars, size_type start = 0 ) const
{
if ( searchChars && searchChars[0] )
{
size_type length = strlen( searchChars );
return IndexOfAnyBut( searchChars, length, start );
}
return npos;
}
size_type IIndexOfAnyBut( const char* searchChars, size_type start = 0 ) const
{
if ( searchChars && searchChars[0] )
{
size_type length = strlen( searchChars );
return IIndexOfAnyBut( searchChars, length, start );
}
return npos;
}
size_type LastIndexOfAnyOf( const char *searchChars, size_type numberOfSearchChars, size_type start ) const
{
Buffer* thisBuffer = toBuffer( );
if ( thisBuffer && numberOfSearchChars )
{
if ( start >= thisBuffer->length )
{
start = thisBuffer->length - 1;
}
do
{
const value_type *p = ( const value_type * )memchr( searchChars, thisBuffer->data[start], numberOfSearchChars );
if ( p )
{
return start;
}
} while ( start-- );
}
return npos;
}
size_type ILastIndexOfAnyOf( const char *searchChars, size_type numberOfSearchChars, size_type start ) const
{
Buffer* thisBuffer = toBuffer( );
if ( thisBuffer && numberOfSearchChars )
{
if ( start >= thisBuffer->length )
{
start = thisBuffer->length - 1;
}
do
{
value_type c = toupper( thisBuffer->data[start] );
for ( size_t i = 0; i < numberOfSearchChars; i++ )
{
value_type sc = toupper( searchChars[i] );
if ( c == sc )
{
return start;
}
}
} while ( start-- );
}
return npos;
}
size_type LastIndexOfAnyOf( const AnsiString& searchChars, size_type start = npos ) const
{
Buffer* searchCharBuffer = searchChars.toBuffer( );
if ( searchCharBuffer )
{
return LastIndexOfAnyOf( searchCharBuffer->data, searchCharBuffer->length, start );
}
return npos;
}
size_type ILastIndexOfAnyOf( const AnsiString& searchChars, size_type start = npos ) const
{
Buffer* searchCharBuffer = searchChars.toBuffer( );
if ( searchCharBuffer )
{
return ILastIndexOfAnyOf( searchCharBuffer->data, searchCharBuffer->length, start );
}
return npos;
}
size_type LastIndexOfAnyOf( const char* searchChars, size_type start = npos ) const
{
if ( searchChars && searchChars[0] )
{
size_type length = strlen( searchChars );
return LastIndexOfAnyOf( searchChars, length, start );
}
return npos;
}
size_type ILastIndexOfAnyOf( const char* searchChars, size_type start = npos ) const
{
if ( searchChars && searchChars[0] )
{
size_type length = strlen( searchChars );
return ILastIndexOfAnyOf( searchChars, length, start );
}
return npos;
}
size_type LastIndexOfAnyBut( const char *searchChars, size_type numberOfSearchChars, size_type start ) const
{
Buffer* thisBuffer = toBuffer( );
if ( thisBuffer )
{
if ( start >= thisBuffer->length )
{
start = thisBuffer->length - 1;
}
do
{
const value_type *p = ( const value_type * )memchr( searchChars, thisBuffer->data[start], numberOfSearchChars );
if ( !p )
{
return start;
}
} while ( start-- );
}
return npos;
}
size_type ILastIndexOfAnyBut( const char *searchChars, size_type numberOfSearchChars, size_type start ) const
{
Buffer* thisBuffer = toBuffer( );
if ( thisBuffer )
{
if ( start >= thisBuffer->length )
{
start = thisBuffer->length - 1;
}
do
{
value_type c = toupper( thisBuffer->data[start] );
size_t i = 0;
for ( ; i < numberOfSearchChars; i++ )
{
value_type sc = toupper( searchChars[i] );
if ( c == sc )
{
break;
}
}
if ( i == numberOfSearchChars )
{
return start;
}
} while ( start-- );
}
return npos;
}
size_type LastIndexOfAnyBut( const AnsiString& searchChars, size_type start = npos ) const
{
Buffer* searchCharBuffer = searchChars.toBuffer( );
if ( searchCharBuffer )
{
return LastIndexOfAnyBut( searchCharBuffer->data, searchCharBuffer->length, start );
}
return npos;
}
size_type ILastIndexOfAnyBut( const AnsiString& searchChars, size_type start = npos ) const
{
Buffer* searchCharBuffer = searchChars.toBuffer( );
if ( searchCharBuffer )
{
return ILastIndexOfAnyBut( searchCharBuffer->data, searchCharBuffer->length, start );
}
return npos;
}
size_type LastIndexOfAnyBut( const char* searchChars, size_type start = npos ) const
{
if ( searchChars && searchChars[0] )
{
size_type length = strlen( searchChars );
return LastIndexOfAnyBut( searchChars, length, start );
}
return npos;
}
size_type ILastIndexOfAnyBut( const char* searchChars, size_type start = npos ) const
{
if ( searchChars && searchChars[0] )
{
size_type length = strlen( searchChars );
return ILastIndexOfAnyBut( searchChars, length, start );
}
return npos;
}
size_type IndexOf( const char *searchString, size_type searchStringLength, size_type start ) const
{
Buffer* thisBuffer = toBuffer( );
if ( thisBuffer && ( start < thisBuffer->length ) )
{
if ( searchStringLength == 1 )
{
const value_type *p = ( const value_type * )memchr( &thisBuffer->data[start], *searchString, thisBuffer->length - start );
if ( p )
{
return p - thisBuffer->data;
}
}
else if ( searchStringLength )
{
while ( ( start + searchStringLength ) <= thisBuffer->length )
{
if ( memcmp( &thisBuffer->data[start], searchString, searchStringLength ) == 0 )
{
return start;
}
start++;
}
}
}
return npos;
}
size_type IIndexOf( const char *searchString, size_type searchStringLength, size_type start ) const
{
Buffer* thisBuffer = toBuffer( );
if ( thisBuffer && ( start < thisBuffer->length ) )
{
if ( searchStringLength == 1 )
{
const value_type *p = ( const value_type * )memichr( &thisBuffer->data[start], *searchString, thisBuffer->length - start );
if ( p )
{
return p - thisBuffer->data;
}
}
else if ( searchStringLength )
{
while ( ( start + searchStringLength ) <= thisBuffer->length )
{
if ( _memicmp( &thisBuffer->data[start], searchString, searchStringLength ) == 0 )
{
return start;
}
start++;
}
}
}
return npos;
}
size_type IndexOf( const AnsiString& searchString, size_type start = 0 ) const
{
Buffer* searchStringBuffer = searchString.toBuffer( );
if ( searchStringBuffer )
{
return IndexOf( searchStringBuffer->data, searchStringBuffer->length, start );
}
return npos;
}
size_type IIndexOf( const AnsiString& searchString, size_type start = 0 ) const
{
Buffer* searchStringBuffer = searchString.toBuffer( );
if ( searchStringBuffer )
{
return IIndexOf( searchStringBuffer->data, searchStringBuffer->length, start );
}
return npos;
}
size_type IndexOf( const char* searchString, size_type start = 0 ) const
{
Buffer* thisBuffer = toBuffer( );
if ( searchString && searchString[0] && thisBuffer && start < thisBuffer->length )
{
const char* pStart = &thisBuffer->data[start];
const char* pEnd = &thisBuffer->data[thisBuffer->length];
while ( pStart < pEnd )
{
const value_type* p = ( value_type* )memchr( pStart, *searchString, pEnd - pStart );
if ( p )
{
const char* pSearchChar = searchString + 1;
const char* pContent = p + 1;
while ( *pSearchChar )
{
if ( *pContent != *pSearchChar )
{
break;
}
pContent++;
pSearchChar++;
}
if ( !( *pSearchChar ) )
{
return p - thisBuffer->data;
}
pStart = p + 1;
}
else
{
return npos;
}
}
}
return npos;
}
size_type IIndexOf( const char* searchString, size_type start = 0 ) const
{
Buffer* thisBuffer = toBuffer( );
if ( searchString && searchString[0] && thisBuffer && start < thisBuffer->length )
{
const char* pStart = &thisBuffer->data[start];
const char* pEnd = &thisBuffer->data[thisBuffer->length];
while ( pStart < pEnd )
{
const value_type* p = ( value_type* )memichr( pStart, *searchString, pEnd - pStart );
if ( p )
{
const char* pSearchChar = searchString + 1;
const char* pContent = p + 1;
while ( *pSearchChar )
{
if ( toupper( *pContent ) != toupper( *pSearchChar ) )
{
break;
}
pContent++;
pSearchChar++;
}
if ( !( *pSearchChar ) )
{
return p - thisBuffer->data;
}
pStart = p + 1;
}
else
{
return npos;
}
}
}
return npos;
}
size_type IndexOf( const char c, size_type start = 0 ) const
{
Buffer* thisBuffer = toBuffer( );
if ( thisBuffer && start < thisBuffer->length )
{
const value_type* p = ( value_type* )memchr( &data_[start], c, thisBuffer->length - start );
if ( p )
{
return p - data_;
}
}
return npos;
}
size_type IndexOf( bool( *test )( char ), size_type start = 0 ) const
{
Buffer* thisBuffer = toBuffer( );
if ( thisBuffer )
{
while ( start < thisBuffer->length )
{
char c = thisBuffer->data[start];
if ( test( c ) )
{
return start;
}
start++;
}
}
return npos;
}
size_type IndexOf( bool( *test )( const char*, size_type length ), size_type start = 0 ) const
{
Buffer* thisBuffer = toBuffer( );
if ( ( thisBuffer ) && ( start < thisBuffer->length ) )
{
char* pStart = &thisBuffer->data[start];
size_type remainingLength = thisBuffer->length - start;
while ( remainingLength )
{
if ( test( pStart, remainingLength ) )
{
return start;
}
remainingLength--;
pStart++;
}
}
return npos;
}
size_type IndexOf( bool( *test )( const char*, const char* ), size_type start = 0 ) const
{
Buffer* thisBuffer = toBuffer( );
if ( ( thisBuffer ) && ( start < thisBuffer->length ) )
{
const char* pStart = &thisBuffer->data[start];
const char* pEnd = end( );
while ( pStart < pEnd )
{
if ( test( pStart, pEnd ) )
{
return start;
}
pStart++;
}
}
return npos;
}
size_type LastIndexOf( const char *searchString, size_type searchStringLength, size_type start ) const
{
Buffer* thisBuffer = toBuffer( );
if ( thisBuffer && ( searchStringLength <= thisBuffer->length ) )
{
if ( start > ( thisBuffer->length - searchStringLength ) )
{
start = thisBuffer->length - searchStringLength;
}
if ( searchStringLength == 1 )
{
do
{
if ( thisBuffer->data[start] == *searchString )
{
return start;
}
} while ( start-- );
}
else if ( searchStringLength )
{
do
{
if ( memcmp( &thisBuffer->data[start], searchString, searchStringLength ) == 0 )
{
return start;
}
} while ( start-- );
}
}
return npos;
}
size_type ILastIndexOf( const char *searchString, size_type searchStringLength, size_type start ) const
{
Buffer* thisBuffer = toBuffer( );
if ( thisBuffer && ( searchStringLength <= thisBuffer->length ) )
{
if ( start > ( thisBuffer->length - searchStringLength ) )
{
start = thisBuffer->length - searchStringLength;
}
if ( searchStringLength == 1 )
{
do
{
if ( toupper( thisBuffer->data[start] ) == toupper( *searchString ) )
{
return start;
}
} while ( start-- );
}
else if ( searchStringLength )
{
do
{
if ( _memicmp( &thisBuffer->data[start], searchString, searchStringLength ) == 0 )
{
return start;
}
} while ( start-- );
}
}
return npos;
}
size_type LastIndexOf( const AnsiString& searchString, size_type start = npos ) const
{
Buffer* searchStringBuffer = searchString.toBuffer( );
if ( searchStringBuffer )
{
return LastIndexOf( searchStringBuffer->data, searchStringBuffer->length, start );
}
return npos;
}
size_type ILastIndexOf( const AnsiString& searchString, size_type start = npos ) const
{
Buffer* searchStringBuffer = searchString.toBuffer( );
if ( searchStringBuffer )
{
return ILastIndexOf( searchStringBuffer->data, searchStringBuffer->length, start );
}
return npos;
}
size_type LastIndexOf( const char* searchString, size_type start = npos ) const
{
if ( searchString && searchString[0] )
{
size_type length = strlen( searchString );
return LastIndexOf( searchString, length, start );
}
return npos;
}
size_type ILastIndexOf( const char* searchString, size_type start = npos ) const
{
if ( searchString && searchString[0] )
{
size_type length = strlen( searchString );
return ILastIndexOf( searchString, length, start );
}
return npos;
}
size_type LastIndexOf( char c, size_type start = npos ) const
{
Buffer* thisBuffer = toBuffer( );
if ( thisBuffer )
{
if ( start >= thisBuffer->length )
{
start = thisBuffer->length - 1;
}
do
{
if ( thisBuffer->data[start] == c )
{
return start;
}
} while ( start-- );
}
return npos;
}
size_type ILastIndexOf( char c, size_type start = npos ) const
{
c = toupper( c );
Buffer* thisBuffer = toBuffer( );
if ( thisBuffer )
{
if ( start >= thisBuffer->length )
{
start = thisBuffer->length - 1;
}
do
{
if ( toupper( thisBuffer->data[start] ) == c )
{
return start;
}
} while ( start-- );
}
return npos;
}
size_type LastIndexOf( bool( *test )( char ), size_type start = npos ) const
{
Buffer* thisBuffer = toBuffer( );
if ( thisBuffer )
{
if ( start >= ( thisBuffer->length ) )
{
start = thisBuffer->length - 1;
}
do
{
char c = thisBuffer->data[start];
if ( test( c ) )
{
return start;
}
} while ( start-- );
}
return npos;
}
size_type LastIndexOf( bool( *test )( const char*, size_type length ), size_type start = npos ) const
{
Buffer* thisBuffer = toBuffer( );
if ( ( thisBuffer ) && ( start < thisBuffer->length ) )
{
if ( start >= ( thisBuffer->length ) )
{
start = thisBuffer->length - 1;
}
const char* pStart = &thisBuffer->data[start];
size_type remainingLength = thisBuffer->length - start;
do
{
if ( test( pStart, remainingLength ) )
{
return start;
}
remainingLength++;
} while ( data_ != pStart-- );
}
return npos;
}
size_type LastIndexOf( bool( *test )( const char*, const char* ), size_type start = npos ) const
{
Buffer* thisBuffer = toBuffer( );
if ( ( thisBuffer ) && ( start < thisBuffer->length ) )
{
if ( start >= ( thisBuffer->length ) )
{
start = thisBuffer->length - 1;
}
const char* pStart = &thisBuffer->data[start];
const char* pEnd = end( );
do
{
if ( test( pStart, pEnd ) )
{
return start;
}
} while ( data_ != pStart-- );
}
return npos;
}
bool IsControl( size_type position )
{
Buffer* thisBuffer = toBuffer( );
if ( ( thisBuffer ) && ( position < thisBuffer->length ) )
{
return iswcntrl( thisBuffer->data[position] ) != 0;
}
return false;
}
bool IsDigit( size_type position )
{
Buffer* thisBuffer = toBuffer( );
if ( ( thisBuffer ) && ( position < thisBuffer->length ) )
{
return iswdigit( thisBuffer->data[position] ) != 0;
}
return false;
}
bool IsLetter( size_type position )
{
Buffer* thisBuffer = toBuffer( );
if ( ( thisBuffer ) && ( position < thisBuffer->length ) )
{
return iswalpha( thisBuffer->data[position] ) != 0;
}
return false;
}
bool IsLetterOrDigit( size_type position )
{
Buffer* thisBuffer = toBuffer( );
if ( ( thisBuffer ) && ( position < thisBuffer->length ) )
{
return iswalnum( thisBuffer->data[position] ) != 0;
}
return false;
}
bool IsLower( size_type position )
{
Buffer* thisBuffer = toBuffer( );
if ( ( thisBuffer ) && ( position < thisBuffer->length ) )
{
return iswlower( thisBuffer->data[position] ) != 0;
}
return false;
}
bool IsUpper( size_type position )
{
Buffer* thisBuffer = toBuffer( );
if ( ( thisBuffer ) && ( position < thisBuffer->length ) )
{
return iswupper( thisBuffer->data[position] ) != 0;
}
return false;
}
bool IsPunctuation( size_type position )
{
Buffer* thisBuffer = toBuffer( );
if ( ( thisBuffer ) && ( position < thisBuffer->length ) )
{
return iswpunct( thisBuffer->data[position] ) != 0;
}
return false;
}
bool IsWhiteSpace( size_type position )
{
Buffer* thisBuffer = toBuffer( );
if ( ( thisBuffer ) && ( position < thisBuffer->length ) )
{
return iswspace( thisBuffer->data[position] ) != 0;
}
return false;
}
bool StartsWith( const char* str ) const
{
if ( data_ && str )
{
const char* p = data_;
while ( *p && *str )
{
if ( *p != *str )
{
break;
}
p++;
str++;
}
return *str == L'\x00';
}
return false;
}
bool StartsWith( const AnsiString& str ) const
{
return StartsWith( str.data_ );
}
bool IStartsWith( const char* str ) const
{
if ( data_ && str )
{
const char* p = data_;
while ( *p && *str )
{
if ( toupper( *p ) != toupper( *str ) )
{
break;
}
p++;
str++;
}
return *str == L'\x00';
}
return false;
}
bool IStartsWith( const AnsiString& str ) const
{
return IStartsWith( str.data_ );
}
HWIN_EXPORT const AnsiString& CopyTo( char* buffer, size_type bufferSize, size_type start = 0, char padCharacter = defaultPadCharacter ) const;
AnsiString SubString( size_type start, size_type length = npos ) const
{
Buffer* thisBuffer = toBuffer( );
if ( thisBuffer && ( start < thisBuffer->length ) )
{
if ( length >( thisBuffer->length - start ) )
{
length = thisBuffer->length - start;
}
if ( ( start == 0 ) && ( length == thisBuffer->length ) )
{
return AnsiString( *this );
}
else
{
return AnsiString( thisBuffer->data + start, length );
}
}
else
{
return AnsiString( );
}
}
AnsiString& UpperCase( )
{
Buffer* thisBuffer = EnsureUnique( );
if ( thisBuffer )
{
CharUpperBuffA( thisBuffer->data, DWORD( thisBuffer->length ) );
}
return *this;
}
AnsiString& LowerCase( )
{
Buffer* thisBuffer = EnsureUnique( );
if ( thisBuffer )
{
CharLowerBuffA( thisBuffer->data, DWORD( thisBuffer->length ) );
}
return *this;
}
AnsiString& erase( )
{
Release( );
return *this;
}
AnsiString& Clear( )
{
Release( );
return *this;
}
AnsiString& Remove( size_type start, size_type length = npos )
{
Buffer* thisBuffer = toBuffer( );
if ( thisBuffer )
{
if ( ( start == 0 ) && ( length >= thisBuffer->length ) )
{
Release( );
}
else if ( start < thisBuffer->length )
{
if ( length >= thisBuffer->length - start )
{
ReallocateUnique( start );
}
else
{
thisBuffer = EnsureUnique( );
memmove( &thisBuffer->data[start], &thisBuffer->data[start + length], ( thisBuffer->length - ( start + length ) )*sizeof( char ) );
ReallocateUnique( thisBuffer->length - length );
}
}
}
return *this;
}
AnsiString& RemoveRange( size_type start, size_type end )
{
if ( start < end )
{
Remove( start, end - start );
}
return *this;
}
AnsiString& Replace( value_type whatCharacter, value_type withCharacter )
{
auto indexOfWhatCharacter = IndexOf( whatCharacter );
if ( indexOfWhatCharacter != npos )
{
auto thisBuffer = EnsureUnique( );
std::replace( begin( ) + indexOfWhatCharacter, end( ), whatCharacter, withCharacter );
}
return *this;
}
AnsiString& Keep( size_type start, size_type length = npos )
{
Buffer* thisBuffer = toBuffer( );
if ( thisBuffer )
{
if ( ( start == 0 ) && ( length >= thisBuffer->length ) )
{
return *this;
}
if ( start >= thisBuffer->length )
{
Release( );
return *this;
}
if ( length > ( thisBuffer->length - start ) )
{
length = thisBuffer->length - start;
}
thisBuffer = EnsureUnique( );
memmove( thisBuffer->data, &thisBuffer->data[start], ( length*sizeof( char ) ) );
ReallocateUnique( length );
}
return *this;
}
AnsiString& KeepRange( size_type start, size_type end )
{
if ( start < end )
{
Keep( start, end - start );
}
else
{
Release( );
}
return *this;
}
AnsiString& Insert( const char* text, size_type textLength, size_type position )
{
if ( text && textLength )
{
Buffer* thisBuffer = toBuffer( );
if ( thisBuffer )
{
if ( position >= thisBuffer->length )
{
Append( text, textLength );
}
else
{
if ( ( text >= data_ ) && ( text < ( data_ + thisBuffer->length ) ) )
{
size_type offset = text - data_;
if ( textLength >( thisBuffer->length - offset ) )
{
textLength = thisBuffer->length - offset;
}
AnsiString s( text, textLength );
size_type oldLength = thisBuffer->length;
thisBuffer = ReallocateUnique( oldLength + textLength );
memmove( &thisBuffer->data[position + textLength], &thisBuffer->data[position], ( oldLength - position )* sizeof( char ) );
memmove( &thisBuffer->data[position], s.c_str( ), textLength* sizeof( char ) );
}
else
{
size_type oldLength = thisBuffer->length;
thisBuffer = ReallocateUnique( oldLength + textLength );
memmove( &thisBuffer->data[position + textLength], &thisBuffer->data[position], ( oldLength - position )* sizeof( char ) );
memcpy( &thisBuffer->data[position], text, textLength* sizeof( char ) );
}
}
}
else
{
thisBuffer = allocate( textLength );
memmove( thisBuffer->data, text, textLength * sizeof( char ) );
}
}
return *this;
}
AnsiString& Insert( const AnsiString& text, size_type position = 0 )
{
Buffer* textBuffer = text.toBuffer( );
if ( textBuffer )
{
Insert( textBuffer->data, textBuffer->length, position );
}
return *this;
}
AnsiString& Insert( const char* text, size_type position = 0 )
{
if ( text && text[0] )
{
size_type length = strlen( text );
Insert( text, length, position );
}
return *this;
}
AnsiString& TrimRight( const char* charactersToRemove, size_type numberOfCharactersToRemove )
{
Buffer* thisBuffer = toBuffer( );
if ( thisBuffer && charactersToRemove && numberOfCharactersToRemove )
{
auto last = thisBuffer->length - 1;
do
{
const value_type* p = ( const value_type* )memchr( charactersToRemove, thisBuffer->data[last], numberOfCharactersToRemove );
if ( !p )
{
last++;
if ( last == thisBuffer->length )
{
break;
}
thisBuffer = ReallocateUnique( last );
break;
}
} while ( last-- );
if ( last == size_type( -1 ) )
{
Release( );
}
}
return *this;
}
AnsiString& TrimRight( const AnsiString& charactersToRemove )
{
return TrimRight( charactersToRemove.c_str( ), charactersToRemove.length( ) );
}
AnsiString& TrimRight( )
{
Buffer* thisBuffer = toBuffer( );
if ( thisBuffer )
{
auto last = thisBuffer->length - 1;
do
{
auto res = iswspace( thisBuffer->data[last] );
if ( !res )
{
last++;
if ( last == thisBuffer->length )
{
break;
}
thisBuffer = ReallocateUnique( last );
break;
}
} while ( last-- );
if ( last == size_type( -1 ) )
{
Release( );
}
}
return *this;
}
AnsiString& TrimLeft( )
{
Buffer* thisBuffer = toBuffer( );
if ( thisBuffer )
{
for ( size_type i = 0; i < thisBuffer->length; i++ )
{
auto res = isspace( thisBuffer->data[i] );
if ( !res )
{
Keep( i );
return *this;
}
}
Release( );
}
return *this;
}
AnsiString& Trim( )
{
Buffer* thisBuffer = toBuffer( );
if ( thisBuffer )
{
for ( size_type i = 0; i < thisBuffer->length; i++ )
{
auto res = isspace( thisBuffer->data[i] );
if ( !res )
{
auto last = thisBuffer->length - 1;
do
{
auto res = isspace( thisBuffer->data[last] );
if ( !res )
{
last++;
KeepRange( i, last );
break;
}
} while ( last-- );
return *this;
}
}
Release( );
}
return *this;
}
AnsiString& Trim( value_type c )
{
Buffer* thisBuffer = toBuffer( );
if ( thisBuffer )
{
for ( size_type i = 0; i < thisBuffer->length; i++ )
{
if ( thisBuffer->data[i] != c )
{
auto last = thisBuffer->length - 1;
do
{
if ( thisBuffer->data[last] != c )
{
last++;
KeepRange( i, last );
break;
}
} while ( last-- );
return *this;
}
}
Release( );
}
return *this;
}
AnsiString Trimmed( ) const
{
auto tmp = *this;
tmp.Trim( );
return tmp;
}
AnsiString TrimmedLeft( ) const
{
auto tmp = *this;
tmp.TrimLeft( );
return tmp;
}
AnsiString TrimmedRight( ) const
{
auto tmp = *this;
tmp.TrimRight( );
return tmp;
}
void swap( AnsiString& s )
{
auto tmp = data_;
data_ = s.data_;
s.data_ = tmp;
}
static void swap( AnsiString& a, AnsiString& b )
{
a.swap( b );
}
static AnsiString Format( const char* fmt, ... )
{
va_list args;
va_start( args, fmt );
int length = _vscprintf( fmt, args );
if ( length < 0 )
{
throw ArgumentException( "fmt" );
}
AnsiString result( AnsiString::size_type( length ), '\x0' );
vsprintf_s( result.c_str( ), length + 1, fmt, args );
va_end( args );
return result;
}
static AnsiString FormatV( const char* fmt, va_list args )
{
int length = _vscprintf( fmt, args );
if ( length < 0 )
{
throw ArgumentException( "fmt" );
}
AnsiString result( AnsiString::size_type( length ), L'\x0' );
vsprintf_s( result.c_str( ), length + 1, fmt, args );
return result;
}
static AnsiString FormatV( const AnsiString& fmt, va_list args )
{
int length = _vscprintf( fmt.c_str( ), args );
if ( length < 0 )
{
throw ArgumentException( "fmt" );
}
AnsiString result( AnsiString::size_type( length ), L'\x0' );
vsprintf_s( result.c_str( ), length + 1, fmt.c_str( ), args );
return result;
}
std::vector<AnsiString> Split( value_type delimiter ) const
{
std::vector<AnsiString> result;
size_type theSize = size( );
if ( theSize )
{
const value_type* start = data_;
const value_type* end = start;
const value_type* thisEnd = start + theSize;
while ( end < thisEnd )
{
if ( *end == delimiter )
{
if ( start < end )
{
result.emplace_back( start, size_type( end - start ) );
}
start = end + 1;
}
end++;
}
if ( start < end )
{
result.emplace_back( start, size_type( end - start ) );
}
}
return std::move( result );
}
std::vector<AnsiString> Split( value_type* delimiters ) const
{
std::vector<AnsiString> result;
size_type theSize = size( );
if ( theSize )
{
const value_type* start = data_;
const value_type* end = start;
const value_type* thisEnd = start + theSize;
while ( end < thisEnd )
{
value_type* ptr = delimiters;
while ( *ptr )
{
if ( *end == *ptr )
{
if ( start < end )
{
result.emplace_back( start, size_type( end - start ) );
}
start = end + 1;
break;
}
ptr++;
}
end++;
}
if ( start < end )
{
result.emplace_back( start, size_type( end - start ) );
}
}
return std::move( result );
}
template<typename ForwardIterator>
std::vector<AnsiString> Split( ForwardIterator delimitersBegin, ForwardIterator delimitersEnd ) const
{
std::vector<AnsiString> result;
size_type theSize = size( );
if ( theSize )
{
const value_type* start = data_;
const value_type* end = start;
const value_type* thisEnd = start + theSize;
while ( end < thisEnd )
{
for ( ForwardIterator it = delimitersBegin; it != delimitersEnd; ++it )
{
value_type delimiter = *it;
if ( *end == delimiter )
{
if ( start < end )
{
result.emplace_back( start, size_type( end - start ) );
}
start = end + 1;
break;
}
}
end++;
}
if ( start < end )
{
result.emplace_back( start, size_type( end - start ) );
}
}
return std::move( result );
}
std::vector<AnsiString> Split( std::initializer_list<value_type> delimiters )
{
return std::move( Split( delimiters.begin( ), delimiters.end( ) ) );
}
std::vector<AnsiString> Split( const std::vector<value_type>& delimiters )
{
return std::move( Split( delimiters.begin( ), delimiters.end( ) ) );
}
std::vector<AnsiString> Split( value_type delimiter, size_t max ) const
{
if ( max > 1 )
{
std::vector<AnsiString> result;
size_type theSize = size( );
if ( theSize )
{
const value_type* start = data_;
const value_type* end = start;
const value_type* thisEnd = start + theSize;
while ( end < thisEnd )
{
if ( *end == delimiter )
{
if ( start < end )
{
result.emplace_back( start, size_type( end - start ) );
if ( result.size( ) == ( max - 1 ) )
{
start = end + 1;
result.emplace_back( start, size_type( thisEnd - start ) );
return std::move( result );
}
}
start = end + 1;
}
end++;
}
if ( start < end )
{
result.emplace_back( start, size_type( end - start ) );
}
}
return std::move( result );
}
else
{
std::vector<AnsiString> result( { *this } );
return std::move( result );
}
}
stdstring ToStdString( ) const
{
Buffer* thisBuffer = toBuffer( );
if ( thisBuffer )
{
stdstring result( thisBuffer->data, thisBuffer->length );
return std::move( result );
}
return stdstring( );
}
HWIN_EXPORT bool ToBoolean( ) const;
HWIN_EXPORT char ToSByte( int radix = 0 ) const;
HWIN_EXPORT unsigned char ToByte( int radix = 0 ) const;
HWIN_EXPORT short ToInt16( int radix = 0 ) const;
HWIN_EXPORT unsigned short ToUInt16( int radix = 0 ) const;
HWIN_EXPORT int ToInt32( int radix = 0 ) const;
HWIN_EXPORT unsigned int ToUInt32( int radix = 0 ) const;
HWIN_EXPORT long long ToInt64( int radix = 0 ) const;
HWIN_EXPORT unsigned long long ToUInt64( int radix = 0 ) const;
HWIN_EXPORT float ToSingle( ) const;
HWIN_EXPORT double ToDouble( ) const;
HWIN_EXPORT DateTime ToDateTime( ) const;
HWIN_EXPORT TimeSpan ToTimeSpan( ) const;
HWIN_EXPORT Guid ToGuid( ) const;
HWIN_EXPORT bool Match( const Regex& regex, std::regex_constants::match_flag_type flags = std::regex_constants::match_default ) const;
HWIN_EXPORT bool Match( MatchResults& results, const Regex& regex, std::regex_constants::match_flag_type flags = std::regex_constants::match_default ) const;
};
HWIN_EXPORT std::ostream& operator << ( std::ostream& s, const AnsiString& str );
HWIN_EXPORT std::wostream& operator << ( std::wostream& s, const AnsiString& str );
HWIN_EXPORT std::istream& operator >> ( std::istream& s, AnsiString& str );
// ----------------------------------------------------------------------
// WideString
//
// The binary representation if this class is a pointer to a zero
// terminated string or nullptr.
//
// No data is allocated for empty strings, causing c_str() to return
// nullptr
// ----------------------------------------------------------------------
class WideString
{
public:
typedef unsigned long long size_type;
typedef wchar_t value_type;
typedef std::wstring stdstring;
static const size_type npos = MAXDWORD64;
static const wchar_t defaultPadCharacter = L'\x20';
typedef value_type* iterator;
typedef const value_type* const_iterator;
typedef std::basic_regex<value_type> Regex;
typedef std::match_results<const_iterator> Match;
friend HWIN_EXPORT std::wostream& operator << ( std::wostream& os, const WideString& s );
private:
HWIN_EXPORT static wchar_t* empty;
struct Buffer
{
size_type referenceCount;
size_type length;
wchar_t data[128];
};
wchar_t* data_;
Buffer* toBuffer( ) const
{
if ( data_ )
{
return ( Buffer* )( ( ( char* )data_ ) - offsetof( Buffer, data ) );
}
return nullptr;
}
static Buffer* toBuffer( const wchar_t* data )
{
if ( data )
{
return ( Buffer* )( ( ( char* )data ) - offsetof( Buffer, data ) );
}
return nullptr;
}
static const size_type nonTextBufferByteCount = offsetof( Buffer, data ) + sizeof( wchar_t );
static const size_type minBufferByteCount = 64;
static const size_type minReservedCharacters = ( minBufferByteCount - nonTextBufferByteCount ) / sizeof( wchar_t );
static size_type allocationByteCount( size_type length )
{
if ( length )
{
if ( length < minReservedCharacters )
{
return minBufferByteCount;
}
size_type bytesRequired = nonTextBufferByteCount + length*sizeof( wchar_t );
size_type remainder = bytesRequired % minBufferByteCount;
if ( remainder != 0 )
{
bytesRequired += minBufferByteCount - remainder;
}
return bytesRequired;
}
return 0;
}
static Buffer* allocate( size_type length )
{
if ( length )
{
size_type byteCount = allocationByteCount( length );
Buffer* result = ( Buffer* )new char[byteCount];
result->referenceCount = 1;
result->length = length;
result->data[length] = 0;
return result;
}
return nullptr;
}
Buffer* EnsureUnique( )
{
Buffer* buffer = toBuffer( );
if ( buffer )
{
if ( buffer->referenceCount > 1 )
{
auto byteCount = allocationByteCount( buffer->length );
Buffer* newBuffer = ( Buffer* )new char[byteCount];
newBuffer->referenceCount = 1;
newBuffer->length = buffer->length;
memcpy( newBuffer->data, buffer->data, buffer->length*sizeof( wchar_t ) );
newBuffer->data[buffer->length] = 0;
Release( );
data_ = newBuffer->data;
return newBuffer;
}
}
return buffer;
}
Buffer* ReallocateUnique( size_type length )
{
Buffer* buffer = toBuffer( );
if ( buffer )
{
auto currentByteCount = allocationByteCount( buffer->length );
auto newByteCount = allocationByteCount( length );
if ( !newByteCount )
{
Release( );
return nullptr;
}
else
{
if ( ( buffer->referenceCount > 1 ) || ( currentByteCount != newByteCount ) )
{
Buffer* newBuffer = ( Buffer* )new char[newByteCount];
newBuffer->referenceCount = 1;
newBuffer->length = length;
size_type copyCount = std::min( buffer->length, length ) + 2;
memcpy( newBuffer->data, buffer->data, copyCount*sizeof( wchar_t ) );
newBuffer->data[length] = 0;
Release( );
data_ = newBuffer->data;
return newBuffer;
}
buffer->length = length;
buffer->data[length] = 0;
}
}
else
{
buffer = allocate( length );
data_ = buffer->data;
}
return buffer;
}
void Release( )
{
Buffer* buffer = toBuffer( );
if ( buffer )
{
LONG64 res = InterlockedDecrement64( ( LONG64* )&( buffer->referenceCount ) );
if ( res == 0 )
{
char* bytes = ( char* )buffer;
delete bytes;
}
data_ = nullptr;
}
}
void AddRef( const WideString& other )
{
if ( other.data_ != data_ )
{
Release( );
if ( other.data_ )
{
data_ = other.data_;
Buffer* buffer = toBuffer( );
InterlockedIncrement64( ( LONG64* )&( buffer->referenceCount ) );
}
}
}
static int Compare( Buffer* buffer1, Buffer* buffer2 )
{
if ( buffer1 == buffer2 )
{
return 0;
}
if ( buffer1 && buffer2 )
{
size_type compareLength = std::min( buffer1->length, buffer2->length );
for ( size_type i = 0; i < compareLength; i++ )
{
int res = int( buffer1->data[i] ) - int( buffer2->data[i] );
if ( res != 0 )
{
return res;
}
}
if ( buffer1->length > buffer2->length )
{
return 1;
}
if ( buffer1->length < buffer2->length )
{
return -1;
}
return 0;
}
else if ( buffer1 )
{
return 1;
}
else if ( buffer2 )
{
return -1;
}
return 0;
}
static int Compare( Buffer* buffer1, const wchar_t* str )
{
if ( buffer1 && str && str[0] != 0 )
{
size_type length = wcslen( str );
size_type compareLength = std::min( buffer1->length, length );
for ( size_type i = 0; i < compareLength; i++ )
{
int res = int( buffer1->data[i] ) - int( str[i] );
if ( res != 0 )
{
return res;
}
}
if ( buffer1->length > length )
{
return 1;
}
if ( buffer1->length < length )
{
return -1;
}
return 0;
}
else if ( buffer1 )
{
return 1;
}
else if ( str && str[0] != 0 )
{
return -1;
}
return 0;
}
static int ICompare( Buffer* buffer1, Buffer* buffer2 )
{
if ( buffer1 == buffer2 )
{
return 0;
}
if ( buffer1 && buffer2 )
{
auto result = CompareStringW( LOCALE_USER_DEFAULT, NORM_IGNORECASE, buffer1->data, static_cast<int>( buffer1->length ), buffer2->data, static_cast<int>( buffer2->length ) );
if ( !result )
{
ThrowLastOSError( );
}
return result - 2;
}
else if ( buffer1 )
{
return 1;
}
else if ( buffer2 )
{
return -1;
}
return 0;
}
static int ICompare( Buffer* buffer1, const wchar_t* buffer2 )
{
if ( buffer1 && buffer2 )
{
auto result = CompareStringW( LOCALE_USER_DEFAULT, NORM_IGNORECASE, buffer1->data, static_cast<int>( buffer1->length ), buffer2, -1 );
if ( !result )
{
ThrowLastOSError( );
}
return result - 2;
}
else if ( buffer1 )
{
return 1;
}
else if ( buffer2 )
{
return -1;
}
return 0;
}
static const wchar_t* wmemichr( const wchar_t* buf, int chr, size_t cnt )
{
chr = towupper( chr );
while ( cnt && ( towupper( *buf ) != chr ) )
{
buf++;
cnt--;
}
return cnt ? buf : nullptr;
}
static int _wmemicmp( const wchar_t* first, const wchar_t* second, size_t count )
{
while ( count )
{
int result = towupper( *first ) - towupper( *second );
if ( result )
{
return result;
}
first++;
second++;
count--;
}
return 0;
}
public:
HWIN_EXPORT static WideString From( const std::string& s );
HWIN_EXPORT static WideString From( const char* s );
HWIN_EXPORT static WideString From( const char* s, size_type theLength );
HWIN_EXPORT static WideString From( const AnsiString& s );
static WideString From( const WideString& s )
{
return s;
}
HWIN_EXPORT static WideString From( const std::wstring& s );
HWIN_EXPORT static WideString From( const wchar_t* s );
HWIN_EXPORT static WideString From( const wchar_t* s, size_type theLength );
HWIN_EXPORT static WideString From( char value, int radix = 10 );
HWIN_EXPORT static WideString From( unsigned char value, int radix = 10 );
HWIN_EXPORT static WideString From( short value, int radix = 10 );
HWIN_EXPORT static WideString From( unsigned short value, int radix = 10 );
HWIN_EXPORT static WideString From( int value, int radix = 10 );
HWIN_EXPORT static WideString From( unsigned int value, int radix = 10 );
HWIN_EXPORT static WideString From( long long value, int radix = 10 );
HWIN_EXPORT static WideString From( unsigned long long value, int radix = 10 );
HWIN_EXPORT static WideString From( float value, wchar_t* fmt = L"%g" );
HWIN_EXPORT static WideString From( double value, wchar_t* fmt = L"%g" );
HWIN_EXPORT static WideString From( DateTime value );
WideString( )
: data_( nullptr )
{
}
WideString( const WideString& other )
: data_( nullptr )
{
if ( other.data_ )
{
data_ = other.data_;
Buffer* buffer = toBuffer( );
InterlockedIncrement64( ( LONG64* )&( buffer->referenceCount ) );
}
}
WideString( size_type length, wchar_t c )
: data_( nullptr )
{
if ( length )
{
ReallocateUnique( length );
std::fill( data_, data_ + length, c );
}
}
WideString( const wchar_t* str, size_type length, wchar_t padCharacter = defaultPadCharacter )
: data_( nullptr )
{
if ( length )
{
ReallocateUnique( length );
if ( str )
{
wmemcpy( data_, str, length );
}
else
{
wmemset( data_, padCharacter, length );
}
}
}
WideString( const wchar_t* str1, size_type length1, const wchar_t* str2, size_type length2, wchar_t padCharacter = defaultPadCharacter )
: data_( nullptr )
{
size_type totalLength = length1 + length2;
if ( totalLength )
{
ReallocateUnique( totalLength );
if ( str1 )
{
wmemcpy( data_, str1, length1 );
}
else
{
wmemset( data_, padCharacter, length1 );
}
if ( str2 )
{
wmemcpy( &data_[length1], str2, length2 );
}
else
{
wmemset( data_ + length1, padCharacter, length2 );
}
}
}
WideString( const wchar_t* str1, size_type length1, const wchar_t* str2, size_type length2, const wchar_t* str3, size_type length3, wchar_t padCharacter = defaultPadCharacter )
: data_( nullptr )
{
size_type totalLength = length1 + length2 + length3;
if ( totalLength )
{
ReallocateUnique( totalLength );
if ( str1 )
{
wmemcpy_s( data_, length1, str1, length1 );
}
else
{
wmemset( data_, padCharacter, length1 );
}
if ( str2 )
{
wmemcpy_s( &data_[length1], length2, str2, length2 );
}
else
{
wmemset( data_ + length1, padCharacter, length2 );
}
if ( str3 )
{
wmemcpy_s( &data_[length2], length3, str3, length3 );
}
else
{
wmemset( data_ + length1 + length2, padCharacter, length3 );
}
}
}
WideString( const std::wstring& str )
: data_( nullptr )
{
if ( str.length( ) )
{
ReallocateUnique( str.length( ) );
wmemcpy( data_, str.c_str( ), str.length( ) );
}
}
WideString( const wchar_t* str )
: data_( nullptr )
{
if ( str )
{
size_type length = wcslen( str );
if ( length )
{
ReallocateUnique( length );
wmemcpy_s( data_, length, str, length );
}
}
}
WideString( WideString&& other )
: data_( nullptr )
{
data_ = other.data_;
other.data_ = nullptr;
}
~WideString( )
{
if ( data_ )
{
Release( );
}
}
WideString& operator = ( const WideString& other )
{
AddRef( other );
return *this;
}
WideString& operator = ( const wchar_t* str )
{
if ( !str || str[0] == 0 )
{
Release( );
}
else
{
if ( str != data_ )
{
Buffer* thisBuffer = toBuffer( );
if ( thisBuffer && str >= data_ && str < data_ + thisBuffer->length )
{
size_type offset = str - data_;
size_type length = thisBuffer->length - offset;
EnsureUnique( );
str = data_ + offset;
memmove( data_, str, length*sizeof( wchar_t ) );
ReallocateUnique( length );
}
else
{
size_type length = wcslen( str );
thisBuffer = ReallocateUnique( length );
wmemcpy( data_, str, length );
}
}
}
return *this;
}
WideString& operator = ( WideString&& other )
{
if ( this != &other )
{
data_ = other.data_;
other.data_ = nullptr;
}
return *this;
}
WideString& operator = ( const std::wstring& str )
{
if ( str.length( ) )
{
ReallocateUnique( str.length( ) );
wmemcpy( data_, str.c_str( ), str.length( ) );
}
return *this;
}
int CompareTo( const WideString& other ) const
{
return Compare( toBuffer( ), other.toBuffer( ) );
}
int CompareTo( const wchar_t* str ) const
{
return Compare( toBuffer( ), str );
}
int compare( const WideString& other ) const
{
return Compare( toBuffer( ), other.toBuffer( ) );
}
int compare( const wchar_t* str ) const
{
return Compare( toBuffer( ), str );
}
int ICompareTo( const WideString& other ) const
{
return ICompare( toBuffer( ), other.toBuffer( ) );
}
int ICompareTo( const wchar_t* str ) const
{
return ICompare( toBuffer( ), str );
}
int CompareTo( const WideString& other, bool ignoreCase ) const
{
if ( ignoreCase )
{
return ICompare( toBuffer( ), other.toBuffer( ) );
}
else
{
return Compare( toBuffer( ), other.toBuffer( ) );
}
}
int CompareTo( const wchar_t* str, bool ignoreCase ) const
{
if ( ignoreCase )
{
return ICompare( toBuffer( ), str );
}
else
{
return Compare( toBuffer( ), str );
}
}
int icompare( const WideString& other ) const
{
return ICompare( toBuffer( ), other.toBuffer( ) );
}
int icompare( const wchar_t* str ) const
{
return ICompare( toBuffer( ), str );
}
bool operator == ( const WideString& other ) const
{
return CompareTo( other ) == 0;
}
bool operator != ( const WideString& other ) const
{
return CompareTo( other ) != 0;
}
bool operator <= ( const WideString& other ) const
{
return CompareTo( other ) <= 0;
}
bool operator < ( const WideString& other ) const
{
return CompareTo( other ) < 0;
}
bool operator >= ( const WideString& other ) const
{
return CompareTo( other ) >= 0;
}
bool operator > ( const WideString& other ) const
{
return CompareTo( other ) > 0;
}
bool operator == ( const wchar_t* str ) const
{
return CompareTo( str ) == 0;
}
bool operator != ( const wchar_t* str ) const
{
return CompareTo( str ) != 0;
}
bool operator <= ( const wchar_t* str ) const
{
return CompareTo( str ) <= 0;
}
bool operator < ( const wchar_t* str ) const
{
return CompareTo( str ) < 0;
}
bool operator >= ( const wchar_t* str ) const
{
return CompareTo( str ) >= 0;
}
bool operator > ( const wchar_t* str ) const
{
return CompareTo( str ) > 0;
}
WideString& Append( const WideString& other )
{
Buffer* otherBuffer = other.toBuffer( );
if ( otherBuffer && otherBuffer->length )
{
Buffer* thisBuffer = toBuffer( );
if ( !thisBuffer )
{
data_ = otherBuffer->data;
InterlockedIncrement64( ( LONG64* )&( otherBuffer->referenceCount ) );
}
else
{
size_type oldLength = thisBuffer->length;
if ( thisBuffer == otherBuffer )
{
thisBuffer = ReallocateUnique( thisBuffer->length + thisBuffer->length );
wmemcpy( &thisBuffer->data[oldLength], thisBuffer->data, oldLength );
}
else
{
thisBuffer = ReallocateUnique( thisBuffer->length + otherBuffer->length );
wmemcpy( &thisBuffer->data[oldLength], otherBuffer->data, otherBuffer->length );
}
}
}
return *this;
}
WideString& Append( const wchar_t* str, size_type length )
{
if ( str )
{
Buffer* thisBuffer = toBuffer( );
if ( !thisBuffer )
{
if ( length )
{
ReallocateUnique( length );
wmemcpy_s( data_, length, str, length );
}
}
else if ( ( str == data_ ) && ( length >= thisBuffer->length ) )
{
size_type oldLength = thisBuffer->length;
thisBuffer = ReallocateUnique( thisBuffer->length + thisBuffer->length );
wmemmove_s( &thisBuffer->data[oldLength], oldLength, thisBuffer->data, oldLength );
}
else if ( str > data_ && str < ( data_ + thisBuffer->length ) )
{
size_type offset = str - data_;
if ( length >( thisBuffer->length - offset ) )
{
length = thisBuffer->length - offset;
}
size_type oldLength = thisBuffer->length;
thisBuffer = ReallocateUnique( oldLength + length );
str = data_ + offset;
wmemmove_s( &thisBuffer->data[oldLength], length, str, length );
}
else
{
Buffer* thisBuffer = toBuffer( );
size_type oldLength = thisBuffer->length;
thisBuffer = ReallocateUnique( oldLength + length );
wmemmove_s( &thisBuffer->data[oldLength], length, str, length );
}
}
return *this;
}
WideString& append( const wchar_t* str, size_type length )
{
Append( str, length );
return *this;
}
WideString& Append( const wchar_t* str )
{
if ( str && str[0] )
{
Buffer* thisBuffer = toBuffer( );
if ( !thisBuffer )
{
size_type length = wcslen( str );
if ( length )
{
ReallocateUnique( length );
wmemmove_s( data_, length, str, length );
}
}
else if ( str == data_ )
{
size_type oldLength = thisBuffer->length;
thisBuffer = ReallocateUnique( thisBuffer->length + thisBuffer->length );
wmemmove_s( &thisBuffer->data[oldLength], oldLength, thisBuffer->data, oldLength );
}
else if ( str > data_ && str < ( data_ + thisBuffer->length ) )
{
size_type offset = str - data_;
size_type length = thisBuffer->length - offset;
size_type oldLength = thisBuffer->length;
thisBuffer = ReallocateUnique( thisBuffer->length + length );
str = data_ + offset;
wmemmove_s( &thisBuffer->data[oldLength], length, str, length );
}
else
{
size_type length = wcslen( str );
Buffer* thisBuffer = toBuffer( );
size_type oldLength = thisBuffer->length;
thisBuffer = ReallocateUnique( thisBuffer->length + length );
wmemmove_s( &thisBuffer->data[oldLength], length, str, length );
}
}
return *this;
}
WideString& Append( wchar_t c, size_type numberOfTimes )
{
Buffer* thisBuffer = toBuffer( );
if ( !thisBuffer )
{
thisBuffer = ReallocateUnique( numberOfTimes );
wmemset( thisBuffer->data, c, numberOfTimes );
}
else
{
size_type oldLength = thisBuffer->length;
thisBuffer = ReallocateUnique( oldLength + numberOfTimes );
wmemset( &thisBuffer->data[oldLength], c, numberOfTimes );
}
return *this;
}
WideString& Append( wchar_t c )
{
Buffer* thisBuffer = toBuffer( );
if ( !thisBuffer )
{
thisBuffer = ReallocateUnique( 1 );
data_[0] = c;
}
else
{
size_type oldLength = thisBuffer->length;
thisBuffer = ReallocateUnique( oldLength + 1 );
data_[oldLength] = c;
}
return *this;
}
WideString Appended( const WideString& other ) const
{
Buffer* thisBuffer = toBuffer( );
Buffer* otherBuffer = other.toBuffer( );
if ( thisBuffer && otherBuffer )
{
WideString result( thisBuffer->data, thisBuffer->length, otherBuffer->data, otherBuffer->length );
return result;
}
else if ( thisBuffer )
{
WideString result( *this );
return result;
}
return other;
}
WideString Appended( const wchar_t* str ) const
{
Buffer* thisBuffer = toBuffer( );
if ( thisBuffer && str && str[0] )
{
size_type length = wcslen( str );
WideString result( thisBuffer->data, thisBuffer->length, str, length );
return result;
}
else if ( thisBuffer )
{
WideString result( *this );
return result;
}
else if ( str && str[0] )
{
return WideString( str );
}
return WideString( );
}
WideString Appended( wchar_t c, size_type numberOfTimes ) const
{
Buffer* thisBuffer = toBuffer( );
if ( thisBuffer )
{
WideString result( thisBuffer->data, thisBuffer->length, nullptr, numberOfTimes, c );
return result;
}
else
{
WideString result( nullptr, numberOfTimes, c );
return result;
}
}
WideString& assign( const wchar_t* s, size_t length )
{
if ( length == 0 )
{
this->Release( );
}
else
{
Buffer* thisBuffer = ReallocateUnique( length );
wmemcpy_s( thisBuffer->data, length + 1, s, length );
}
return *this;
}
WideString& operator += ( const WideString& other )
{
return Append( other );
}
WideString& operator += ( const wchar_t* str )
{
return Append( str );
}
WideString& operator += ( const wchar_t c )
{
return Append( c );
}
friend WideString operator + ( const WideString& str1, const WideString& str2 )
{
return str1.Appended( str2 );
}
friend WideString operator + ( const WideString& str1, const wchar_t* str2 )
{
return str1.Appended( str2 );
}
friend WideString operator + ( const WideString& str, const wchar_t c )
{
return str.Appended( c, 1 );
}
wchar_t& operator[]( size_type index )
{
#ifdef _DEBUG
Buffer* buffer = EnsureUnique( );
if ( !buffer || index >= buffer->length )
{
throw ArgumentOutOfRangeException( "index" );
}
return data_[index];
#else
return data_[index];
#endif
}
wchar_t operator[]( size_type index ) const
{
#ifdef _DEBUG
Buffer* buffer = toBuffer( );
if ( !buffer || index >= buffer->length )
{
throw ArgumentOutOfRangeException( "index" );
}
return data_[index];
#else
return data_[index];
#endif
}
WideString& SetLength( size_type newLength )
{
Buffer* buffer = toBuffer( );
if ( buffer && buffer->length != newLength )
{
ReallocateUnique( newLength );
}
else if ( newLength )
{
ReallocateUnique( newLength );
}
return *this;
}
WideString& SetString( const wchar_t* text, size_type textLength )
{
Buffer* buffer = ReallocateUnique( textLength );
if ( buffer )
{
wmemcpy( buffer->data, text, textLength );
}
return *this;
}
size_type size( ) const
{
Buffer* buffer = toBuffer( );
if ( buffer )
{
return buffer->length;
}
return 0;
}
size_type length( ) const
{
Buffer* buffer = toBuffer( );
if ( buffer )
{
return buffer->length;
}
return 0;
}
size_type Length( ) const
{
Buffer* buffer = toBuffer( );
if ( buffer )
{
return buffer->length;
}
return 0;
}
bool IsEmpty( ) const
{
return size( ) == 0;
}
explicit operator bool( ) const
{
return size( ) != 0;
}
const wchar_t* c_str( ) const
{
if ( !data_ )
{
return empty;
}
return data_;
}
wchar_t* c_str( )
{
EnsureUnique( );
if ( !data_ )
{
return empty;
}
return data_;
}
const wchar_t* data( ) const
{
return data_;
}
wchar_t* data( )
{
EnsureUnique( );
return data_;
}
const wchar_t* begin( ) const
{
return data_;
}
const wchar_t* end( ) const
{
if ( data_ )
{
Buffer* buffer = toBuffer( );
return data_ + buffer->length;
}
else
{
return data_;
}
}
const wchar_t* cbegin( ) const
{
return data_;
}
const wchar_t* cend( ) const
{
if ( data_ )
{
Buffer* buffer = toBuffer( );
return data_ + buffer->length;
}
else
{
return data_;
}
}
wchar_t* begin( )
{
EnsureUnique( ); return data_;
}
wchar_t* end( )
{
if ( data_ )
{
Buffer* buffer = EnsureUnique( );
return data_ + buffer->length;
}
else
{
return data_;
}
}
size_type IndexOfAnyOf( const wchar_t *searchChars, size_type numberOfSearchChars, size_type start ) const
{
Buffer* thisBuffer = toBuffer( );
if ( thisBuffer && searchChars && numberOfSearchChars )
{
while ( start < thisBuffer->length )
{
auto *p = wmemchr( searchChars, thisBuffer->data[start], numberOfSearchChars );
if ( p )
{
return start;
}
start++;
}
}
return npos;
}
size_type IIndexOfAnyOf( const wchar_t *searchChars, size_type numberOfSearchChars, size_type start ) const
{
Buffer* thisBuffer = toBuffer( );
if ( thisBuffer && searchChars && numberOfSearchChars )
{
while ( start < thisBuffer->length )
{
value_type c = towupper( thisBuffer->data[start] );
for ( size_t i = 0; i < numberOfSearchChars; i++ )
{
value_type sc = towupper( searchChars[i] );
if ( c == sc )
{
return start;
}
}
start++;
}
}
return npos;
}
size_type IndexOfAnyOf( const WideString& searchChars, size_type start = 0 ) const
{
Buffer* searchCharBuffer = searchChars.toBuffer( );
if ( searchCharBuffer )
{
return IndexOfAnyOf( searchCharBuffer->data, searchCharBuffer->length, start );
}
return npos;
}
size_type IIndexOfAnyOf( const WideString& searchChars, size_type start = 0 ) const
{
Buffer* searchCharBuffer = searchChars.toBuffer( );
if ( searchCharBuffer )
{
return IIndexOfAnyOf( searchCharBuffer->data, searchCharBuffer->length, start );
}
return npos;
}
size_type IndexOfAnyOf( const wchar_t* searchChars, size_type start = 0 ) const
{
if ( searchChars && searchChars[0] )
{
size_type length = wcslen( searchChars );
return IndexOfAnyOf( searchChars, length, start );
}
return npos;
}
size_type IIndexOfAnyOf( const wchar_t* searchChars, size_type start = 0 ) const
{
if ( searchChars && searchChars[0] )
{
size_type length = wcslen( searchChars );
return IIndexOfAnyOf( searchChars, length, start );
}
return npos;
}
size_type IndexOfAnyBut( const wchar_t *searchChars, size_type numberOfSearchChars, size_type start ) const
{
Buffer* thisBuffer = toBuffer( );
if ( thisBuffer && searchChars && numberOfSearchChars )
{
while ( start < thisBuffer->length )
{
auto *p = wmemchr( searchChars, thisBuffer->data[start], numberOfSearchChars );
if ( !p )
{
return start;
}
start++;
}
}
return npos;
}
size_type IIndexOfAnyBut( const wchar_t *searchChars, size_type numberOfSearchChars, size_type start ) const
{
Buffer* thisBuffer = toBuffer( );
if ( thisBuffer && searchChars && numberOfSearchChars )
{
while ( start < thisBuffer->length )
{
value_type c = towupper( thisBuffer->data[start] );
size_t i = 0;
for ( ; i < numberOfSearchChars; i++ )
{
value_type sc = towupper( searchChars[i] );
if ( c == sc )
{
break;
}
}
if ( i == numberOfSearchChars )
{
return start;
}
start++;
}
}
return npos;
}
size_type IndexOfAnyBut( const WideString& searchChars, size_type start = 0 ) const
{
Buffer* searchCharBuffer = searchChars.toBuffer( );
if ( searchCharBuffer )
{
return IndexOfAnyBut( searchCharBuffer->data, searchCharBuffer->length, start );
}
return npos;
}
size_type IIndexOfAnyBut( const WideString& searchChars, size_type start = 0 ) const
{
Buffer* searchCharBuffer = searchChars.toBuffer( );
if ( searchCharBuffer )
{
return IIndexOfAnyBut( searchCharBuffer->data, searchCharBuffer->length, start );
}
return npos;
}
size_type IndexOfAnyBut( const wchar_t* searchChars, size_type start = 0 ) const
{
if ( searchChars && searchChars[0] )
{
size_type length = wcslen( searchChars );
return IndexOfAnyBut( searchChars, length, start );
}
return npos;
}
size_type IIndexOfAnyBut( const wchar_t* searchChars, size_type start = 0 ) const
{
if ( searchChars && searchChars[0] )
{
size_type length = wcslen( searchChars );
return IIndexOfAnyBut( searchChars, length, start );
}
return npos;
}
size_type LastIndexOfAnyOf( const wchar_t *searchChars, size_type numberOfSearchChars, size_type start ) const
{
Buffer* thisBuffer = toBuffer( );
if ( thisBuffer && numberOfSearchChars )
{
if ( start >= thisBuffer->length )
{
start = thisBuffer->length - 1;
}
do
{
auto *p = wmemchr( searchChars, thisBuffer->data[start], numberOfSearchChars );
if ( p )
{
return start;
}
} while ( start-- );
}
return npos;
}
size_type ILastIndexOfAnyOf( const wchar_t *searchChars, size_type numberOfSearchChars, size_type start ) const
{
Buffer* thisBuffer = toBuffer( );
if ( thisBuffer && numberOfSearchChars )
{
if ( start >= thisBuffer->length )
{
start = thisBuffer->length - 1;
}
do
{
value_type c = towupper( thisBuffer->data[start] );
for ( size_t i = 0; i < numberOfSearchChars; i++ )
{
value_type sc = towupper( searchChars[i] );
if ( c == sc )
{
return start;
}
}
} while ( start-- );
}
return npos;
}
size_type LastIndexOfAnyOf( const WideString& searchChars, size_type start = npos ) const
{
Buffer* searchCharBuffer = searchChars.toBuffer( );
if ( searchCharBuffer )
{
return LastIndexOfAnyOf( searchCharBuffer->data, searchCharBuffer->length, start );
}
return npos;
}
size_type ILastIndexOfAnyOf( const WideString& searchChars, size_type start = npos ) const
{
Buffer* searchCharBuffer = searchChars.toBuffer( );
if ( searchCharBuffer )
{
return ILastIndexOfAnyOf( searchCharBuffer->data, searchCharBuffer->length, start );
}
return npos;
}
size_type LastIndexOfAnyOf( const wchar_t* searchChars, size_type start = npos ) const
{
if ( searchChars && searchChars[0] )
{
size_type length = wcslen( searchChars );
return LastIndexOfAnyOf( searchChars, length, start );
}
return npos;
}
size_type ILastIndexOfAnyOf( const wchar_t* searchChars, size_type start = npos ) const
{
if ( searchChars && searchChars[0] )
{
size_type length = wcslen( searchChars );
return ILastIndexOfAnyOf( searchChars, length, start );
}
return npos;
}
size_type LastIndexOfAnyBut( const wchar_t *searchChars, size_type numberOfSearchChars, size_type start ) const
{
Buffer* thisBuffer = toBuffer( );
if ( thisBuffer )
{
if ( start >= thisBuffer->length )
{
start = thisBuffer->length - 1;
}
do
{
auto *p = wmemchr( searchChars, thisBuffer->data[start], numberOfSearchChars );
if ( !p )
{
return start;
}
} while ( start-- );
}
return npos;
}
size_type ILastIndexOfAnyBut( const wchar_t *searchChars, size_type numberOfSearchChars, size_type start ) const
{
Buffer* thisBuffer = toBuffer( );
if ( thisBuffer )
{
if ( start >= thisBuffer->length )
{
start = thisBuffer->length - 1;
}
do
{
value_type c = toupper( thisBuffer->data[start] );
size_t i = 0;
for ( ; i < numberOfSearchChars; i++ )
{
value_type sc = toupper( searchChars[i] );
if ( c == sc )
{
break;
}
}
if ( i == numberOfSearchChars )
{
return start;
}
} while ( start-- );
}
return npos;
}
size_type LastIndexOfAnyBut( const WideString& searchChars, size_type start = npos ) const
{
Buffer* searchCharBuffer = searchChars.toBuffer( );
if ( searchCharBuffer )
{
return LastIndexOfAnyBut( searchCharBuffer->data, searchCharBuffer->length, start );
}
return npos;
}
size_type ILastIndexOfAnyBut( const WideString& searchChars, size_type start = npos ) const
{
Buffer* searchCharBuffer = searchChars.toBuffer( );
if ( searchCharBuffer )
{
return ILastIndexOfAnyBut( searchCharBuffer->data, searchCharBuffer->length, start );
}
return npos;
}
size_type LastIndexOfAnyBut( const wchar_t* searchChars, size_type start = npos ) const
{
if ( searchChars && searchChars[0] )
{
size_type length = wcslen( searchChars );
return LastIndexOfAnyBut( searchChars, length, start );
}
return npos;
}
size_type ILastIndexOfAnyBut( const wchar_t* searchChars, size_type start = npos ) const
{
if ( searchChars && searchChars[0] )
{
size_type length = wcslen( searchChars );
return ILastIndexOfAnyBut( searchChars, length, start );
}
return npos;
}
size_type IndexOf( const wchar_t *searchString, size_type searchStringLength, size_type start ) const
{
Buffer* thisBuffer = toBuffer( );
if ( thisBuffer && ( start < thisBuffer->length ) )
{
if ( searchStringLength == 1 )
{
auto *p = wmemchr( &thisBuffer->data[start], *searchString, thisBuffer->length - start );
if ( p )
{
return p - thisBuffer->data;
}
}
else if ( searchStringLength )
{
while ( ( start + searchStringLength ) <= thisBuffer->length )
{
if ( wmemcmp( &thisBuffer->data[start], searchString, searchStringLength ) == 0 )
{
return start;
}
start++;
}
}
}
return npos;
}
size_type IIndexOf( const wchar_t *searchString, size_type searchStringLength, size_type start ) const
{
Buffer* thisBuffer = toBuffer( );
if ( thisBuffer && ( start < thisBuffer->length ) )
{
if ( searchStringLength == 1 )
{
auto *p = ( value_type* )wmemichr( &thisBuffer->data[start], *searchString, thisBuffer->length - start );
if ( p )
{
return p - thisBuffer->data;
}
}
else if ( searchStringLength )
{
while ( ( start + searchStringLength ) <= thisBuffer->length )
{
if ( _wmemicmp( &thisBuffer->data[start], searchString, searchStringLength ) == 0 )
{
return start;
}
start++;
}
}
}
return npos;
}
size_type IndexOf( const WideString& searchString, size_type start = 0 ) const
{
Buffer* searchStringBuffer = searchString.toBuffer( );
if ( searchStringBuffer )
{
return IndexOf( searchStringBuffer->data, searchStringBuffer->length, start );
}
return npos;
}
size_type IIndexOf( const WideString& searchString, size_type start = 0 ) const
{
Buffer* searchStringBuffer = searchString.toBuffer( );
if ( searchStringBuffer )
{
return IIndexOf( searchStringBuffer->data, searchStringBuffer->length, start );
}
return npos;
}
size_type IndexOf( const wchar_t* searchString, size_type start = 0 ) const
{
Buffer* thisBuffer = toBuffer( );
if ( searchString && searchString[0] && thisBuffer && start < thisBuffer->length )
{
const wchar_t* pStart = &thisBuffer->data[start];
const wchar_t* pEnd = &thisBuffer->data[thisBuffer->length];
while ( pStart < pEnd )
{
auto p = wmemchr( pStart, *searchString, pEnd - pStart );
if ( p )
{
const wchar_t* pSearchChar = searchString + 1;
const wchar_t* pContent = p + 1;
while ( *pSearchChar )
{
if ( *pContent != *pSearchChar )
{
break;
}
pContent++;
pSearchChar++;
}
if ( !( *pSearchChar ) )
{
return p - thisBuffer->data;
}
pStart = p + 1;
}
else
{
return npos;
}
}
}
return npos;
}
size_type IIndexOf( const wchar_t* searchString, size_type start = 0 ) const
{
Buffer* thisBuffer = toBuffer( );
if ( searchString && searchString[0] && thisBuffer && start < thisBuffer->length )
{
const wchar_t* pStart = &thisBuffer->data[start];
const wchar_t* pEnd = &thisBuffer->data[thisBuffer->length];
while ( pStart < pEnd )
{
const value_type* p = ( value_type* )wmemichr( pStart, *searchString, pEnd - pStart );
if ( p )
{
const wchar_t* pSearchChar = searchString + 1;
const wchar_t* pContent = p + 1;
while ( *pSearchChar )
{
if ( towupper( *pContent ) != towupper( *pSearchChar ) )
{
break;
}
pContent++;
pSearchChar++;
}
if ( !( *pSearchChar ) )
{
return p - thisBuffer->data;
}
pStart = p + 1;
}
else
{
return npos;
}
}
}
return npos;
}
size_type IndexOf( const wchar_t c, size_type start = 0 ) const
{
Buffer* thisBuffer = toBuffer( );
if ( thisBuffer && start < thisBuffer->length )
{
auto p = wmemchr( &data_[start], c, thisBuffer->length - start );
if ( p )
{
return p - data_;
}
}
return npos;
}
size_type IndexOf( bool( *test )( wchar_t ), size_type start = 0 ) const
{
Buffer* thisBuffer = toBuffer( );
if ( thisBuffer )
{
while ( start < thisBuffer->length )
{
wchar_t c = thisBuffer->data[start];
if ( test( c ) )
{
return start;
}
start++;
}
}
return npos;
}
size_type IndexOf( bool( *test )( const wchar_t*, size_type length ), size_type start = 0 ) const
{
Buffer* thisBuffer = toBuffer( );
if ( ( thisBuffer ) && ( start < thisBuffer->length ) )
{
wchar_t* pStart = &thisBuffer->data[start];
size_type remainingLength = thisBuffer->length - start;
while ( remainingLength )
{
if ( test( pStart, remainingLength ) )
{
return start;
}
remainingLength--;
pStart++;
}
}
return npos;
}
size_type IndexOf( bool( *test )( const wchar_t*, const wchar_t* ), size_type start = 0 ) const
{
Buffer* thisBuffer = toBuffer( );
if ( ( thisBuffer ) && ( start < thisBuffer->length ) )
{
const wchar_t* pStart = &thisBuffer->data[start];
const wchar_t* pEnd = end( );
while ( pStart < pEnd )
{
if ( test( pStart, pEnd ) )
{
return start;
}
pStart++;
}
}
return npos;
}
size_type LastIndexOf( const wchar_t *searchString, size_type searchStringLength, size_type start ) const
{
Buffer* thisBuffer = toBuffer( );
if ( thisBuffer && ( searchStringLength <= thisBuffer->length ) )
{
if ( start > ( thisBuffer->length - searchStringLength ) )
{
start = thisBuffer->length - searchStringLength;
}
if ( searchStringLength == 1 )
{
do
{
if ( thisBuffer->data[start] == *searchString )
{
return start;
}
} while ( start-- );
}
else if ( searchStringLength )
{
do
{
if ( wmemcmp( &thisBuffer->data[start], searchString, searchStringLength ) == 0 )
{
return start;
}
} while ( start-- );
}
}
return npos;
}
size_type ILastIndexOf( const wchar_t *searchString, size_type searchStringLength, size_type start ) const
{
Buffer* thisBuffer = toBuffer( );
if ( thisBuffer && ( searchStringLength <= thisBuffer->length ) )
{
if ( start > ( thisBuffer->length - searchStringLength ) )
{
start = thisBuffer->length - searchStringLength;
}
if ( searchStringLength == 1 )
{
do
{
if ( towupper( thisBuffer->data[start] ) == towupper( *searchString ) )
{
return start;
}
} while ( start-- );
}
else if ( searchStringLength )
{
do
{
if ( _wmemicmp( &thisBuffer->data[start], searchString, searchStringLength ) == 0 )
{
return start;
}
} while ( start-- );
}
}
return npos;
}
size_type LastIndexOf( const WideString& searchString, size_type start = npos ) const
{
Buffer* searchStringBuffer = searchString.toBuffer( );
if ( searchStringBuffer )
{
return LastIndexOf( searchStringBuffer->data, searchStringBuffer->length, start );
}
return npos;
}
size_type ILastIndexOf( const WideString& searchString, size_type start = npos ) const
{
Buffer* searchStringBuffer = searchString.toBuffer( );
if ( searchStringBuffer )
{
return ILastIndexOf( searchStringBuffer->data, searchStringBuffer->length, start );
}
return npos;
}
size_type LastIndexOf( const wchar_t* searchString, size_type start = npos ) const
{
if ( searchString && searchString[0] )
{
size_type length = wcslen( searchString );
return LastIndexOf( searchString, length, start );
}
return npos;
}
size_type ILastIndexOf( const wchar_t* searchString, size_type start = npos ) const
{
if ( searchString && searchString[0] )
{
size_type length = wcslen( searchString );
return ILastIndexOf( searchString, length, start );
}
return npos;
}
size_type LastIndexOf( wchar_t c, size_type start = npos ) const
{
Buffer* thisBuffer = toBuffer( );
if ( thisBuffer )
{
if ( start >= thisBuffer->length )
{
start = thisBuffer->length - 1;
}
do
{
if ( thisBuffer->data[start] == c )
{
return start;
}
} while ( start-- );
}
return npos;
}
size_type ILastIndexOf( wchar_t c, size_type start = npos ) const
{
c = towupper( c );
Buffer* thisBuffer = toBuffer( );
if ( thisBuffer )
{
if ( start >= thisBuffer->length )
{
start = thisBuffer->length - 1;
}
do
{
if ( towupper( thisBuffer->data[start] ) == c )
{
return start;
}
} while ( start-- );
}
return npos;
}
size_type LastIndexOf( bool( *test )( wchar_t ), size_type start = npos ) const
{
Buffer* thisBuffer = toBuffer( );
if ( thisBuffer )
{
if ( start >= ( thisBuffer->length ) )
{
start = thisBuffer->length - 1;
}
do
{
wchar_t c = thisBuffer->data[start];
if ( test( c ) )
{
return start;
}
} while ( start-- );
}
return npos;
}
size_type LastIndexOf( bool( *test )( const wchar_t*, size_type length ), size_type start = npos ) const
{
Buffer* thisBuffer = toBuffer( );
if ( ( thisBuffer ) && ( start < thisBuffer->length ) )
{
if ( start >= ( thisBuffer->length ) )
{
start = thisBuffer->length - 1;
}
const wchar_t* pStart = &thisBuffer->data[start];
size_type remainingLength = thisBuffer->length - start;
do
{
if ( test( pStart, remainingLength ) )
{
return start;
}
remainingLength++;
} while ( data_ != pStart-- );
}
return npos;
}
size_type LastIndexOf( bool( *test )( const wchar_t*, const wchar_t* ), size_type start = npos ) const
{
Buffer* thisBuffer = toBuffer( );
if ( ( thisBuffer ) && ( start < thisBuffer->length ) )
{
if ( start >= ( thisBuffer->length ) )
{
start = thisBuffer->length - 1;
}
const wchar_t* pStart = &thisBuffer->data[start];
const wchar_t* pEnd = end( );
do
{
if ( test( pStart, pEnd ) )
{
return start;
}
} while ( data_ != pStart-- );
}
return npos;
}
bool IsControl( size_type position )
{
Buffer* thisBuffer = toBuffer( );
if ( ( thisBuffer ) && ( position < thisBuffer->length ) )
{
return iswcntrl( thisBuffer->data[position] ) != 0;
}
return false;
}
bool IsDigit( size_type position )
{
Buffer* thisBuffer = toBuffer( );
if ( ( thisBuffer ) && ( position < thisBuffer->length ) )
{
return iswdigit( thisBuffer->data[position] ) != 0;
}
return false;
}
bool IsLetter( size_type position )
{
Buffer* thisBuffer = toBuffer( );
if ( ( thisBuffer ) && ( position < thisBuffer->length ) )
{
return iswalpha( thisBuffer->data[position] ) != 0;
}
return false;
}
bool IsLetterOrDigit( size_type position )
{
Buffer* thisBuffer = toBuffer( );
if ( ( thisBuffer ) && ( position < thisBuffer->length ) )
{
return iswalnum( thisBuffer->data[position] ) != 0;
}
return false;
}
bool IsLower( size_type position )
{
Buffer* thisBuffer = toBuffer( );
if ( ( thisBuffer ) && ( position < thisBuffer->length ) )
{
return iswlower( thisBuffer->data[position] ) != 0;
}
return false;
}
bool IsUpper( size_type position )
{
Buffer* thisBuffer = toBuffer( );
if ( ( thisBuffer ) && ( position < thisBuffer->length ) )
{
return iswupper( thisBuffer->data[position] ) != 0;
}
return false;
}
bool IsPunctuation( size_type position )
{
Buffer* thisBuffer = toBuffer( );
if ( ( thisBuffer ) && ( position < thisBuffer->length ) )
{
return iswpunct( thisBuffer->data[position] ) != 0;
}
return false;
}
bool IsWhiteSpace( size_type position )
{
Buffer* thisBuffer = toBuffer( );
if ( ( thisBuffer ) && ( position < thisBuffer->length ) )
{
return iswspace( thisBuffer->data[position] ) != 0;
}
return false;
}
bool StartsWith( const wchar_t* str ) const
{
if ( data_ && str )
{
const wchar_t* p = data_;
while ( *p && *str )
{
if ( *p != *str )
{
break;
}
p++;
str++;
}
return *str == L'\x00';
}
return false;
}
bool StartsWith( const WideString& str ) const
{
return StartsWith( str.data_ );
}
bool IStartsWith( const wchar_t* str ) const
{
if ( data_ && str )
{
const wchar_t* p = data_;
while ( *p && *str )
{
if ( towupper( *p ) != towupper( *str ) )
{
break;
}
p++;
str++;
}
return *str == L'\x00';
}
return false;
}
bool IStartsWith( const WideString& str ) const
{
return IStartsWith( str.data_ );
}
HWIN_EXPORT const WideString& CopyTo( wchar_t* buffer, size_type bufferSize, size_type start = 0, wchar_t padCharacter = defaultPadCharacter ) const;
WideString SubString( size_type start, size_type length = npos ) const
{
Buffer* thisBuffer = toBuffer( );
if ( thisBuffer && ( start < thisBuffer->length ) )
{
if ( length >( thisBuffer->length - start ) )
{
length = thisBuffer->length - start;
}
if ( ( start == 0 ) && ( length == thisBuffer->length ) )
{
return WideString( *this );
}
else
{
return WideString( thisBuffer->data + start, length );
}
}
else
{
return WideString( );
}
}
WideString& UpperCase( )
{
Buffer* thisBuffer = EnsureUnique( );
if ( thisBuffer )
{
CharUpperBuffW( thisBuffer->data, DWORD( thisBuffer->length ) );
}
return *this;
}
WideString& LowerCase( )
{
Buffer* thisBuffer = EnsureUnique( );
if ( thisBuffer )
{
CharLowerBuffW( thisBuffer->data, DWORD( thisBuffer->length ) );
}
return *this;
}
WideString& erase( )
{
Release( );
return *this;
}
WideString& Clear( )
{
Release( );
return *this;
}
WideString& Remove( size_type start, size_type length = npos )
{
Buffer* thisBuffer = toBuffer( );
if ( thisBuffer )
{
if ( ( start == 0 ) && ( length >= thisBuffer->length ) )
{
Release( );
}
else if ( start < thisBuffer->length )
{
if ( length >= thisBuffer->length - start )
{
ReallocateUnique( start );
}
else
{
thisBuffer = EnsureUnique( );
memmove( &thisBuffer->data[start], &thisBuffer->data[start + length], ( thisBuffer->length - ( start + length ) )*sizeof( wchar_t ) );
ReallocateUnique( thisBuffer->length - length );
}
}
}
return *this;
}
WideString& RemoveRange( size_type start, size_type end )
{
if ( start < end )
{
Remove( start, end - start );
}
return *this;
}
WideString& Replace( value_type whatCharacter, value_type withCharacter )
{
auto indexOfWhatCharacter = IndexOf( whatCharacter );
if ( indexOfWhatCharacter != npos )
{
auto thisBuffer = EnsureUnique( );
std::replace( begin( ) + indexOfWhatCharacter, end( ), whatCharacter, withCharacter );
}
return *this;
}
WideString& Keep( size_type start, size_type length = npos )
{
Buffer* thisBuffer = toBuffer( );
if ( thisBuffer )
{
if ( ( start == 0 ) && ( length >= thisBuffer->length ) )
{
return *this;
}
if ( start >= thisBuffer->length )
{
Release( );
return *this;
}
if ( length > ( thisBuffer->length - start ) )
{
length = thisBuffer->length - start;
}
thisBuffer = EnsureUnique( );
memmove( thisBuffer->data, &thisBuffer->data[start], ( length*sizeof( wchar_t ) ) );
ReallocateUnique( length );
}
return *this;
}
WideString& KeepRange( size_type start, size_type end )
{
if ( start < end )
{
Keep( start, end - start );
}
else
{
Release( );
}
return *this;
}
WideString& Insert( const wchar_t* text, size_type textLength, size_type position )
{
if ( text && textLength )
{
Buffer* thisBuffer = toBuffer( );
if ( thisBuffer )
{
if ( position >= thisBuffer->length )
{
Append( text, textLength );
}
else
{
if ( ( text >= data_ ) && ( text < ( data_ + thisBuffer->length ) ) )
{
size_type offset = text - data_;
if ( textLength >( thisBuffer->length - offset ) )
{
textLength = thisBuffer->length - offset;
}
WideString s( text, textLength );
size_type oldLength = thisBuffer->length;
thisBuffer = ReallocateUnique( oldLength + textLength );
memmove( &thisBuffer->data[position + textLength], &thisBuffer->data[position], ( oldLength - position )* sizeof( wchar_t ) );
memmove( &thisBuffer->data[position], s.c_str( ), textLength* sizeof( wchar_t ) );
}
else
{
size_type oldLength = thisBuffer->length;
thisBuffer = ReallocateUnique( oldLength + textLength );
memmove( &thisBuffer->data[position + textLength], &thisBuffer->data[position], ( oldLength - position )* sizeof( wchar_t ) );
memcpy( &thisBuffer->data[position], text, textLength* sizeof( wchar_t ) );
}
}
}
else
{
thisBuffer = allocate( textLength );
memmove( thisBuffer->data, text, textLength * sizeof( wchar_t ) );
}
}
return *this;
}
WideString& Insert( const WideString& text, size_type position = 0 )
{
Buffer* textBuffer = text.toBuffer( );
if ( textBuffer )
{
Insert( textBuffer->data, textBuffer->length, position );
}
return *this;
}
WideString& Insert( const wchar_t* text, size_type position = 0 )
{
if ( text && text[0] )
{
size_type length = wcslen( text );
Insert( text, length, position );
}
return *this;
}
WideString& TrimRight( const wchar_t* charactersToRemove, size_type numberOfCharactersToRemove )
{
Buffer* thisBuffer = toBuffer( );
if ( thisBuffer && charactersToRemove && numberOfCharactersToRemove )
{
auto last = thisBuffer->length - 1;
do
{
auto *p = wmemchr( charactersToRemove, thisBuffer->data[last], numberOfCharactersToRemove );
if ( !p )
{
last++;
if ( last == thisBuffer->length )
{
break;
}
thisBuffer = ReallocateUnique( last );
break;
}
} while ( last-- );
if ( last == size_type( -1 ) )
{
Release( );
}
}
return *this;
}
WideString& TrimRight( const WideString& charactersToRemove )
{
return TrimRight( charactersToRemove.c_str( ), charactersToRemove.length( ) );
}
WideString& TrimRight( )
{
Buffer* thisBuffer = toBuffer( );
if ( thisBuffer )
{
auto last = thisBuffer->length - 1;
do
{
auto res = iswspace( thisBuffer->data[last] );
if ( !res )
{
last++;
if ( last == thisBuffer->length )
{
break;
}
thisBuffer = ReallocateUnique( last );
break;
}
} while ( last-- );
if ( last == size_type( -1 ) )
{
Release( );
}
}
return *this;
}
WideString& TrimLeft( )
{
Buffer* thisBuffer = toBuffer( );
if ( thisBuffer )
{
for ( size_type i = 0; i < thisBuffer->length; i++ )
{
auto res = iswspace( thisBuffer->data[i] );
if ( !res )
{
Keep( i );
return *this;
}
}
Release( );
}
return *this;
}
WideString& Trim( )
{
Buffer* thisBuffer = toBuffer( );
if ( thisBuffer )
{
for ( size_type i = 0; i < thisBuffer->length; i++ )
{
auto res = iswspace( thisBuffer->data[i] );
if ( !res )
{
auto last = thisBuffer->length - 1;
do
{
auto res = iswspace( thisBuffer->data[last] );
if ( !res )
{
last++;
KeepRange( i, last );
break;
}
} while ( last-- );
return *this;
}
}
Release( );
}
return *this;
}
WideString& Trim( value_type c )
{
Buffer* thisBuffer = toBuffer( );
if ( thisBuffer )
{
for ( size_type i = 0; i < thisBuffer->length; i++ )
{
if ( thisBuffer->data[i] != c )
{
auto last = thisBuffer->length - 1;
do
{
if ( thisBuffer->data[last] != c )
{
last++;
KeepRange( i, last );
break;
}
} while ( last-- );
return *this;
}
}
Release( );
}
return *this;
}
void swap( WideString& s )
{
auto tmp = data_;
data_ = s.data_;
s.data_ = tmp;
}
static void swap( WideString& a, WideString& b )
{
a.swap( b );
}
static WideString Format( const wchar_t* fmt, ... )
{
va_list args;
va_start( args, fmt );
int length = _vscwprintf( fmt, args );
if ( length < 0 )
{
throw ArgumentException( "fmt" );
}
WideString result( WideString::size_type( length ), L'\x0' );
vswprintf_s( result.c_str( ), length + 1, fmt, args );
va_end( args );
return result;
}
static WideString FormatV( const wchar_t* fmt, va_list args )
{
int length = _vscwprintf( fmt, args );
if ( length < 0 )
{
throw ArgumentException( "fmt" );
}
WideString result( WideString::size_type( length ), L'\x0' );
vswprintf_s( result.c_str( ), length + 1, fmt, args );
return result;
}
static WideString FormatV( const WideString& fmt, va_list args )
{
int length = _vscwprintf( fmt.c_str( ), args );
if ( length < 0 )
{
throw ArgumentException( "fmt" );
}
WideString result( WideString::size_type( length ), L'\x0' );
vswprintf_s( result.c_str( ), length + 1, fmt.c_str( ), args );
return result;
}
std::vector<WideString> Split( value_type delimiter ) const
{
std::vector<WideString> result;
size_type theSize = size( );
if ( theSize )
{
const value_type* start = data_;
const value_type* end = start;
const value_type* thisEnd = start + theSize;
while ( end < thisEnd )
{
if ( *end == delimiter )
{
if ( start < end )
{
result.emplace_back( start, size_type( end - start ) );
}
start = end + 1;
}
end++;
}
if ( start < end )
{
result.emplace_back( start, size_type( end - start ) );
}
}
return std::move( result );
}
std::vector<WideString> Split( value_type* delimiters ) const
{
std::vector<WideString> result;
size_type theSize = size( );
if ( theSize )
{
const value_type* start = data_;
const value_type* end = start;
const value_type* thisEnd = start + theSize;
while ( end < thisEnd )
{
value_type* ptr = delimiters;
while ( *ptr )
{
if ( *end == *ptr )
{
if ( start < end )
{
result.emplace_back( start, size_type( end - start ) );
}
start = end + 1;
break;
}
ptr++;
}
end++;
}
if ( start < end )
{
result.emplace_back( start, size_type( end - start ) );
}
}
return std::move( result );
}
template<typename ForwardIterator>
std::vector<WideString> Split( ForwardIterator delimitersBegin, ForwardIterator delimitersEnd ) const
{
std::vector<WideString> result;
size_type theSize = size( );
if ( theSize )
{
const value_type* start = data_;
const value_type* end = start;
const value_type* thisEnd = start + theSize;
while ( end < thisEnd )
{
for ( ForwardIterator it = delimitersBegin; it != delimitersEnd; ++it )
{
value_type delimiter = *it;
if ( *end == delimiter )
{
if ( start < end )
{
result.emplace_back( start, size_type( end - start ) );
}
start = end + 1;
break;
}
}
end++;
}
if ( start < end )
{
result.emplace_back( start, size_type( end - start ) );
}
}
return std::move( result );
}
std::vector<WideString> Split( std::initializer_list<value_type> delimiters )
{
return std::move( Split( delimiters.begin( ), delimiters.end( ) ) );
}
std::vector<WideString> Split( const std::vector<value_type>& delimiters )
{
return std::move( Split( delimiters.begin( ), delimiters.end( ) ) );
}
std::vector<WideString> Split( value_type delimiter, size_t max ) const
{
if ( max > 1 )
{
std::vector<WideString> result;
size_type theSize = size( );
if ( theSize )
{
const value_type* start = data_;
const value_type* end = start;
const value_type* thisEnd = start + theSize;
while ( end < thisEnd )
{
if ( *end == delimiter )
{
if ( start < end )
{
result.emplace_back( start, size_type( end - start ) );
if ( result.size( ) == ( max - 1 ) )
{
start = end + 1;
result.emplace_back( start, size_type( thisEnd - start ) );
return std::move( result );
}
}
start = end + 1;
}
end++;
}
if ( start < end )
{
result.emplace_back( start, size_type( end - start ) );
}
}
return std::move( result );
}
else
{
std::vector<WideString> result( { *this } );
return std::move( result );
}
}
stdstring ToStdString( ) const
{
Buffer* thisBuffer = toBuffer( );
if ( thisBuffer )
{
stdstring result( thisBuffer->data, thisBuffer->length );
std::move( result );
}
return std::move( stdstring( ) );
}
HWIN_EXPORT bool ToBoolean( ) const;
HWIN_EXPORT char ToSByte( int radix = 0 ) const;
HWIN_EXPORT unsigned char ToByte( int radix = 0 ) const;
HWIN_EXPORT short ToInt16( int radix = 0 ) const;
HWIN_EXPORT unsigned short ToUInt16( int radix = 0 ) const;
HWIN_EXPORT int ToInt32( int radix = 0 ) const;
HWIN_EXPORT unsigned int ToUInt32( int radix = 0 ) const;
HWIN_EXPORT long long ToInt64( int radix = 0 ) const;
HWIN_EXPORT unsigned long long ToUInt64( int radix = 0 ) const;
HWIN_EXPORT float ToSingle( ) const;
HWIN_EXPORT double ToDouble( ) const;
HWIN_EXPORT DateTime ToDateTime( ) const;
HWIN_EXPORT TimeSpan ToTimeSpan( ) const;
HWIN_EXPORT Guid ToGuid( ) const;
};
HWIN_EXPORT std::ostream& operator << ( std::ostream& s, const WideString& str );
HWIN_EXPORT std::wostream& operator << ( std::wostream& s, const WideString& str );
HWIN_EXPORT WideString to_string( const char* str );
HWIN_EXPORT WideString to_string( const wchar_t* str );
template<class ElementType, class TraitsType, class StringType>
inline std::basic_istream<ElementType, TraitsType>& ReadFrom( std::basic_istream<ElementType, TraitsType>& theInputStream, const ElementType theDelimiter, StringType& theString )
{
typedef std::basic_istream<ElementType, TraitsType> InputStreamType;
std::ios_base::iostate ioState = std::ios_base::goodbit;
bool changed = false;
const typename InputStreamType::sentry isOk( theInputStream, true );
if ( isOk )
{
try
{
theString.erase( );
const typename TraitsType::int_type delimiter = TraitsType::to_int_type( theDelimiter );
typename TraitsType::int_type inputCharacter = theInputStream.rdbuf( )->sgetc( );
for ( ;; inputCharacter = theInputStream.rdbuf( )->snextc( ) )
{
if ( TraitsType::eq_int_type( TraitsType::eof( ), inputCharacter ) )
{
// We've reached the en d of the file
ioState |= std::ios_base::eofbit;
break;
}
else if ( TraitsType::eq_int_type( inputCharacter, delimiter ) )
{
// We've got a delimiter
changed = true;
theInputStream.rdbuf( )->sbumpc( );
break;
}
else
{
// We've got a character, append it to string
theString += static_cast< StringType::value_type >( inputCharacter );
changed = true;
}
}
}
catch ( ... )
{
theInputStream.setstate( std::ios_base::badbit, true );
}
}
if ( !changed )
{
ioState |= std::ios_base::failbit;
}
theInputStream.setstate( ioState );
return theInputStream;
}
HWIN_EXPORT std::wistream& operator >> ( std::wistream& s, WideString& str );
}
}
namespace std
{
template<>
struct hash<harlinn::windows::AnsiString> : public std::unary_function<harlinn::windows::AnsiString, size_t>
{
inline size_t operator()( const harlinn::windows::AnsiString& theString ) const
{
auto result = _Hash_seq( ( const unsigned char* )theString.c_str( ), theString.Length( ) );
return result;
}
};
template<>
struct hash<harlinn::windows::WideString> : public std::unary_function<harlinn::windows::WideString, size_t>
{
inline size_t operator()( const harlinn::windows::WideString& theString ) const
{
auto result = _Hash_seq( ( const unsigned char* )theString.c_str( ), theString.Length( ) * 2 );
return result;
}
};
}
#pragma pack(pop)
#ifdef _MANAGED
#pragma managed(pop)
#endif
#endif // __HWINSTRING_H__