Click here to Skip to main content
15,897,187 members
Articles / Desktop Programming / Win32

Stopwatch

Rate me:
Please Sign up or sign in to vote.
4.97/5 (29 votes)
3 Jan 2015CPOL6 min read 66.4K   1.5K   43  
Benchmark C++ std::vector vs raw arrays, move assignable/constructable & copy assignable/constructable
#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__

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Architect Sea Surveillance AS
Norway Norway
Chief Architect - Sea Surveillance AS.

Specializing in integrated operations and high performance computing solutions.

I’ve been fooling around with computers since the early eighties, I’ve even done work on CP/M and MP/M.

Wrote my first “real” program on a BBC micro model B based on a series in a magazine at that time. It was fun and I got hooked on this thing called programming ...

A few Highlights:

  • High performance application server development
  • Model Driven Architecture and Code generators
  • Real-Time Distributed Solutions
  • C, C++, C#, Java, TSQL, PL/SQL, Delphi, ActionScript, Perl, Rexx
  • Microsoft SQL Server, Oracle RDBMS, IBM DB2, PostGreSQL
  • AMQP, Apache qpid, RabbitMQ, Microsoft Message Queuing, IBM WebSphereMQ, Oracle TuxidoMQ
  • Oracle WebLogic, IBM WebSphere
  • Corba, COM, DCE, WCF
  • AspenTech InfoPlus.21(IP21), OsiSoft PI


More information about what I do for a living can be found at: harlinn.com or LinkedIn

You can contact me at espen@harlinn.no

Comments and Discussions