//+---------------------------------------------------------------------------
//
//  Microsoft Windows
//  Copyright (C) Microsoft Corporation, 1997.
//
//  File:       N C S T L S T R . H
//
//  Contents:   STL string class renamed so as to remove our dependance
//              from msvcp50.dll.
//
//  Notes:
//
//  Author:     shaunco   12 Apr 1998
//
//----------------------------------------------------------------------------

#pragma once
#ifndef _NCSTLSTR_H_
#define _NCSTLSTR_H_

#include <stliter.h>
#include <stlxutil.h>
#include <limits.h>
#include <wchar.h>
#include "ncdebug.h"
using namespace std;


//template<class _E,
//class _Tr = char_traits<_E>,
//class _A  = allocator<_E> >

struct wchar_traits
{
    typedef wchar_t     _E;
    typedef _E          char_type;   // for overloads
    typedef wint_t      int_type;
    typedef mbstate_t   state_type;

    static void __cdecl assign(_E& _X, const _E& _Y)
    {
        _X = _Y;
    }
    static bool __cdecl eq(const _E& _X, const _E& _Y)
    {
        return (_X == _Y);
    }
    static bool __cdecl lt(const _E& _X, const _E& _Y)
    {
        return (_X < _Y);
    }
    static int __cdecl compare(const _E *_U, const _E *_V, size_t _N)
    {
        return (wmemcmp(_U, _V, _N));
    }
    static size_t __cdecl length(const _E *_U)
    {
        return (wcslen(_U));
    }
    static _E *__cdecl copy(_E *_U, const _E *_V, size_t _N)
    {
        return (wmemcpy(_U, _V, _N));
    }
    static const _E * __cdecl find(const _E *_U, size_t _N,
                                   const _E& _C)
    {
        return ((const _E *)wmemchr(_U, _C, _N));
    }
    static _E * __cdecl move(_E *_U, const _E *_V, size_t _N)
    {
        return (wmemmove(_U, _V, _N));
    }
    static _E * __cdecl assign(_E *_U, size_t _N, const _E& _C)
    {
        return (wmemset(_U, _C, _N));
    }
    static _E __cdecl to_char_type(const int_type& _C)
    {
        return (_C);
    }
    static int_type __cdecl to_int_type(const _E& _C)
    {
        return (_C);
    }
    static bool __cdecl eq_int_type(const int_type& _X,
                                    const int_type& _Y)
    {
        return (_X == _Y);
    }
    static int_type __cdecl eof()
    {
        return (WEOF);
    }
    static int_type __cdecl not_eof(const int_type& _C)
    {
        return (_C != eof() ? _C : !eof());
    }
};


class CWideString
{
public:
    typedef CWideString     _Myt;
    typedef wchar_traits    _Tr;
    typedef _Tr::_E         _E;
    typedef size_t          size_type;
    typedef ptrdiff_t       difference_type;
    typedef _E*             pointer;
    typedef const _E*       const_pointer;
    typedef _E&             reference;
    typedef const _E&       const_reference;
    typedef _E              value_type;
    typedef pointer         iterator;
    typedef const_pointer   const_iterator;

    typedef reverse_iterator<const_iterator, value_type, const_reference,
                                const_pointer, difference_type>
                const_reverse_iterator;

    typedef reverse_iterator<iterator, value_type, reference, pointer,
                                difference_type>
                reverse_iterator;

    typedef const_iterator _It;

    explicit CWideString()
    {
        _Tidy();
    }
    CWideString(const _Myt& _X)
    {
        _Tidy(), assign(_X, 0, npos);
    }
    CWideString(const _Myt& _X, size_type _P, size_type _M)
    {
        _Tidy(), assign(_X, _P, _M);
    }
    CWideString(const _E *_S, size_type _N)
    {
        _Tidy(), assign(_S, _N);
    }
    CWideString(const _E *_S)
    {
        _Tidy(), assign(_S);
    }
    CWideString(size_type _N, _E _C)
    {
        _Tidy(), assign(_N, _C);
    }
    CWideString(_It _F, _It _L)
    {
        _Tidy(); assign(_F, _L);
    }
    ~CWideString()
    {
        _Tidy(true);
    }
    enum _Mref
    {
        _FROZEN = USHRT_MAX
    };
    enum _Npos
    {
        // -1 is not arbitrary.  It is chosen because it works in math
        // operations.  npos is treated as size_type and is inolved in
        // arithmetic.
        //
        npos = -1
    };
    _Myt& operator=(const _Myt& _X)
    {
        return (assign(_X));
    }
    _Myt& operator=(const _E *_S)
    {
        return (assign(_S));
    }
    _Myt& operator=(_E _C)
    {
        return (assign(1, _C));
    }
    _Myt& operator+=(const _Myt& _X)
    {
        return (append(_X));
    }
    _Myt& operator+=(const _E *_S)
    {
        return (append(_S));
    }
    _Myt& operator+=(_E _C)
    {
        return (append(1, _C));
    }
    _Myt& append(const _Myt& _X)
    {
        return (append(_X, 0, npos));
    }
    _Myt& append(const _Myt& _X, size_type _P, size_type _M)
    {
        AssertH (_X.size() >= _P);
        //if (_X.size() < _P)
        //    _Xran();

        size_type _N = _X.size() - _P;
        if (_N < _M)
            _M = _N;

        AssertH ((_Len + _M < npos));
        //if (npos - _Len <= _M)
        //    _Xlen();

        if (0 < _M && _Grow(_N = _Len + _M))
        {
            _Tr::copy(_Ptr + _Len, &_X.c_str()[_P], _M);
            _Eos(_N);
        }
        return (*this);
    }
    _Myt& append(const _E *_S, size_type _M)
    {
        AssertH ((_Len + _M < npos));
        //if (npos - _Len <= _M)
        //    _Xlen();

        size_type _N;
        if (0 < _M && _Grow(_N = _Len + _M))
        {
            _Tr::copy(_Ptr + _Len, _S, _M);
            _Eos(_N);
        }
        return (*this);
    }
    _Myt& append(const _E *_S)
    {
        return (append(_S, _Tr::length(_S)));
    }
    _Myt& append(size_type _M, _E _C)
    {
        AssertH ((_Len + _M < npos));
        //if (npos - _Len <= _M)
        //    _Xlen();

        size_type _N;
        if (0 < _M && _Grow(_N = _Len + _M))
        {
            _Tr::assign(_Ptr + _Len, _M, _C);
            _Eos(_N);
        }
        return (*this);
    }
    _Myt& append(_It _F, _It _L)
    {
        return (replace(end(), end(), _F, _L));
    }
    _Myt& assign(const _Myt& _X)
    {
        return (assign(_X, 0, npos));
    }
    _Myt& assign(const _Myt& _X, size_type _P, size_type _M)
    {
        AssertH (_X.size() >= _P);
        //if (_X.size() < _P)
        //    _Xran();

        size_type _N = _X.size() - _P;
        if (_M < _N)
            _N = _M;

        if (this == &_X)
        {
            erase((size_type)(_P + _N)), erase(0, _P);
        }
        else if (0 < _N && _N == _X.size()
                 && _Refcnt(_X.c_str()) < _FROZEN - 1)
        {
            _Tidy(true);
            _Ptr = (_E *)_X.c_str();
            _Len = _X.size();
            _Res = _X.capacity();
            ++_Refcnt(_Ptr);
        }
        else if (_Grow(_N, true))
        {
            _Tr::copy(_Ptr, &_X.c_str()[_P], _N);
            _Eos(_N);
        }
        return (*this);
    }
    _Myt& assign(const _E *_S, size_type _N)
    {
        if (_Grow(_N))
        {
            _Tr::copy(_Ptr, _S, _N);
            _Eos(_N);
        }
        return (*this);
    }
    _Myt& assign(const _E *_S)
    {
        return (assign(_S, _Tr::length(_S)));
    }
    _Myt& assignSafe(const _E *_S)
    {
        return (_S) ? assign(_S, _Tr::length(_S)) : erase();
    }
    _Myt& assign(size_type _N, _E _C)
    {
        AssertH (npos != _N);
        //if (_N == npos)
        //    _Xlen();

        if (_Grow(_N))
        {
            _Tr::assign(_Ptr, _N, _C);
            _Eos(_N);
        }
        return (*this);
    }
    _Myt& assign(_It _F, _It _L)
    {
        return (replace(begin(), end(), _F, _L));
    }
    _Myt& insert(size_type _P0, const _Myt& _X)
    {
        return (insert(_P0, _X, 0, npos));
    }
    _Myt& insert(size_type _P0, const _Myt& _X, size_type _P, size_type _M)
    {
        AssertH ((_Len >= _P0) && (_X.size() >= _P));
        //if (_Len < _P0 || _X.size() < _P)
        //    _Xran();

        size_type _N = _X.size() - _P;
        if (_N < _M)
            _M = _N;

        AssertH ((_Len + _M < npos));
        //if (npos - _Len <= _M)
        //    _Xlen();

        if (0 < _M && _Grow(_N = _Len + _M))
        {
            _Tr::move(_Ptr + _P0 + _M, _Ptr + _P0, _Len - _P0);
            _Tr::copy(_Ptr + _P0, &_X.c_str()[_P], _M);
            _Eos(_N);
        }
        return (*this);
    }
    _Myt& insert(size_type _P0, const _E *_S, size_type _M)
    {
        AssertH (_Len >= _P0);
        //if (_Len < _P0)
        //    _Xran();

        AssertH ((_Len + _M < npos));
        //if (npos - _Len <= _M)
        //    _Xlen();

        size_type _N;
        if (0 < _M && _Grow(_N = _Len + _M))
        {
            _Tr::move(_Ptr + _P0 + _M, _Ptr + _P0, _Len - _P0);
            _Tr::copy(_Ptr + _P0, _S, _M);
            _Eos(_N);
        }
        return (*this);
    }
    _Myt& insert(size_type _P0, const _E *_S)
    {
        return (insert(_P0, _S, _Tr::length(_S)));
    }
    _Myt& insert(size_type _P0, size_type _M, _E _C)
    {
        AssertH (_Len >= _P0);
        //if (_Len < _P0)
        //    _Xran();

        AssertH ((_Len + _M < npos));
        //if (npos - _Len <= _M)
        //    _Xlen();

        size_type _N;
        if (0 < _M && _Grow(_N = _Len + _M))
        {
            _Tr::move(_Ptr + _P0 + _M, _Ptr + _P0, _Len - _P0);
            _Tr::assign(_Ptr + _P0, _M, _C);
            _Eos(_N);
        }
        return (*this);
    }
    iterator insert(iterator _P, _E _C)
    {
        size_type _P0 = _Pdif(_P, begin());
        insert(_P0, 1, _C);
        return (begin() + _P0);
    }
    void insert(iterator _P, size_type _M, _E _C)
    {
        size_type _P0 = _Pdif(_P, begin());
        insert(_P0, _M, _C);
    }
    void insert(iterator _P, _It _F, _It _L)
    {
        replace(_P, _P, _F, _L);
    }
    _Myt& erase(size_type _P0 = 0, size_type _M = npos)
    {
        AssertH (_Len >= _P0);
        //if (_Len < _P0)
        //    _Xran();

        _Split();
        if (_Len - _P0 < _M)
            _M = _Len - _P0;
        if (0 < _M)
        {
            _Tr::move(_Ptr + _P0, _Ptr + _P0 + _M,
                      _Len - _P0 - _M);
            size_type _N = _Len - _M;
            if (_Grow(_N))
                _Eos(_N);
        }
        return (*this);
    }
    iterator erase(iterator _P)
    {
        size_t _M = _Pdif(_P, begin());
        erase(_M, 1);
        return (_Psum(_Ptr, _M));
    }
    iterator erase(iterator _F, iterator _L)
    {
        size_t _M = _Pdif(_F, begin());
        erase(_M, _Pdif(_L, _F));
        return (_Psum(_Ptr, _M));
    }
    _Myt& replace(size_type _P0, size_type _N0, const _Myt& _X)
    {
        return (replace(_P0, _N0, _X, 0, npos));
    }
    _Myt& replace(size_type _P0, size_type _N0, const _Myt& _X,
                  size_type _P, size_type _M)
    {
        AssertH ((_Len >= _P0) && (_X.size() >= _P));
        //if (_Len < _P0 || _X.size() < _P)
        //    _Xran();

        if (_Len - _P0 < _N0)
            _N0 = _Len - _P0;

        size_type _N = _X.size() - _P;
        if (_N < _M)
            _M = _N;

        AssertH (npos - _M > _Len - _N0);
        //if (npos - _M <= _Len - _N0)
        //    _Xlen();

        _Split();
        size_type _Nm = _Len - _N0 - _P0;
        if (_M < _N0)
            _Tr::move(_Ptr + _P0 + _M, _Ptr + _P0 + _N0, _Nm);

        if ((0 < _M || 0 < _N0) && _Grow(_N = _Len + _M - _N0))
        {
            if (_N0 < _M)
                _Tr::move(_Ptr + _P0 + _M, _Ptr + _P0 + _N0, _Nm);
            _Tr::copy(_Ptr + _P0, &_X.c_str()[_P], _M);
            _Eos(_N);
        }
        return (*this);
    }
    _Myt& replace(size_type _P0, size_type _N0, const _E *_S,
                  size_type _M)
    {
        AssertH (_Len >= _P0);
        //if (_Len < _P0)
        //    _Xran();

        if (_Len - _P0 < _N0)
            _N0 = _Len - _P0;

        AssertH (npos - _M > _Len - _N0);
        //if (npos - _M <= _Len - _N0)
        //    _Xlen();

        _Split();
        size_type _Nm = _Len - _N0 - _P0;
        if (_M < _N0)
            _Tr::move(_Ptr + _P0 + _M, _Ptr + _P0 + _N0, _Nm);
        size_type _N;
        if ((0 < _M || 0 < _N0) && _Grow(_N = _Len + _M - _N0))
        {
            if (_N0 < _M)
                _Tr::move(_Ptr + _P0 + _M, _Ptr + _P0 + _N0, _Nm);
            _Tr::copy(_Ptr + _P0, _S, _M);
            _Eos(_N);
        }
        return (*this);
    }
    _Myt& replace(size_type _P0, size_type _N0, const _E *_S)
    {
        return (replace(_P0, _N0, _S, _Tr::length(_S)));
    }
    _Myt& replace(size_type _P0, size_type _N0,
                  size_type _M, _E _C)
    {
        AssertH (_Len >= _P0);
        //if (_Len < _P0)
        //    _Xran();

        if (_Len - _P0 < _N0)
            _N0 = _Len - _P0;

        AssertH (npos - _M > _Len - _N0);
        //if (npos - _M <= _Len - _N0)
        //    _Xlen();

        _Split();
        size_type _Nm = _Len - _N0 - _P0;
        if (_M < _N0)
            _Tr::move(_Ptr + _P0 + _M, _Ptr + _P0 + _N0, _Nm);
        size_type _N;
        if ((0 < _M || 0 < _N0) && _Grow(_N = _Len + _M - _N0))
        {
            if (_N0 < _M)
                _Tr::move(_Ptr + _P0 + _M, _Ptr + _P0 + _N0,
                          _Nm);
            _Tr::assign(_Ptr + _P0, _M, _C);
            _Eos(_N);
        }
        return (*this);
    }
    _Myt& replace(iterator _F, iterator _L, const _Myt& _X)
    {
        return (replace(_Pdif(_F, begin()), _Pdif(_L, _F), _X));
    }
    _Myt& replace(iterator _F, iterator _L, const _E *_S,
                  size_type _M)
    {
        return (replace(_Pdif(_F, begin()), _Pdif(_L, _F), _S, _M));
    }
    _Myt& replace(iterator _F, iterator _L, const _E *_S)
    {
        return (replace(_Pdif(_F, begin()), _Pdif(_L, _F), _S));
    }
    _Myt& replace(iterator _F, iterator _L, size_type _M, _E _C)
    {
        return (replace(_Pdif(_F, begin()), _Pdif(_L, _F), _M, _C));
    }
    _Myt& replace(iterator _F1, iterator _L1,
                  _It _F2, _It _L2)
    {
        size_type _P0 = _Pdif(_F1, begin());
        size_type _M = 0;
        _Distance(_F2, _L2, _M);
        replace(_P0, _Pdif(_L1, _F1), _M, _E(0));
        for (_F1 = begin() + _P0; 0 < _M; ++_F1, ++_F2, --_M)
            *_F1 = *_F2;
        return (*this);
    }
    iterator begin()
    {
        _Freeze();
        return (_Ptr);
    }
    const_iterator begin() const
    {
        return (_Ptr);
    }
    iterator end()
    {
        _Freeze();
        return ((iterator)_Psum(_Ptr, _Len));
    }
    const_iterator end() const
    {
        return ((const_iterator)_Psum(_Ptr, _Len));
    }
    reverse_iterator rbegin()
    {
        return (reverse_iterator(end()));
    }
    const_reverse_iterator rbegin() const
    {
        return (const_reverse_iterator(end()));
    }
    reverse_iterator rend()
    {
        return (reverse_iterator(begin()));
    }
    const_reverse_iterator rend() const
    {
        return (const_reverse_iterator(begin()));
    }
    reference at(size_type _P0)
    {
        AssertH (_Len > _P0);
        //if (_Len <= _P0)
        //    _Xran();

        _Freeze();
        return (_Ptr[_P0]);
    }
    const_reference at(size_type _P0) const
    {
        AssertH (_Len > _P0);
        //if (_Len <= _P0)
        //    _Xran();

        return (_Ptr[_P0]);
    }
    reference operator[](size_type _P0)
    {
        if (_Len < _P0 || _Ptr == 0)
            return ((reference)*_Nullstr());

        _Freeze();
        return (_Ptr[_P0]);
    }
    const_reference operator[](size_type _P0) const
    {
        if (_Ptr == 0)
            return (*_Nullstr());
        else
            return (_Ptr[_P0]);
    }
    const _E *c_str() const
    {
        return (_Ptr == 0 ? _Nullstr() : _Ptr);
    }
    const _E *data() const
    {
        return (c_str());
    }
    size_type length() const
    {
        return (_Len);
    }
    size_type size() const
    {
        return (_Len);
    }
    void resize(size_type _N, _E _C)
    {
        _N <= _Len ? erase(_N) : append(_N - _Len, _C);
    }
    void resize(size_type _N)
    {
        _N <= _Len ? erase(_N) : append(_N - _Len, _E(0));
    }
    size_type capacity() const
    {
        return (_Res);
    }
    void reserve(size_type _N = 0)
    {
        if (_Res < _N)
            _Grow(_N);
    }
    bool empty() const
    {
        return (_Len == 0);
    }
    size_type copy(_E *_S, size_type _N, size_type _P0 = 0) const
    {
        AssertH (_Len >= _P0);
        //if (_Len < _P0)
        //    _Xran();

        if (_Len - _P0 < _N)
            _N = _Len - _P0;
        if (0 < _N)
            _Tr::copy(_S, _Ptr + _P0, _N);
        return (_N);
    }
    void swap(_Myt& _X)
    {
        std::swap(_Ptr, _X._Ptr);
        std::swap(_Len, _X._Len);
        std::swap(_Res, _X._Res);
    }
    void swap(_Myt& _X, _Myt& _Y)
    {
        _X.swap(_Y);
    }
    size_type find(const _Myt& _X, size_type _P = 0) const
    {
        return (find(_X.c_str(), _P, _X.size()));
    }
    size_type find(const _E *_S, size_type _P,
                   size_type _N) const
    {
        if (_N == 0 && _P <= _Len)
            return (_P);
        size_type _Nm;
        if (_P < _Len && _N <= (_Nm = _Len - _P))
        {
            const _E *_U, *_V;
            for (_Nm -= _N - 1, _V = _Ptr + _P;
                (_U = _Tr::find(_V, _Nm, *_S)) != 0;
                _Nm -= (size_type)(_U - _V + 1), _V = _U + 1)
                if (_Tr::compare(_U, _S, _N) == 0)
                    return (_U - _Ptr);
        }
        return (npos);
    }
    size_type find(const _E *_S, size_type _P = 0) const
    {
        return (find(_S, _P, _Tr::length(_S)));
    }
    size_type find(_E _C, size_type _P = 0) const
    {
        return (find((const _E *)&_C, _P, 1));
    }
    size_type rfind(const _Myt& _X, size_type _P = npos) const
    {
        return (rfind(_X.c_str(), _P, _X.size()));
    }
    size_type rfind(const _E *_S, size_type _P,
                    size_type _N) const
    {
        if (_N == 0)
            return (_P < _Len ? _P : _Len);
        if (_N <= _Len)
            for (const _E *_U = _Ptr +
                 + (_P < _Len - _N ? _P : _Len - _N); ; --_U)
                if (_Tr::eq(*_U, *_S)
                    && _Tr::compare(_U, _S, _N) == 0)
                    return (_U - _Ptr);
                else if (_U == _Ptr)
                    break;
        return (npos);
    }
    size_type rfind(const _E *_S, size_type _P = npos) const
    {
        return (rfind(_S, _P, _Tr::length(_S)));
    }
    size_type rfind(_E _C, size_type _P = npos) const
    {
        return (rfind((const _E *)&_C, _P, 1));
    }
    size_type find_first_of(const _Myt& _X,
                            size_type _P = 0) const
    {
        return (find_first_of(_X.c_str(), _P, _X.size()));
    }
    size_type find_first_of(const _E *_S, size_type _P,
                            size_type _N) const
    {
        if (0 < _N && _P < _Len)
        {
            const _E *const _V = _Ptr + _Len;
            for (const _E *_U = _Ptr + _P; _U < _V; ++_U)
                if (_Tr::find(_S, _N, *_U) != 0)
                    return (_U - _Ptr);
        }
        return (npos);
    }
    size_type find_first_of(const _E *_S, size_type _P = 0) const
    {
        return (find_first_of(_S, _P, _Tr::length(_S)));
    }
    size_type find_first_of(_E _C, size_type _P = 0) const
    {
        return (find((const _E *)&_C, _P, 1));
    }
    size_type find_last_of(const _Myt& _X,
                           size_type _P = npos) const
    {
        return (find_last_of(_X.c_str(), _P, _X.size()));
    }
    size_type find_last_of(const _E *_S, size_type _P,
                           size_type _N) const
    {
        if (0 < _N && 0 < _Len)
            for (const _E *_U = _Ptr
                 + (_P < _Len ? _P : _Len - 1); ; --_U)
                if (_Tr::find(_S, _N, *_U) != 0)
                    return (_U - _Ptr);
                else if (_U == _Ptr)
                    break;
        return (npos);
    }
    size_type find_last_of(const _E *_S,
                           size_type _P = npos) const
    {
        return (find_last_of(_S, _P, _Tr::length(_S)));
    }
    size_type find_last_of(_E _C, size_type _P = npos) const
    {
        return (rfind((const _E *)&_C, _P, 1));
    }
    size_type find_first_not_of(const _Myt& _X,
                                size_type _P = 0) const
    {
        return (find_first_not_of(_X.c_str(), _P,
                                  _X.size()));
    }
    size_type find_first_not_of(const _E *_S, size_type _P,
                                size_type _N) const
    {
        if (_P < _Len)
        {
            const _E *const _V = _Ptr + _Len;
            for (const _E *_U = _Ptr + _P; _U < _V; ++_U)
                if (_Tr::find(_S, _N, *_U) == 0)
                    return (_U - _Ptr);
        }
        return (npos);
    }
    size_type find_first_not_of(const _E *_S,
                                size_type _P = 0) const
    {
        return (find_first_not_of(_S, _P, _Tr::length(_S)));
    }
    size_type find_first_not_of(_E _C, size_type _P = 0) const
    {
        return (find_first_not_of((const _E *)&_C, _P, 1));
    }
    size_type find_last_not_of(const _Myt& _X,
                               size_type _P = npos) const
    {
        return (find_last_not_of(_X.c_str(), _P, _X.size()));
    }
    size_type find_last_not_of(const _E *_S, size_type _P,
                               size_type _N) const
    {
        if (0 < _Len)
            for (const _E *_U = _Ptr
                 + (_P < _Len ? _P : _Len - 1); ; --_U)
                if (_Tr::find(_S, _N, *_U) == 0)
                    return (_U - _Ptr);
                else if (_U == _Ptr)
                    break;
        return (npos);
    }
    size_type find_last_not_of(const _E *_S,
                               size_type _P = npos) const
    {
        return (find_last_not_of(_S, _P, _Tr::length(_S)));
    }
    size_type find_last_not_of(_E _C, size_type _P = npos) const
    {
        return (find_last_not_of((const _E *)&_C, _P, 1));
    }
    _Myt substr(size_type _P = 0, size_type _M = npos) const
    {
        return (_Myt(*this, _P, _M));
    }
    int compare(const _Myt& _X) const
    {
        return (compare(0, _Len, _X.c_str(), _X.size()));
    }
    int compare(size_type _P0, size_type _N0,
                const _Myt& _X) const
    {
        return (compare(_P0, _N0, _X, 0, npos));
    }
    int compare(size_type _P0, size_type _N0, const _Myt& _X,
                size_type _P, size_type _M) const
    {
        AssertH (_X.size() >= _P);
        //if (_X.size() < _P)
        //    _Xran();

        if (_X._Len - _P < _M)
            _M = _X._Len - _P;
        return (compare(_P0, _N0, _X.c_str() + _P, _M));
    }
    int compare(const _E *_S) const
    {
        return (compare(0, _Len, _S, _Tr::length(_S)));
    }
    int compare(size_type _P0, size_type _N0, const _E *_S) const
    {
        return (compare(_P0, _N0, _S, _Tr::length(_S)));
    }
    int compare(size_type _P0, size_type _N0, const _E *_S,
                size_type _M) const
    {
        AssertH (_Len >= _P0);
        //if (_Len < _P0)
        //    _Xran();

        if (_Len - _P0 < _N0)
            _N0 = _Len - _P0;
        size_type _Ans = _Tr::compare(_Psum(_Ptr, _P0), _S,
                                      _N0 < _M ? _N0 : _M);
        return (_Ans != 0 ? _Ans : _N0 < _M ? -1
                : _N0 == _M ? 0 : +1);
    }
private:
    enum
    {
        // the number of characters that, when multiplied by sizeof(_E) will
        // still fit within the range of size_type.  (We allocate two extra
        // characters -- one for the refcount, the other for the terminator.)
        //
        _MAX_SIZE = (((unsigned int)(-1)) / sizeof(_E)) - 2,

        // _MIN_SIZE seems to be an allocation granularity (in characters).
        // Allocation requests are bit ORed with _MIN_SIZE.
        //
        _MIN_SIZE = 7,
        //_MIN_SIZE = sizeof (_E) <= 32 ? 31 : 7
    };
    void _Copy(size_type _N)
    {
        //AssertSzH (_Len <= _N, "Can't allocate less than we need to copy");
        size_type _Ns = _N | _MIN_SIZE;

        if (_MAX_SIZE < _Ns)
            _Ns = _N;

        size_type _NewLen = (_Ns < _Len) ? _Ns : _Len;

        _E *_S = (_E*) MemAllocRaiseException ((_Ns + 2) * sizeof(_E));

        //_TRY_BEGIN
        //_S = allocator.allocate(_Ns + 2, (void *)0);
        //_CATCH_ALL
        //_Ns = _N;
        //_S = allocator.allocate(_Ns + 2, (void *)0);
        //_CATCH_END

        if (_Len)
        {
            _Tr::copy(_S + 1, _Ptr, _NewLen);
        }

        _Tidy(true);
        _Ptr = _S + 1;
        _Refcnt(_Ptr) = 0;
        _Res = _Ns;
        _Eos(_NewLen);
    }
    void _Eos(size_type _N)
    {
        _Tr::assign(_Ptr[_Len = _N], _E(0));
    }
    void _Freeze()
    {
        if (_Ptr != 0
            && _Refcnt(_Ptr) != 0 && _Refcnt(_Ptr) != _FROZEN)
            _Grow(_Len);
        if (_Ptr != 0)
            _Refcnt(_Ptr) = _FROZEN;
    }
    bool _Grow(size_type _N, bool _Trim = false)
    {
        AssertH (_N < _MAX_SIZE);
        //if (_MAX_SIZE < _N)
        //    _Xlen();

        if (_Ptr != 0 && _Refcnt(_Ptr) != 0 && _Refcnt(_Ptr) != _FROZEN)
        {
            if (_N == 0)
            {
                --_Refcnt(_Ptr), _Tidy();
                return (false);
            }
            else
            {
                _Copy(_N);
                return (true);
            }
        }
        else if (_N == 0)
        {
            if (_Trim)
            {
                _Tidy(true);
            }
            else if (_Ptr != 0)
            {
                _Eos(0);
            }

            return (false);
        }
        else
        {
            if (_Trim && (_N > _Res || _Res > _MIN_SIZE))
            {
                _Tidy(true);
                _Copy(_N);
            }
            else if (!_Trim && (_N > _Res))
            {
                _Copy(_N);
            }

            return (true);
        }
    }
    static const _E * __cdecl _Nullstr()
    {
        static const _E _C = _E(0);
        return (&_C);
    }
    static size_type _Pdif(const_pointer _P2, const_pointer _P1)
    {
        return (_P2 == 0 ? 0 : _P2 - _P1);
    }
    static const_pointer _Psum(const_pointer _P, size_type _N)
    {
        return (_P == 0 ? 0 : _P + _N);
    }
    static pointer _Psum(pointer _P, size_type _N)
    {
        return (_P == 0 ? 0 : _P + _N);
    }
    unsigned short& _Refcnt(const _E *_U)
    {
        return (((unsigned short *)_U)[-1]);
    }
    void _Split()
    {
        if (_Ptr != 0 && _Refcnt(_Ptr) != 0 && _Refcnt(_Ptr) != _FROZEN)
        {
            _E *_Temp = _Ptr;
            _Tidy(true);
            assign(_Temp);
        }
    }
    void _Tidy(bool _Built = false)
    {
        if (!_Built || _Ptr == 0)
        {
            ;
        }
        else if (_Refcnt(_Ptr) == 0 || _Refcnt(_Ptr) == _FROZEN)
        {
            MemFree(_Ptr - 1);
            //allocator.deallocate(_Ptr - 1, _Res + 2);
        }
        else
        {
            --_Refcnt(_Ptr);
        }
        _Ptr = 0, _Len = 0, _Res = 0;
    }
    _E *_Ptr;
    size_type _Len, _Res;
};



inline
CWideString __cdecl operator+(
    const CWideString& _L,
    const CWideString& _R)
{return (CWideString(_L) += _R); }

inline
CWideString __cdecl operator+(
    const CWideString::_E *_L,
    const CWideString& _R)
{return (CWideString(_L) += _R); }

inline
CWideString __cdecl operator+(
    const CWideString::_E _L,
    const CWideString& _R)
{return (CWideString(1, _L) += _R); }

inline
CWideString __cdecl operator+(
    const CWideString& _L,
    const CWideString::_E *_R)
{return (CWideString(_L) += _R); }

inline
CWideString __cdecl operator+(
    const CWideString& _L,
    const CWideString::_E _R)
{return (CWideString(_L) += _R); }

inline
bool __cdecl operator==(
    const CWideString& _L,
    const CWideString& _R)
{return (_L.compare(_R) == 0); }

inline
bool __cdecl operator==(
    const CWideString::_E * _L,
    const CWideString& _R)
{return (_R.compare(_L) == 0); }

inline
bool __cdecl operator==(
    const CWideString& _L,
    const CWideString::_E *_R)
{return (_L.compare(_R) == 0); }

inline
bool __cdecl operator!=(
    const CWideString& _L,
    const CWideString& _R)
{return (!(_L == _R)); }

inline
bool __cdecl operator!=(
    const CWideString::_E *_L,
    const CWideString& _R)
{return (!(_L == _R)); }

inline
bool __cdecl operator!=(
    const CWideString& _L,
    const CWideString::_E *_R)
{return (!(_L == _R)); }

inline
bool __cdecl operator<(
    const CWideString& _L,
    const CWideString& _R)
{return (_L.compare(_R) < 0); }

inline
bool __cdecl operator<(
    const CWideString::_E * _L,
    const CWideString& _R)
{return (_R.compare(_L) > 0); }

inline
bool __cdecl operator<(
    const CWideString& _L,
    const CWideString::_E *_R)
{return (_L.compare(_R) < 0); }

inline
bool __cdecl operator>(
    const CWideString& _L,
    const CWideString& _R)
{return (_R < _L); }

inline
bool __cdecl operator>(
    const CWideString::_E * _L,
    const CWideString& _R)
{return (_R < _L); }

inline
bool __cdecl operator>(
    const CWideString& _L,
    const CWideString::_E *_R)
{return (_R < _L); }

inline
bool __cdecl operator<=(
    const CWideString& _L,
    const CWideString& _R)
{return (!(_R < _L)); }

inline
bool __cdecl operator<=(
    const CWideString::_E * _L,
    const CWideString& _R)
{return (!(_R < _L)); }

inline
bool __cdecl operator<=(
    const CWideString& _L,
    const CWideString::_E *_R)
{return (!(_R < _L)); }

inline
bool __cdecl operator>=(
    const CWideString& _L,
    const CWideString& _R)
{return (!(_L < _R)); }

inline
bool __cdecl operator>=(
    const CWideString::_E * _L,
    const CWideString& _R)
{return (!(_L < _R)); }

inline
bool __cdecl operator>=(
    const CWideString& _L,
    const CWideString::_E *_R)
{return (!(_L < _R)); }

#endif // _NCSTLSTR_H_