// xstring internal header (from <string>) -*-c++-*-
// Copyright 2003-2020 IAR Systems AB. 
#ifndef _DLIB5_XSTRING_
#define _DLIB5_XSTRING_

#ifndef _SYSTEM_BUILD
#pragma system_include
#endif

#include <string.h>
#include <dlib5/xstddef>

_DLIB5_BEGIN

                // STRUCT char_traits (FROM <string>)
struct char_traits
{       // properties of a string or stream char element
  typedef char _Elem;
  typedef _Elem char_type;
  typedef int int_type;
  typedef size_t pos_type;
  typedef ptrdiff_t off_type;
//  typedef mbstate_t state_type;

  static void assign(_Elem& _Left, const _Elem& _Right)
  {     // assign an element
    _Left = _Right;
  }

  static bool eq(const _Elem& _Left, const _Elem& _Right)
  {     // test for element equality
    return (_Left == _Right);
  }

  static bool lt(const _Elem& _Left, const _Elem& _Right)
  {     // test if _Left precedes _Right
    return (_Left < _Right);
  }

  static int compare(const _Elem *_First1, const _Elem *_First2,
                     size_t _Count)
  {     // compare [_First1, _First1 + _Count) with [_First2, ...)
    return (_CSTD memcmp(_First1, _First2, _Count));
  }

  static size_t length(const _Elem *_First)
  {     // find length of null-terminated string
    return (_CSTD strlen(_First));
  }

  static _Elem *copy(_Elem *_First1, const _Elem *_First2,
                     size_t _Count)
  {     // copy [_First1, _First1 + _Count) to [_First2, ...)
    return ((_Elem *)_CSTD memcpy(_First1, _First2, _Count));
  }

  static const _Elem *find(const _Elem *_First, size_t _Count,
                           const _Elem& _Ch)
  {     // look for _Ch in [_First, _First + _Count)
    return ((const _Elem *)_CSTD memchr(_First, _Ch, _Count));
  }

  static _Elem *move(_Elem *_First1, const _Elem *_First2,
                     size_t _Count)
  {     // copy [_First1, _First1 + _Count) to [_First2, ...)
    return ((_Elem *)_CSTD memmove(_First1, _First2, _Count));
  }

  static _Elem *assign(_Elem *_First, size_t _Count, _Elem _Ch)
  {     // assign _Count * _Ch to [_First, ...)
    return ((_Elem *)_CSTD memset(_First, _Ch, _Count));
  }

  static _Elem to_char_type(const int_type& _Meta)
  {     // convert metacharacter to character
    return ((_Elem)_Meta);
  }

  static int_type to_int_type(const _Elem& _Ch)
  {     // convert character to metacharacter
    return ((unsigned char)_Ch);
  }

  static bool eq_int_type(const int_type& _Left,
                          const int_type& _Right)
  {     // test for metacharacter equality
    return (_Left == _Right);
  }

  static int_type eof()
  {     // return end-of-file metacharacter
    return (-1);
  }

  static int_type not_eof(const int_type& _Meta)
  {     // return anything but EOF
    return (_Meta != eof() ? _Meta : !eof());
  }
};

// CLASS _String_base
class _String_base
{       // ultimate base class for string to hold error reporters
public:
  void _Xlen() const;   // report a length_error

  void _Xran() const;   // report an out_of_range error

  // Variants that are used when exceptions are disabled. 
  void _XlenAbort() const;     // report a length_error
  void _XranAbort() const;     // report an out_of_range error
};

// CLASS char_allocator
class char_allocator
{       // allocator for string memory
public:
  char_allocator()
  {     // construct default allocator
  }

  static char *allocate(size_t _Count)
  {     // allocate _Count bytes, ignoring hint
    return ((char *)operator new(_Count));
  }

  static void deallocate(void *_Ptr, size_t)
  {     // delete object at _Ptr, ignoring size
    operator delete(_Ptr);
  }

  static size_t max_size()
  {     // return estimate of maximum size
    return ((size_t)(-1));
  }

  bool operator==(const char_allocator&) const
  {     // report all allocators as equal
    return (true);
  }
};

// CLASS _String_val
class _String_val
  : public _String_base
{       // base class for string to hold allocator _Alval
protected:
  _String_val(char_allocator _Al = char_allocator())
    : _Alval(_Al)
  {     // construct allocator from _Al
  }

  char_allocator _Alval;        // allocator object for strings
};

// CLASS string
class string
  : public _String_val
{       // null-terminated transparent array of chars
public:
  typedef string _Myt;
  typedef _String_val _Mybase;
  typedef char _Elem;
  typedef char_traits _Traits;
  typedef char_allocator _Alloc;
  typedef size_t size_type;
  typedef ptrdiff_t difference_type;
  typedef char *pointer;
  typedef const char *const_pointer;
  typedef char& reference;
  typedef const char& const_reference;
  typedef char value_type;
  typedef pointer iterator;
  typedef const_pointer const_iterator;

  #define _STR_ITER_BASE(it)     (it)
  #define _DLIB5_STRING_ITERATOR(ptr)  (ptr)
  #define _DLIB5_STRING_CONST_ITERATOR(ptr)    (ptr)

  // CLASS reverse_iterator (from <iterator>)
  class reverse_iterator
  {     // reverse iterator for mutable string
  public:
    typedef reverse_iterator _Myt;
    typedef char *iter_type;
    typedef char value_type;
    typedef char& reference;
    typedef char *pointer;
    typedef ptrdiff_t difference_type;

    reverse_iterator()
    {   // construct with default wrapped iterator
    }

    explicit reverse_iterator(iter_type _Iter)
      : current(_Iter)
    {   // construct wrapped iterator from _Iter
    }

    iter_type base() const
    {   // return wrapped pointer
      return (current);
    }

    reference operator*() const
    {   // return designated object
      return (*(current - 1));
    }

    _Myt& operator++()
    {   // preincrement
      --current;
      return (*this);
    }

    _Myt operator++(int)
    {   // postincrement
      _Myt _Tmp = *this;
      --current;
      return (_Tmp);
    }

    _Myt& operator--()
    {   // predecrement
      ++current;
      return (*this);
    }

    _Myt operator--(int)
    {   // postdecrement
      _Myt _Tmp = *this;
      ++current;
      return (_Tmp);
    }

    _Myt& operator+=(difference_type _Off)
    {   // increment by integer
      current -= _Off;
      return (*this);
    }

    _Myt operator+(difference_type _Off) const
    {   // return this + integer
      return (_Myt(current - _Off));
    }

    _Myt& operator-=(difference_type _Off)
    {   // decrement by integer
      current += _Off;
      return (*this);
    }

    _Myt operator-(difference_type _Off) const
    {   // return this - integer
      return (_Myt(current + _Off));
    }

    difference_type operator-(const _Myt _Right) const
    {   // return difference of iterators
      return (_Right.current - current);
    }

    reference operator[](difference_type _Off) const
    {   // subscript
      return (*(*this + _Off));
    }

    bool operator==(const _Myt _Right) const
    {   // test for iterator equality
      return (current == _Right.current);
    }

    bool operator!=(const _Myt _Right) const
    {   // test for iterator inequality
      return (!(*this == _Right));
    }

    bool operator<(const _Myt _Right) const
    {   // test if this < _Right
      return (_Right.current < current);
    }

    bool operator>(const _Myt _Right) const
    {   // test if this > _Right
      return (_Right < *this);
    }

    bool operator<=(const _Myt _Right) const
    {   // test if this <= _Right
      return (!(_Right < *this));
    }

    bool operator>=(const _Myt _Right) const
    {   // test if this >= _Right
      return (!(*this < _Right));
    }

    friend _Myt operator+(ptrdiff_t _Off, const _Myt& _Right)
    {   // return iterator + integer
      return (_Myt(_Right.current - _Off));
    }

  protected:
    iter_type current;  // the wrapped iterator
  };

  // CLASS const_reverse_iterator (from <iterator>)
  class const_reverse_iterator
  {     // reverse iterator for nonmutable string
  public:
    typedef const_reverse_iterator _Myt;
    typedef const char *iter_type;
    typedef const char value_type;
    typedef const char& reference;
    typedef const char *pointer;
    typedef ptrdiff_t difference_type;

    const_reverse_iterator()
    {   // construct with default wrapped iterator
    }

    explicit const_reverse_iterator(iter_type _Iter)
      : current(_Iter)
    {   // construct wrapped iterator from _Iter
    }

    iter_type base() const
    {   // return wrapped iterator
      return (current);
    }

    reference operator*() const
    {   // return designated value
      return (*(current - 1));
    }

    _Myt& operator++()
    {   // preincrement
      --current;
      return (*this);
    }

    _Myt operator++(int)
    {   // predecrement
      _Myt _Tmp = *this;
      --current;
      return (_Tmp);
    }

    _Myt& operator--()
    {   // postincrement
      ++current;
      return (*this);
    }

    _Myt operator--(int)
    {   // postdecrement
      _Myt _Tmp = *this;
      ++current;
      return (_Tmp);
    }

    _Myt& operator+=(difference_type _Off)
    {   // increment by integer
      current -= _Off;
      return (*this);
    }

    _Myt operator+(difference_type _Off) const
    {   // return this + integer
      return (_Myt(current - _Off));
    }

    _Myt& operator-=(difference_type _Off)
    {   // decrement by integer
      current += _Off;
      return (*this);
    }

    _Myt operator-(difference_type _Off) const
    {   // return this - integer
      return (_Myt(current + _Off));
    }

    difference_type operator-(const _Myt _Right) const
    {   // return difference of iterators
      return (_Right.current - current);
    }

    reference operator[](difference_type _Off) const
    {   // subscript
      return (*(*this + _Off));
    }

    bool operator==(const _Myt _Right) const
    {   // test for equality
      return (current == _Right.current);
    }

    bool operator!=(const _Myt _Right) const
    {   // test for inequality
      return (!(*this == _Right));
    }

    bool operator<(const _Myt _Right) const
    {   // test if this < _Right
      return (_Right.current < current);
    }

    bool operator>(const _Myt _Right) const
    {   // test if this > _Right
      return (_Right < *this);
    }

    bool operator<=(const _Myt _Right) const
    {   // test if this <= _Right
      return (!(_Right < *this));
    }

    bool operator>=(const _Myt _Right) const
    {   // test if this >= _Right
      return (!(*this < _Right));
    }

    friend _Myt operator+(ptrdiff_t _Off, const _Myt& _Right)
    {   // return iterator + integer
      return (_Myt(_Right.current - _Off));
    }

  protected:
    iter_type current;  // the wrapped iterator
  };

  string()
    : _Mybase()
  {     // construct empty string
    _Tidy();
  }

  explicit string(const _Alloc& _Al)
    : _Mybase(_Al)
  {     // construct empty string with allocator
    _Tidy();
  }

  string(const _Myt& _Right)
    : _Mybase(_Right._Alval)
  {     // construct by copying _Right
    _Tidy();
    assign(_Right, 0, npos);
  }

  string(const _Myt& _Right, size_type _Roff,
         size_type _Count = npos)
    : _Mybase(_Right._Alval)
  {     // construct from _Right [_Roff, _Roff + _Count)
    _Tidy();
    assign(_Right, _Roff, _Count);
  }

  string(const _Myt& _Right, size_type _Roff, size_type _Count,
         const _Alloc& _Al)
    : _Mybase(_Al)
  {     // construct from _Right [_Roff, _Roff + _Count) with allocator
    _Tidy();
    assign(_Right, _Roff, _Count);
  }

  string(const _Elem *_Ptr, size_type _Count)
    : _Mybase()
  {     // construct from [_Ptr, _Ptr + _Count)
    _Tidy();
    assign(_Ptr, _Count);
  }

  string(const _Elem *_Ptr, size_type _Count, const _Alloc& _Al)
    : _Mybase(_Al)
  {     // construct from [_Ptr, _Ptr + _Count) with allocator
    _Tidy();
    assign(_Ptr, _Count);
  }

  string(const _Elem *_Ptr)
    : _Mybase()
  {     // construct from [_Ptr, <null>)
    _Tidy();
    assign(_Ptr);
  }

  string(const _Elem *_Ptr, const _Alloc& _Al)
    : _Mybase(_Al)
  {     // construct from [_Ptr, <null>) with allocator
    _Tidy();
    assign(_Ptr);
  }

  string(size_type _Count, _Elem _Ch)
    : _Mybase()
  {     // construct from _Count * _Ch
    _Tidy();
    assign(_Count, _Ch);
  }

  string(size_type _Count, _Elem _Ch, const _Alloc& _Al)
    : _Mybase(_Al)
  {     // construct from _Count * _Ch with allocator
    _Tidy();
    assign(_Count, _Ch);
  }
  string(const_iterator _First, const_iterator _Last,
         const _Alloc& _Al)
    : _Mybase(_Al)
  {     // construct from [_First, _Last) with allocator, const_iterators
    _Tidy();
    if (_First != _Last)
      assign(&*_First, _Last - _First);
  }

  string(const_iterator _First, const_iterator _Last)
    : _Mybase()
  {     // construct from [_First, _Last), const_iterators
    _Tidy();
    if (_First != _Last)
      assign(&*_First, _Last - _First);
  }

  ~string()
  {     // destroy the string
    _Tidy(true);
  }

  typedef _Traits traits_type;
  typedef _Alloc allocator_type;

  _DLIB_CONST_ATTR static const size_type npos;  // generic bad/missing length/position

  _Myt& operator=(const _Myt& _Right)
  {     // assign _Right
    return (assign(_Right));
  }

  _Myt& operator=(const _Elem *_Ptr)
  {     // assign [_Ptr, <null>)
    return (assign(_Ptr));
  }

  _Myt& operator=(_Elem _Ch)
  {     // assign 1 * _Ch
    return (assign(1, _Ch));
  }

  _Myt& operator+=(const _Myt& _Right)
  {     // append _Right
    return (append(_Right));
  }

  _Myt& operator+=(const _Elem *_Ptr)
  {     // append [_Ptr, <null>)
    return (append(_Ptr));
  }

  _Myt& operator+=(_Elem _Ch)
  {     // append 1 * _Ch
    return (append((size_type)1, _Ch));
  }

  _Myt& append(const _Myt& _Right)
  {     // append _Right
    return (append(_Right, 0, npos));
  }

  _Myt& append(const _Myt& _Right, size_type _Roff, size_type _Count);

  _Myt& append(const _Elem *_Ptr, size_type _Count);

  _Myt& append(const _Elem *_Ptr)
  {     // append [_Ptr, <null>)
    return (append(_Ptr, _Traits::length(_Ptr)));
  }

  _Myt& append(size_type _Count, _Elem _Ch);

  _Myt& append(const_iterator _First, const_iterator _Last)
  {     // append [_First, _Last), const_iterators
    return (replace(end(), end(), _First, _Last));
  }

  _Myt& assign(const _Myt& _Right)
  {     // assign _Right
    return (assign(_Right, 0, npos));
  }

  _Myt& assign(const _Myt& _Right, size_type _Roff, size_type _Count);

  _Myt& assign(const _Elem *_Ptr, size_type _Count);

  _Myt& assign(const _Elem *_Ptr)
  {     // assign [_Ptr, <null>)
    return (assign(_Ptr, _Traits::length(_Ptr)));
  }

  _Myt& assign(size_type _Count, _Elem _Ch);

  _Myt& assign(const_iterator _First, const_iterator _Last)
  {     // assign [First, _Last), const_iterators
    return (replace(begin(), end(), _First, _Last));
  }

  _Myt& insert(size_type _Off, const _Myt& _Right)
  {     // insert _Right at _Off
    return (insert(_Off, _Right, 0, npos));
  }

  _Myt& insert(size_type _Off, const _Myt& _Right, size_type _Roff,
               size_type _Count);

  _Myt& insert(size_type _Off, const _Elem *_Ptr, size_type _Count);

  _Myt& insert(size_type _Off, const _Elem *_Ptr)
  {     // insert [_Ptr, <null>) at _Off
    return (insert(_Off, _Ptr, _Traits::length(_Ptr)));
  }

  _Myt& insert(size_type _Off, size_type _Count, _Elem _Ch);

  iterator insert(const_iterator _Where)
  {     // insert <null> at _Where
    return (insert(_Where, _Elem()));
  }

  iterator insert(const_iterator _Where, _Elem _Ch)
  {     // insert _Ch at _Where
    size_type _Off = _Pdif(_Where, begin());
    insert(_Off, 1, _Ch);
    return (begin() + _Off);
  }

  void insert(const_iterator _Where, size_type _Count, _Elem _Ch)
  {     // insert _Count * _Elem at _Where
    size_type _Off = _Pdif(_Where, begin());
    insert(_Off, _Count, _Ch);
  }

  void insert(const_iterator _Where,
              const_iterator _First, const_iterator _Last)
  {     // insert [_First, _Last) at _Where, const_iterators
    replace(_Where, _Where, _First, _Last);
  }

  _Myt& erase(size_type _Off = 0, size_type _Count = npos);

  iterator erase(const_iterator _Where)
  {     // erase element at _Where
    size_type _Count = _Pdif(_Where, begin());
    erase(_Count, 1);
    return (_DLIB5_STRING_ITERATOR(_Myptr() + _Count));
  }

  iterator erase(const_iterator _First, const_iterator _Last)
  {     // erase substring [_First, _Last)
    size_type _Count = _Pdif(_First, begin());
    erase(_Count, _Pdif(_Last, _First));
    return (_DLIB5_STRING_ITERATOR(_Myptr() + _Count));
  }

  void clear()
  {     // erase all
    erase(begin(), end());
  }

  _Myt& replace(size_type _Off, size_type _N0, const _Myt& _Right)
  {     // replace [_Off, _Off + _N0) with _Right
    return (replace(_Off, _N0, _Right, 0, npos));
  }

  _Myt& replace(size_type _Off, size_type _N0, const _Myt& _Right,
                size_type _Roff, size_type _Count);

  _Myt& replace(size_type _Off, size_type _N0, const _Elem *_Ptr,
                size_type _Count);

  _Myt& replace(size_type _Off, size_type _N0, const _Elem *_Ptr)
  {     // replace [_Off, _Off + _N0) with [_Ptr, <null>)
    return (replace(_Off, _N0, _Ptr, _Traits::length(_Ptr)));
  }

  _Myt& replace(size_type _Off, size_type _N0,
                size_type _Count, _Elem _Ch);

  _Myt& replace(const_iterator _First, const_iterator _Last, const _Myt& _Right)
  {     // replace [_First, _Last) with _Right
    return (replace(
      _Pdif(_First, begin()), _Pdif(_Last, _First), _Right));
  }

  _Myt& replace(const_iterator _First, const_iterator _Last, const _Elem *_Ptr,
                size_type _Count)
  {     // replace [_First, _Last) with [_Ptr, _Ptr + _Count)
    return (replace(
      _Pdif(_First, begin()), _Pdif(_Last, _First), _Ptr, _Count));
  }

  _Myt& replace(const_iterator _First, const_iterator _Last, const _Elem *_Ptr)
  {     // replace [_First, _Last) with [_Ptr, <null>)
    return (replace(
      _Pdif(_First, begin()), _Pdif(_Last, _First), _Ptr));
  }

  _Myt& replace(const_iterator _First, const_iterator _Last,
                size_type _Count, _Elem _Ch)
  {     // replace [_First, _Last) with _Count * _Ch
    return (replace(
      _Pdif(_First, begin()), _Pdif(_Last, _First), _Count, _Ch));
  }

  _Myt& replace(const_iterator _First, const_iterator _Last,
                const_iterator _First2, const_iterator _Last2)
  {     // replace [_First, _Last) with [_First2, _Last2), const_iterators
    if (_First2 == _Last2)
      erase(_Pdif(_First, begin()), _Pdif(_Last, _First));
    else
      replace(_Pdif(_First, begin()), _Pdif(_Last, _First),
              &*_First2, _Last2 - _First2);
    return (*this);
  }

  iterator begin()
  {     // return iterator for beginning of mutable sequence
    return (_DLIB5_STRING_ITERATOR(_Myptr()));
  }

  const_iterator begin() const
  {     // return iterator for beginning of nonmutable sequence
    return (_DLIB5_STRING_CONST_ITERATOR(_Myptr()));
  }

  iterator end()
  {     // return iterator for end of mutable sequence
    return (_DLIB5_STRING_ITERATOR(_Myptr() + _Mysize));
  }

  const_iterator end() const
  {     // return iterator for end of nonmutable sequence
    return (_DLIB5_STRING_CONST_ITERATOR(_Myptr() + _Mysize));
  }

  reverse_iterator rbegin()
  {     // return iterator for beginning of reversed mutable sequence
    return (reverse_iterator(end()));
  }

  const_reverse_iterator rbegin() const
  {     // return iterator for beginning of reversed nonmutable sequence
    return (const_reverse_iterator(end()));
  }

  reverse_iterator rend()
  {     // return iterator for end of reversed mutable sequence
    return (reverse_iterator(begin()));
  }

  const_reverse_iterator rend() const
  {     // return iterator for end of reversed nonmutable sequence
    return (const_reverse_iterator(begin()));
  }

  reference at(size_type _Off)
  {     // subscript mutable sequence with checking
    if (_Mysize <= _Off)
      _String_base::_Xran();    // _Off off end
    return (_Myptr()[_Off]);
  }

  const_reference at(size_type _Off) const
  {     // subscript nonmutable sequence with checking
    if (_Mysize <= _Off)
      _String_base::_Xran();    // _Off off end
    return (_Myptr()[_Off]);
  }

  reference operator[](size_type _Off)
  {     // subscript mutable sequence
    return (_Myptr()[_Off]);
  }

  const_reference operator[](size_type _Off) const
  {     // subscript nonmutable sequence
    return (_Myptr()[_Off]);
  }

  void push_back(_Elem _Ch)
  {     // insert element at end
    insert(end(), _Ch);
  }

  const _Elem *c_str() const
  {     // return pointer to null-terminated nonmutable array
    return (_Myptr());
  }

  const _Elem *data() const
  {     // return pointer to nonmutable array
    return (c_str());
  }

  size_type length() const
  {     // return length of sequence
    return (_Mysize);
  }

  size_type size() const
  {     // return length of sequence
    return (_Mysize);
  }

  size_type max_size() const
  {     // return maximum possible length of sequence
    size_type _Num = _Mybase::_Alval.max_size();
    return (_Num <= 1 ? 1 : _Num - 1);
  }

  void resize(size_type _Newsize)
  {     // determine new length, padding with null elements as needed
    resize(_Newsize, _Elem());
  }

  void resize(size_type _Newsize, _Elem _Ch)
  {     // determine new length, padding with _Ch elements as needed
    if (_Newsize <= _Mysize)
      erase(_Newsize);
    else
      append(_Newsize - _Mysize, _Ch);
  }

  size_type capacity() const
  {     // return current length of allocated storage
    return (_Myres);
  }

  void reserve(size_type _Newcap = 0)
  {     // determine new minimum length of allocated storage
    if (_Mysize <= _Newcap && _Myres != _Newcap)
    {   // change reservation
      size_type _Size = _Mysize;
      if (_Grow(_Newcap, true))
        _Eos(_Size);
    }
  }

  bool empty() const
  {     // test if sequence is empty
    return (_Mysize == 0);
  }

  size_type copy(_Elem *_Ptr, size_type _Count, size_type _Off = 0) const;

  void swap(_Myt& _Right);

  size_type find(const _Myt& _Right, size_type _Off = 0) const
  {     // look for _Right beginnng at or after _Off
    return (find(_Right._Myptr(), _Off, _Right.size()));
  }

  size_type find(const _Elem *_Ptr, size_type _Off,
                 size_type _Count) const;

  size_type find(const _Elem *_Ptr, size_type _Off = 0) const
  {     // look for [_Ptr, <null>) beginnng at or after _Off
    return (find(_Ptr, _Off, _Traits::length(_Ptr)));
  }

  size_type find(_Elem _Ch, size_type _Off = 0) const
  {     // look for _Ch at or after _Off
    return (find((const _Elem *)&_Ch, _Off, 1));
  }

  size_type rfind(const _Myt& _Right, size_type _Off = npos) const
  {     // look for _Right beginning before _Off
    return (rfind(_Right._Myptr(), _Off, _Right.size()));
  }

  size_type rfind(const _Elem *_Ptr, size_type _Off,
                  size_type _Count) const;

  size_type rfind(const _Elem *_Ptr, size_type _Off = npos) const
  {     // look for [_Ptr, <null>) beginning before _Off
    return (rfind(_Ptr, _Off, _Traits::length(_Ptr)));
  }

  size_type rfind(_Elem _Ch, size_type _Off = npos) const
  {     // look for _Ch before _Off
    return (rfind((const _Elem *)&_Ch, _Off, 1));
  }

  size_type find_first_of(const _Myt& _Right,
                          size_type _Off = 0) const
  {     // look for one of _Right at or after _Off
    return (find_first_of(_Right._Myptr(), _Off, _Right.size()));
  }

  size_type find_first_of(const _Elem *_Ptr, size_type _Off,
                          size_type _Count) const;

  size_type find_first_of(const _Elem *_Ptr, size_type _Off = 0) const
  {     // look for one of [_Ptr, <null>) at or after _Off
    return (find_first_of(_Ptr, _Off, _Traits::length(_Ptr)));
  }

  size_type find_first_of(_Elem _Ch, size_type _Off = 0) const
  {     // look for _Ch at or after _Off
    return (find((const _Elem *)&_Ch, _Off, 1));
  }

  size_type find_last_of(const _Myt& _Right,
                         size_type _Off = npos) const
  {     // look for one of _Right before _Off
    return (find_last_of(_Right._Myptr(), _Off, _Right.size()));
  }

  size_type find_last_of(const _Elem *_Ptr, size_type _Off,
                         size_type _Count) const;

  size_type find_last_of(const _Elem *_Ptr,
                         size_type _Off = npos) const
  {     // look for one of [_Ptr, <null>) before _Off
    return (find_last_of(_Ptr, _Off, _Traits::length(_Ptr)));
  }

  size_type find_last_of(_Elem _Ch, size_type _Off = npos) const
  {     // look for _Ch before _Off
    return (rfind((const _Elem *)&_Ch, _Off, 1));
  }

  size_type find_first_not_of(const _Myt& _Right,
                              size_type _Off = 0) const
  {     // look for none of _Right at or after _Off
    return (find_first_not_of(_Right._Myptr(), _Off,
                              _Right.size()));
  }

  size_type find_first_not_of(const _Elem *_Ptr, size_type _Off,
                              size_type _Count) const;

  size_type find_first_not_of(const _Elem *_Ptr,
                              size_type _Off = 0) const
  {     // look for one of [_Ptr, <null>) at or after _Off
    return (find_first_not_of(_Ptr, _Off, _Traits::length(_Ptr)));
  }

  size_type find_first_not_of(_Elem _Ch, size_type _Off = 0) const
  {     // look for non _Ch at or after _Off
    return (find_first_not_of((const _Elem *)&_Ch, _Off, 1));
  }

  size_type find_last_not_of(const _Myt& _Right,
                             size_type _Off = npos) const
  {     // look for none of _Right before _Off
    return (find_last_not_of(_Right._Myptr(), _Off, _Right.size()));
  }

  size_type find_last_not_of(const _Elem *_Ptr, size_type _Off,
                             size_type _Count) const;

  size_type find_last_not_of(const _Elem *_Ptr,
                             size_type _Off = npos) const
  {     // look for none of [_Ptr, <null>) before _Off
    return (find_last_not_of(_Ptr, _Off, _Traits::length(_Ptr)));
  }

  size_type find_last_not_of(_Elem _Ch, size_type _Off = npos) const
  {     // look for non _Ch before _Off
    return (find_last_not_of((const _Elem *)&_Ch, _Off, 1));
  }

  _Myt substr(size_type _Off = 0, size_type _Count = npos) const
  {     // return [_Off, _Off + _Count) as new string
    return (_Myt(*this, _Off, _Count, get_allocator()));
  }

  int compare(const _Myt& _Right) const
  {     // compare [0, _Mysize) with _Right
    return (compare(0, _Mysize, _Right._Myptr(), _Right.size()));
  }

  int compare(size_type _Off, size_type _N0,
              const _Myt& _Right) const
  {     // compare [_Off, _Off + _N0) with _Right
    return (compare(_Off, _N0, _Right, 0, npos));
  }

  int compare(size_type _Off, size_type _N0, const _Myt& _Right,
              size_type _Roff, size_type _Count) const;

  int compare(const _Elem *_Ptr) const
  {     // compare [0, _Mysize) with [_Ptr, <null>)
    return (compare(0, _Mysize, _Ptr, _Traits::length(_Ptr)));
  }

  int compare(size_type _Off, size_type _N0, const _Elem *_Ptr) const
  {     // compare [_Off, _Off + _N0) with [_Ptr, <null>)
    return (compare(_Off, _N0, _Ptr, _Traits::length(_Ptr)));
  }

  int compare(size_type _Off, size_type _N0, const _Elem *_Ptr,
              size_type _Count) const;

  allocator_type get_allocator() const
  {     // return allocator object for values
    return (_Mybase::_Alval);
  }

  enum
  {     // length of internal buffer, [1, 16]
    _BUF_SIZE = 16 / sizeof (_Elem) < 1 ? 1
    : 16 / sizeof(_Elem)};

protected:
  enum
  {     // roundup mask for allocated buffers, [0, 15]
    _ALLOC_MASK = sizeof (_Elem) <= 1 ? 15
    : sizeof (_Elem) <= 2 ? 7
    : sizeof (_Elem) <= 4 ? 3
    : sizeof (_Elem) <= 8 ? 1 : 0};

  void _Chassign(size_type _Off, size_type _Count, _Elem _Ch)
  {       // assign _Count copies of _Ch beginning at _Off
    if (_Count == 1)
      _Traits::assign(*(_Myptr() + _Off), _Ch);
    else
      _Traits::assign(_Myptr() + _Off, _Count, _Ch);
  }

  void _Copy(size_type _Newsize, size_type _Oldlen);

  void _Eos(size_type _Newsize)
  {     // set new length and null terminator
    _Traits::assign(_Myptr()[_Mysize = _Newsize], _Elem());
  }

  bool _Grow(size_type _Newsize, bool _Trim = false);

  bool _Inside(const _Elem *_Ptr);

  static size_type _Pdif(const_iterator _P2,
                         const_iterator _P1)
  {     // compute safe iterator difference
    return (_STR_ITER_BASE(_P2) == 0 ? 0 : _P2 - _P1);
  }

  void _Tidy(bool _Built = false, size_type _Newsize = 0);

  union _Bxty
  {     // storage for small buffer or pointer to larger one
    _Elem _Buf[_BUF_SIZE];
    _Elem *_Ptr;
  } _Bx;

  _Elem *_Myptr()
  {     // determine current pointer to buffer for mutable string
    return (_BUF_SIZE <= _Myres ? _Bx._Ptr : _Bx._Buf);
  }

  const _Elem *_Myptr() const
  {     // determine current pointer to buffer for nonmutable string
    return (_BUF_SIZE <= _Myres ? _Bx._Ptr : _Bx._Buf);
  }

  size_type _Mysize;    // current length of string
  size_type _Myres;     // current storage reserved for string
};

inline void swap(string& _Left, string& _Right)
{       // swap _Left and _Right strings
  _Left.swap(_Right);
}
_DLIB5_END
#endif /* _XSTRING */

/*
 * Copyright (c) 1992-2009 by P.J. Plauger.  ALL RIGHTS RESERVED.
 * Consult your license regarding permissions and restrictions.
 V5.04:0576 */
