// -*- C++ -*-
/***************************************************************************
 *
 * <string> - definition of the C++ Standard Library basic_string template
 *
 * $Id$
 *
 ***************************************************************************
 *
 * Copyright (c) 1994-2001 Rogue Wave Software, Inc.  All Rights Reserved.
 *
 * This computer software is owned by Rogue Wave Software, Inc. and is
 * protected by U.S. copyright laws and other laws and by international
 * treaties.  This computer software is furnished by Rogue Wave Software,
 * Inc. pursuant to a written license agreement and may be used, copied,
 * transmitted, and stored only in accordance with the terms of such
 * license and with the inclusion of the above copyright notice.  This
 * computer software or any other copies thereof may not be provided or
 * otherwise made available to any other person.
 *
 * U.S. Government Restricted Rights.  This computer software is provided
 * with Restricted Rights.  Use, duplication, or disclosure by the
 * Government is subject to restrictions as set forth in subparagraph (c)
 * (1) (ii) of The Rights in Technical Data and Computer Software clause
 * at DFARS 252.227-7013 or subparagraphs (c) (1) and (2) of the
 * Commercial Computer Software--Restricted Rights at 48 CFR 52.227-19,
 * as applicable.  Manufacturer is Rogue Wave Software, Inc., 5500
 * Flatiron Parkway, Boulder, Colorado 80301 USA.
 *
 **************************************************************************/

#ifndef _RWSTD_STRING_INCLUDED
#define _RWSTD_STRING_INCLUDED

#include <iosfwd>
#include <limits>

#include <rw/_algobase.h>
#include <rw/_iterator.h>
#include <rw/_strref.h>
#include <rw/_defs.h>
#include <rw/_error.h>


_RWSTD_NAMESPACE_BEGIN (std)


template <class _CharT, class _Traits, class _Allocator>
class basic_string: private _Allocator
{
public:

    typedef _Traits                               traits_type;
    typedef _TYPENAME traits_type::char_type      value_type;
    typedef _Allocator                            allocator_type;

private:

    typedef _RW::__string_ref<value_type, traits_type, allocator_type>
     _C_string_ref_type;

    typedef  _RWSTD_ALLOC_TYPE(allocator_type, value_type)          
        _C_value_alloc_type;
    typedef  _RWSTD_REBIND(allocator_type, _C_string_ref_type)  
        _C_ref_alloc_type;
      
public:

    typedef _TYPENAME allocator_type::size_type       size_type;
    typedef _TYPENAME allocator_type::difference_type difference_type;
    typedef _TYPENAME allocator_type::reference       reference;
    typedef _TYPENAME allocator_type::const_reference const_reference;
    typedef _TYPENAME allocator_type::pointer         pointer;
    typedef _TYPENAME allocator_type::const_pointer   const_pointer;

#ifndef _RWSTD_NO_DEBUG_ITER

    typedef _RW::__rw_debug_iter <basic_string, pointer, pointer>
        iterator;
    
    typedef _RW::__rw_debug_iter <basic_string, const_pointer, pointer>
        const_iterator;

    iterator _C_make_iter (const pointer& __ptr) {
        return iterator (*this, __ptr);
    }

    const_iterator _C_make_iter (const const_pointer& __ptr) const {
        return const_iterator (*this, __ptr);
    }

#else   // if defined (_RWSTD_NO_DEBUG_ITER)

    typedef pointer                        iterator;
    typedef const_pointer                  const_iterator;

    iterator _C_make_iter (pointer __ptr) {
        return __ptr;
    }

    const_iterator _C_make_iter (const_pointer __ptr) const {
        return __ptr;
    }

#endif   // _RWSTD_NO_DEBUG_ITER



#ifndef _RWSTD_NO_CLASS_PARTIAL_SPEC 
    typedef _STD::reverse_iterator<const_iterator> const_reverse_iterator;
    typedef _STD::reverse_iterator<iterator>       reverse_iterator;
#else
    typedef _STD::reverse_iterator<const_iterator, 
      random_access_iterator_tag, value_type, 
      const_reference, const_pointer, difference_type>
      const_reverse_iterator;
    typedef _STD::reverse_iterator<iterator, 
      random_access_iterator_tag, value_type, 
      reference, pointer, difference_type>
      reverse_iterator;
#endif

#if defined(_RWSTD_LLP64_ARCHITECTURE) && defined(_RWSTD_NO_STATIC_CONST_MEMBER_INIT)
    static const size_type npos;
#else
    _RWSTD_STATIC_CONST (size_type, npos = size_type(-1));
#endif    

    _EXPLICIT
    basic_string (const allocator_type &__alloc = allocator_type ())
        : allocator_type (__alloc), _C_data (_C_null ()) { }

    // LWG Issue #42.
    basic_string (const basic_string&);

    basic_string (const basic_string&, size_type, size_type = npos, 
                  const allocator_type& = allocator_type ());

    basic_string (const_pointer, size_type, 
                  const allocator_type& = allocator_type ());

    basic_string (const_pointer, const allocator_type& = allocator_type ());


#ifndef _RWSTD_NO_MEMBER_TEMPLATES

    // pointers to the incomplete types declared below are used
    // to disambiguate calls to template member functions
    // requires: member function and class templates
    //           and partial specialization

    template <class _InputIterator>
    basic_string (_InputIterator, _InputIterator, 
                  const allocator_type& = allocator_type ());

    basic_string (int __n, value_type __c, 
                  const allocator_type& __alloc = allocator_type ())
        : allocator_type (__alloc) {
        _C_initn (_RWSTD_STATIC_CAST (size_type, __n), __c);
    }

    basic_string (unsigned int __n, value_type __c, 
                  const allocator_type& __alloc = allocator_type ())
      : allocator_type (__alloc) {
        _C_initn (_RWSTD_STATIC_CAST (size_type, __n), __c);
    }

    basic_string (long __n, value_type __c, 
                  const allocator_type& __alloc = allocator_type ())
        : allocator_type (__alloc) {
        _C_initn (_RWSTD_STATIC_CAST (size_type, __n), __c);
    }

    basic_string (unsigned long __n, value_type __c, 
                  const allocator_type& __alloc = allocator_type ())
        : allocator_type (__alloc) {
        _C_initn (_RWSTD_STATIC_CAST (size_type, __n), __c);
    }

    basic_string (short __n, value_type __c, 
                  const allocator_type& __alloc = allocator_type ())
        : allocator_type (__alloc) {
        _C_initn (_RWSTD_STATIC_CAST (size_type, __n), __c);
    }

    basic_string (unsigned short __n, value_type __c, 
                  const allocator_type& __alloc = allocator_type ())
        : allocator_type (__alloc) {
        _C_initn (_RWSTD_STATIC_CAST (size_type, __n), __c);
    }

    basic_string (char __n, value_type __c, 
                  const allocator_type& __alloc = allocator_type ())
        : allocator_type (__alloc) {
        _C_initn (_RWSTD_STATIC_CAST (size_type, __n), __c);
    }

    basic_string (unsigned char __n, value_type __c, 
                  const allocator_type& __alloc = allocator_type ())
        : allocator_type (__alloc) {  
        _C_initn (_RWSTD_STATIC_CAST (size_type, __n), __c);  
    }


#ifndef _RWSTD_NO_NATIVE_WCHAR_T

    basic_string (wchar_t __n, value_type __c, 
                  const allocator_type& __alloc = allocator_type ())
        : allocator_type (__alloc) {
        _C_initn (_RWSTD_STATIC_CAST (size_type, __n), __c);
    }

#endif   // _RWSTD_NO_NATIVE_WCHAR_T


#ifndef _RWSTD_NO_BOOL

    basic_string (bool __n, value_type __c, 
                  const allocator_type& __alloc = allocator_type ())
        : allocator_type (__alloc) {
        _C_initn (_RWSTD_STATIC_CAST (size_type, __n), __c);
    }

#endif   // _RWSTD_NO_BOOL


#else   // if defined (_RWSTD_NO_MEMBER_TEMPLATES)

    basic_string (size_type __n, value_type __c, 
                  const allocator_type& __alloc = allocator_type ())
      : allocator_type (__alloc) {
        _C_initn (__n, __c);
    }

#endif // _RWSTD_NO_MEMBER_TEMPLATES


    basic_string (const_pointer, const_pointer, 
                  const allocator_type& = allocator_type ());

    ~basic_string () {
        _C_unlink();
    }

    basic_string& operator= (const basic_string&);
    basic_string& operator= (const_pointer __s);

    basic_string& operator= (value_type __c) {
        return replace (0, size(), 1, __c);
    }

    iterator begin () {
        _C_cow ();
        _C_pref ()->_C_set_ref_count (0);   // disable ref counting
        return _C_make_iter (_C_data);
    }

    const_iterator begin () const {
        return _C_make_iter (_C_data);
    }

    iterator end () {
        // disable reference counting
        return begin () + size ();
    }

    const_iterator end () const {
        return _C_make_iter (_C_data + size ());
    }

    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 ());
    }

    size_type size () const {
        return _C_pref()->_C_size;
    }

    size_type length () const {
        return size ();
    }

    size_type max_size () const {
        return size_type (npos) - sizeof (_C_string_ref_type) - 2U;
    }

    void resize (size_type, value_type);

    void resize (size_type __n) {
        resize (__n, value_type ()); 
    }

    size_type capacity () const {
        return _C_pref ()->capacity ();
    }

    void reserve (size_type = 0);

    void clear () {
        erase ();
    }

    bool empty () const  {
        return size () == 0;
    }

    const_reference operator[] (size_type) const;
    reference       operator[] (size_type);

    const_reference at (size_type) const;
    reference       at (size_type);

    basic_string& operator+= (const basic_string &__s) {
        return append (__s);
    }

    basic_string& operator+= (const_pointer __s) {
        return append (__s);
    }

    basic_string& operator+= (value_type __c) {
        return append (size_type (1), __c);
    }

    basic_string& append (const basic_string&, size_type, size_type);

    basic_string& append (const basic_string &__str);

    basic_string& append (const_pointer __s, size_type __n) {
        return replace (size (), 0, __s, __n, 0, __n), *this;
    }

    basic_string& append (const_pointer __s) {
        return replace (size (), 0, __s);
    }

#if     !defined (_RWSTD_NO_MEMBER_TEMPLATES)   \
     && !defined (_RWSTD_NO_CLASS_PARTIAL_SPEC)

    template<class _InputIterator>
    basic_string& append (_InputIterator __first, _InputIterator __last) {
        // resolves to append (size_type, value_type) if _InputIterator
        // is any integral type (even not an exact match, such as char)
        // the cast to int is necessary to prevent an exact match
        return append (__first, __last, _RWSTD_DISPATCH (_InputIterator));
    }

    template<class _InputIterator>
    basic_string& append (_InputIterator __first, _InputIterator __last,
                          _RWSTD_DISPATCH_INT (false)) {
        return replace (_C_make_iter (_C_data + size ()),
                        _C_make_iter (_C_data + size ()),
                        __first, __last), *this;
    }

    basic_string& append (size_type __n, value_type __c,
                          _RWSTD_DISPATCH_INT (true)) {
        // unnamed arg is used for overload resolution
        return replace (size (), 0, __n, __c);
    }

#else   // if defined (_RWSTD_NO_MEMBER_TEMPLATES)

    basic_string& append (const_pointer __first, const_pointer __last) {
        replace (size (), 0, __first, __last - __first, 0, __last - __first);
        return *this;
    }

#endif // _RWSTD_NO_MEMBER_TEMPLATES

    basic_string& append (size_type __n, value_type __c) {
        return replace (size (), 0, __n, __c);
    }

    void push_back (value_type __c) {
        append (size_type (1), __c);
    }

    basic_string& assign (const basic_string &__str) {
        return *this = __str;
    }

    basic_string& assign (const basic_string&, size_type, size_type);

    basic_string& assign (const_pointer __s, size_type __n) {
        return replace (0, size (), __s, __n, 0, __n), *this;
    }

    basic_string& assign (const_pointer __s) {
        return *this = __s;
    }


#if     !defined (_RWSTD_NO_MEMBER_TEMPLATES)   \
     && !defined (_RWSTD_NO_CLASS_PARTIAL_SPEC)

    template<class _InputIterator>
    basic_string& assign (_InputIterator __first, _InputIterator __last) {
        // resolves to assign (size_type, value_type) if _InputIterator
        // is any integral type (even not an exact match, such as char)
        // the cast to int is necessary to prevent an exact match
        return assign (__first, __last, _RWSTD_DISPATCH (_InputIterator));
    }

    template<class _InputIterator>
    basic_string& assign (_InputIterator __first, _InputIterator __last,
                          _RWSTD_DISPATCH_INT (false)) {
        // unnamed arg is used for overload resolution
        // _RWSTD_COMPILE_ASSERT (sizeof (*__first));
        return replace (_C_make_iter (_C_data),
                        _C_make_iter (_C_data + size ()), __first, __last);
    }

    basic_string& assign (size_type __n, value_type __c,
                          _RWSTD_DISPATCH_INT (true)) {
        // unnamed arg is used for overload resolution
        return replace (0, size (), __n, __c);
    }

#else   // if defined (_RWSTD_NO_MEMBER_TEMPLATES)

    basic_string& assign (const_pointer __first, const_pointer __last) {
        replace (size_type (), size (), __first,
                 __last - __first, size_type (), __last - __first);
        return *this;
    }

#endif  // _RWSTD_NO_MEMBER_TEMPLATES

    basic_string& assign (size_type __n, value_type __c) {
        return replace (0, size (), __n, __c);
    }

    basic_string& insert (size_type, const basic_string&);
    basic_string& insert (size_type, const basic_string&,
                          size_type, size_type);

    basic_string& insert (size_type __pos, const_pointer __s, size_type __n) {
        return replace (__pos, 0, __s, __n, 0, __n), *this;
    }

    basic_string& insert (size_type __pos, const_pointer __s) {
        return insert (__pos, __s, traits_type::length (__s));
    }

    // 21.3.5.4, p10
    iterator insert (iterator __pos, value_type __c) {
        _RWSTD_ASSERT_RANGE (_C_make_iter (_C_data), __pos);
        size_type __inx = __pos - _C_make_iter (_C_data);
        return insert (__inx, &__c, 1), begin () + __inx;
    }


#if     !defined (_RWSTD_NO_MEMBER_TEMPLATES)   \
     && !defined (_RWSTD_NO_CLASS_PARTIAL_SPEC)

    template<class _InputIterator>
    void insert (iterator __p,
                 _InputIterator __first, _InputIterator __last) {
        // resolves to insert (iterator, size_type, value_type)
        // if _InputIterator is any integral type (even not an exact match,
        // such as char)
        // the cast to int is necessary to avoid an exact match
        insert (__p, __first, __last, _RWSTD_DISPATCH (_InputIterator));
    }

    void insert (iterator __p, const_iterator __first, const_iterator __last) {
        iterator __begin = _C_make_iter (_C_data);
        iterator __end   = _C_make_iter (_C_data + size ());
        _RWSTD_ASSERT_RANGE (__begin, __p);
        if (__first >= __begin && __first <= __end)
            insert (__p - __begin, basic_string (__first, __last));
        else
            replace (__p, __p, __first, __last);
    }

    void insert (iterator __p, iterator __first, iterator __last) {
        insert (__p, const_iterator (__first), const_iterator (__last));
    }

    template <class _InputIterator>
    void insert (iterator __p, _InputIterator __first, _InputIterator __last,
                 _RWSTD_DISPATCH_INT (false)) {
        // unnamed arg is used for overload resolution
        // _RWSTD_COMPILE_ASSERT (sizeof (*__first));
        replace (__p, __p, __first, __last);
    }

    void insert (iterator __p, size_type __n, value_type __c,
                 _RWSTD_DISPATCH_INT (true)) {
        // unnamed arg is used for overload resolution
        replace (__p - _C_make_iter (_C_data), 0, __n, __c);
    }

#else   // if defined (_RWSTD_NO_MEMBER_TEMPLATES)

    void insert (iterator __p, const_pointer __first, const_pointer __last) {
        replace (__p - _C_make_iter (_C_data), 0, __first,
                 __last - __first, 0, __last - __first);
    }

#endif  // _RWSTD_NO_MEMBER_TEMPLATES
    

    void insert (iterator __p, size_type __n, value_type __c) {
        replace (__p - _C_make_iter (_C_data), 0, __n, __c);
    }

    basic_string& insert (size_type __pos, size_type __n, value_type __c) {
        return replace (__pos, 0, __n, __c);
    }

    basic_string& erase (size_type = 0, size_type = npos);

    iterator erase (iterator __it) { 
        return replace (__it - _C_make_iter (_C_data), 1,
                        const_pointer (0), 0, 0, 0);
    }

    iterator erase (iterator __first, iterator __last) {  
        return replace (__first - _C_make_iter (_C_data), __last - __first,
                        const_pointer (0), 0, 0, 0);
    }

private:  

    iterator replace (size_type, size_type, const_pointer,
                      size_type, size_type, size_type);

    iterator __replace_aux (size_type pos1, size_type __n1,
                            const basic_string &__str,
                            size_type pos2 = 0,
                            size_type __n2   = npos) {
        return replace (pos1, __n1, __str.c_str(), __str.size(), pos2, __n2);
    }


#ifndef _RWSTD_NO_MEMBER_TEMPLATES

    template<class _InputIterator>
    basic_string& __replace_aux (iterator       first1,
                                 iterator       last1, 
                                 _InputIterator first2,
                                 _InputIterator last2);
#endif   // _RWSTD_NO_MEMBER_TEMPLATES


  public:

    basic_string& replace (size_type pos1, size_type __n1,
                           const basic_string &__s,
                           size_type pos2, size_type __n2) {
        replace (pos1, __n1, __s.c_str (), __s.size (), pos2, __n2);
        return *this;
    }

    basic_string& replace (size_type __pos, size_type __n,
                           const basic_string &__s) {
        return replace (__pos, __n, __s, 0, __s.size ());
    }


    basic_string& replace (size_type __pos, size_type __n1, const_pointer __s,
                           size_type __n2) {
        return replace (__pos, __n1, __s, __n2, 0, __n2), *this;
    }

    basic_string& replace (size_type __pos, size_type __n, const_pointer __s) {
        return replace (__pos, __n, __s, traits_type::length (__s));
    }

    basic_string& replace (size_type, size_type, size_type, value_type);

    basic_string& replace (iterator __first, iterator __last,
                           const basic_string &__str) {
        return replace (__first - _C_make_iter (_C_data),
                        __last - __first, __str);
    }

    basic_string& replace (iterator __first, iterator __last,
                           const_pointer __s, size_type __n) {
        replace (__first - _C_make_iter (_C_data), __last - __first,
                 __s, __n, 0, __n);
        return *this;;
    }

    basic_string&
    replace (iterator __first, iterator __last, const_pointer __s) {
        return replace (__first, __last, __s, traits_type::length(__s));
    }


#if     !defined (_RWSTD_NO_MEMBER_TEMPLATES)   \
     && !defined (_RWSTD_NO_CLASS_PARTIAL_SPEC)

    template<class _InputIterator>
    basic_string& replace (iterator, iterator,
                           _InputIterator, _InputIterator,
                           _RWSTD_DISPATCH_INT (false));


    basic_string& replace (iterator __first, iterator __last,
                           size_type __n, value_type __c,
                           _RWSTD_DISPATCH_INT (true)) {
        // unnamed arg is used for overload resolution
        return replace (__first - _C_make_iter (_C_data), __last - __first,
                        __n, __c);
    }

    template<class _InputIterator>
    basic_string& replace (iterator __first1, iterator __last1,
                           _InputIterator __first2, _InputIterator __last2) {
        // resolves to replace (iterator, iterator, size_type, value_type)
        // if _InputIterator is any integral type (even not an exact match,
        // Such as char)
        // the cast to int is necessary to prevent an exact match
        return replace (__first1, __last1, __first2, __last2,
                        _RWSTD_DISPATCH (_InputIterator));
    }

#else   // if defined (_RWSTD_NO_MEMBER_TEMPLATES)

    basic_string& replace (iterator first1, iterator last1,
                           const_pointer first2, const_pointer last2) {
        return replace (first1 - _C_make_iter (_C_data), last1 - first1,
                        first2, last2 - first2, 0, last2 - first2), *this;
    }

#endif  // _RWSTD_NO_MEMBER_TEMPLATES

    basic_string& replace (iterator __first, iterator __last,
        size_type __n, value_type __c) {

        // unnamed arg is used for overload resolution
        return replace (__first - _C_make_iter (_C_data), __last - __first,
                        __n, __c);
    }

    size_type copy (pointer, size_type, size_type = 0) const;

#ifndef _RWSTD_NO_EXT_DEEP_STRING_COPY

    basic_string copy () const {
        return basic_string (data (), data () + size ());
    }

#endif   //_RWSTD_NO_EXT_DEEP_STRING_COPY

    void swap (basic_string &__s) {
        if (get_allocator () == __s.get_allocator ()) {
            pointer __temp = _C_data;
            _C_data = __s._C_data;
            __s._C_data = __temp;
        }
        else {
            basic_string __tmp = *this;
            *this = __s;
            __s = __tmp;
        }
    }

    //
    // string operations
    //
    const_pointer c_str () const {
        return _C_data;
    }

    const_pointer data () const {
        return _C_data;
    }

    allocator_type get_allocator() const {
        return *this;
    }

    // 21.3.6.1, p1
    size_type find (const basic_string &__str, size_type __pos = 0) const {
        return find (__str.c_str (), __pos, __str.size ());
    }

    // 21.3.6.1, p4
    size_type find (const_pointer, size_type, size_type) const;

    // 21.3.6.1, p5
    size_type find (const_pointer, size_type = 0) const;

    // 21.3.6.1, p7
    size_type find (value_type, size_type = 0) const;

    // 21.3.6.2, p1
    size_type rfind (const basic_string &__str, size_type __pos = npos) const {
        return rfind (__str.c_str (), __pos, __str.size ());
    }

    // 21.3.6.2, p4
    size_type rfind (const_pointer, size_type, size_type) const;

    // 21.3.6.2, p5
    size_type rfind (const_pointer __s, size_type __pos = npos) const {
        return rfind (__s, __pos, traits_type::length (__s));
    }

    // 21.3.6.2, p7
    size_type rfind (value_type, size_type = npos) const;

    // 21.3.6.3, p1
    size_type find_first_of (const basic_string &__str,
                             size_type __pos = 0) const {
        return find_first_of (__str.c_str (), __pos, __str.size ());
    }

    // 21.3.6.3, p4
    size_type find_first_of (const_pointer, size_type, size_type) const;

    // 21.3.6.3, p5
    size_type find_first_of (const_pointer, size_type = 0) const;

    // 21.3.6.3, p6
    size_type find_first_of (value_type __c, size_type __pos = 0) const {
        return find (__c, __pos);
    }

    // 21.3.6.4, p1
    size_type find_last_of (const basic_string &__str,
                            size_type __pos = npos) const {
        return find_last_of (__str.c_str (), __pos, __str.size ());
    }

    // 21.3.6.4, p4
    size_type find_last_of (const_pointer, size_type, size_type) const;

    // 21.3.6.4, p5
    size_type find_last_of (const_pointer __s, size_type __pos = npos) const {
        return find_last_of (__s, __pos, traits_type::length (__s));
    }

    // 21.3.6.4, p7
    size_type find_last_of (value_type __c, size_type __pos = npos) const {
        return rfind (__c, __pos);
    }

    // 21.3.6.5, p1
    size_type find_first_not_of (const basic_string &__str, 
                                 size_type __pos = 0) const {
        return find_first_not_of (__str.c_str (), __pos, __str.size ());
    }

    // 21.3.6.5, p4
    size_type find_first_not_of (const_pointer, size_type,
                                 size_type) const;

    // 21.3.6.5, p5
    size_type find_first_not_of (const_pointer, size_type = 0) const;

    // 21.3.6.5, p7
    size_type find_first_not_of (value_type, size_type = 0) const;

    // 21.3.6.6, p1
    size_type find_last_not_of (const basic_string &__str, 
                                size_type __pos = npos) const {
        return find_last_not_of (__str.c_str (), __pos, __str.size ());
    }

    // 21.3.6.6, p4
    size_type find_last_not_of (const_pointer, size_type, size_type) const;

    // 21.3.6.6, p6
    size_type find_last_not_of (const_pointer __s,
                                size_type __pos = npos) const {
        return find_last_not_of (__s, __pos, traits_type::length (__s));
    }

    // 21.3.6.6, p7
    size_type find_last_not_of (value_type, size_type = npos) const;
  
    // 21.3.6.7
    basic_string substr (size_type = 0, size_type = npos) const;
  
    int compare (const basic_string &__str) const;

    int compare (size_type __pos, size_type __n, const basic_string &__str) const {
        return compare (__pos, __n, __str.c_str(), __str.size());
    }

    int compare (size_type, size_type, const basic_string&, 
                size_type, size_type) const;

    int compare (const_pointer __s) const {
        return compare (0, size (), __s, traits_type::length(__s));
    }

    // LWG Issue #5.
    int compare (size_type __pos, size_type __n, const_pointer __s) const {
        return compare(__pos, __n, __s, traits_type::length (__s));
    }

    int compare (size_type, size_type, const_pointer, size_type) const;

protected:

    void _C_cow () {             // Do copy on write as necessary
        if (_C_pref ()->_C_ref_count() > 1) 
            _C_clone ();
    }

    void _C_cow (size_type __nc) {   // Do copy on write w/ new capacity
        if (_C_pref ()->_C_ref_count () > 1 || capacity () < __nc)
            _C_clone (__nc);
    }

private:

    void _C_initn (size_type, value_type);

    void _C_clone (size_type __nc = npos);

    _C_string_ref_type* _C_pref () const { 
        return _RWSTD_REINTERPRET_CAST (_C_string_ref_type*, _C_data) - 1; 
    }

    void _C_unlink ();   

    friend struct _RW::__string_ref<value_type, traits_type, allocator_type>;

#ifndef _RWSTD_NO_COLLAPSE_TEMPLATE_STATICS

    static _RW::__null_ref<_CharT, _Traits, _Allocator> __nullref;

    static pointer _C_null () {
        return __nullref.data ();
    }

#else   // if defined (_RWSTD_NO_COLLAPSE_TEMPLATE_STATICS)

    static pointer _C_null () {
        typedef _RW::__null_ref<_CharT, _Traits, _Allocator> _NullRef;

        return _RWSTD_REINTERPRET_CAST (_NullRef*, &_RW::__nullref)->data ();
    }

#endif   // _RWSTD_NO_COLLAPSE_TEMPLATE_STATICS

    _C_string_ref_type * _C_getRep (size_type, size_type);

    // for convenience
    pointer _C_allocate (size_type __cur, size_type __cap, size_type __size) {
        return _C_getRep (max (size_type (_RW::__rw_new_capacity (__cur, this)),
                               __cap), __size)->data ();
    }

    pointer _C_data;
};


typedef basic_string<char, char_traits<char>, allocator<char> > string;

#ifndef _RWSTD_NO_WCHAR_T

typedef basic_string<wchar_t, char_traits<wchar_t>, allocator<wchar_t> >
wstring;

#endif   // _RWSTD_NO_WCHAR_T


template <class _CharT, class _Traits , class _Allocator>
inline void basic_string<_CharT, _Traits, _Allocator>::_C_unlink()
{
    _RWSTD_ASSERT (0 != _C_data);

    if (data () == _C_null ())
        return;

    if (_C_pref ()->_C_ref_count () == 0 || _C_pref ()->_C_dec_ref () == 0) {
        // Required to pass same size to deallocate as allocate (see string.cc).
        // Also note that we cannot call capacity() after the destroy() call.
        size_type __size =
            capacity () + sizeof (_C_string_ref_type) / sizeof (value_type) + 2;

        // explicitly destroy POD
        _C_pref ()->_C_destroy ();
        
        _C_ref_alloc_type (*this).destroy (_C_pref ());
        _RWSTD_VALUE_ALLOC (_C_value_alloc_type,
                            deallocate (_RWSTD_REINTERPRET_CAST (pointer,
                                                                 _C_pref()),
                                        __size));
    }
}


template <class _CharT, class _Traits , class _Allocator>
inline basic_string<_CharT, _Traits, _Allocator>::
basic_string (const basic_string<_CharT, _Traits, _Allocator> &__s)
    : allocator_type (__s.get_allocator ())
{
    if (__s._C_pref()->_C_ref_count () > 0) {
        _C_data = __s._C_data;
        _C_pref()->_C_inc_ref ();
    }
    else {
        size_type __n = __s.size();
        _C_data  = _C_getRep (__n, __n)->data ();
        traits_type::copy (_C_data, __s.c_str (), __n);
    }
}


template <class _CharT, class _Traits , class _Allocator>
inline basic_string<_CharT, _Traits, _Allocator>&
basic_string<_CharT, _Traits, _Allocator>::erase (size_type __pos,
                                                  size_type __n)
{
    _RWSTD_REQUIRES (__pos <= size (),
                     (_RWSTD_ERROR_OUT_OF_RANGE,
                      _RWSTD_FUNC ("basic_string::erase(size_type, size_type)"),
                      __pos, size ()));

    const value_type __tmp =  value_type () ;
    size_type __len = size () - __pos;
    return replace (__pos, __n < __len ? __n : __len, &__tmp, 0);
}


template <class _CharT, class _Traits , class _Allocator>
inline _TYPENAME basic_string<_CharT, _Traits, _Allocator>::const_reference 
basic_string<_CharT, _Traits, _Allocator>::operator[] (size_type __pos) const
{
#ifdef _RWSTD_BOUNDS_CHECKING

    _RWSTD_REQUIRES (__pos <= size (),
                     (_RWSTD_ERROR_OUT_OF_RANGE,
                     _RWSTD_FUNC ("basic_string::operator[](size_type) const"),
                     __pos, size ()));

#endif   // _RWSTD_BOUNDS_CHECKING

    // reference counting still enabled
    return _C_data [__pos];
}


template <class _CharT, class _Traits , class _Allocator>
inline _TYPENAME basic_string<_CharT, _Traits, _Allocator>::reference
basic_string<_CharT, _Traits, _Allocator>::operator[] (size_type __pos)
{
#ifdef _RWSTD_BOUNDS_CHECKING

    // 21.3.4, p1 - behavior is undefined if __pos == size ()
    _RWSTD_REQUIRES (__pos < size (),
                     (_RWSTD_ERROR_OUT_OF_RANGE,
                     _RWSTD_FUNC ("basic_string::operator[](size_type)"),
                     __pos, size ()));

#endif   // _RWSTD_BOUNDS_CHECKING

    // prevent reference counting
    return begin ()[__pos];
}


template <class _CharT, class _Traits , class _Allocator>
inline _TYPENAME basic_string<_CharT, _Traits, _Allocator>::const_reference
basic_string<_CharT, _Traits, _Allocator>::at (size_type __pos) const
{
    _RWSTD_REQUIRES (__pos < size (),
                     (_RWSTD_ERROR_OUT_OF_RANGE,
                     _RWSTD_FUNC ("basic_string::at (size_type) const"),
                     __pos, size ()));

    // reference counting still enabled
    return _C_data [__pos];
}


template <class _CharT, class _Traits , class _Allocator>
inline _TYPENAME basic_string<_CharT, _Traits, _Allocator>::reference
basic_string<_CharT, _Traits, _Allocator>::at (size_type __pos)
{
    _RWSTD_REQUIRES (__pos < size (),
                     (_RWSTD_ERROR_OUT_OF_RANGE,
                     _RWSTD_FUNC ("basic_string::at (size_type)"),
                     __pos, size ()));

    // prevent reference counting
    return begin ()[__pos];
}


template <class _CharT, class _Traits , class _Allocator>
inline void
basic_string<_CharT, _Traits, _Allocator>::
resize (size_type __n, value_type __c)
{
    _RWSTD_REQUIRES (__n <= max_size (),
                     (_RWSTD_ERROR_LENGTH_ERROR,
                      _RWSTD_FUNC ("basic_string::resize(size_type, "
                                   "value_type)"), __n, max_size ()));

    if (__n < size())
        erase (__n, size () - __n);
    else
        replace (size (), 0, __n - size (), __c);
}

template <class _CharT, class _Traits , class _Allocator>
inline void basic_string<_CharT, _Traits, _Allocator>::
reserve (size_type __n)
{
    _RWSTD_REQUIRES (__n <= max_size (),
                     (_RWSTD_ERROR_LENGTH_ERROR,
                      _RWSTD_FUNC ("basic_string::reserve(size_type)"),
                      __n, max_size ()));

    if (__n > capacity ())
        _C_clone (__n);
}


template <class _CharT, class _Traits , class _Allocator>
inline _TYPENAME basic_string<_CharT, _Traits, _Allocator>::size_type
basic_string<_CharT, _Traits, _Allocator>::
find (const_pointer __s, size_type __pos) const
{
    _RWSTD_ASSERT (__s != 0);

    // 21.3.6.1, p1, bullet 1
    if (__pos > size ())
        return npos;

    const_pointer __where =
        _RW::rw_traits<value_type, traits_type>::find (_C_data + __pos, __s);
 
   return __where ? __where - _C_data : npos;
}


template <class _CharT, class _Traits , class _Allocator>
inline _TYPENAME basic_string<_CharT, _Traits, _Allocator>::size_type
basic_string<_CharT, _Traits, _Allocator>::
find (value_type __c, size_type __pos) const
{
    if (__pos > size())
        return npos;

    const_pointer __where =  traits_type::find (_C_data + __pos,
                                                size() - __pos, __c);
    return __where ? __where  - _C_data : npos;
}


template <class _CharT, class _Traits , class _Allocator>
inline _TYPENAME basic_string<_CharT, _Traits, _Allocator>::size_type
basic_string<_CharT, _Traits, _Allocator>::
rfind (value_type __c, size_type __pos) const
{
    if (!size ())
        return npos;

    if (__pos >= size ())
        __pos = size () - 1;   // start at the last valid position

    const_pointer __where =
        _RW::rw_traits<value_type, traits_type>::rfind (_C_data,
                                                        __c, __pos);
    return __where ? __where - _C_data : npos;
}


template <class _CharT, class _Traits , class _Allocator>
inline _TYPENAME basic_string<_CharT, _Traits, _Allocator>::size_type
basic_string<_CharT, _Traits, _Allocator>::
find_first_of (const_pointer __s, size_type __pos) const
{
    _RWSTD_ASSERT (__s != 0);

    if (__pos > size())
        return npos;

    typedef _RW::rw_traits<_CharT, _Traits> __rw_traits;

    size_type __i = __rw_traits::find_first_of (_C_data + __pos, __s) + __pos;

    return __i >= size () ? npos : __i;
}


template <class _CharT, class _Traits , class _Allocator>
inline _TYPENAME basic_string<_CharT, _Traits, _Allocator>::size_type
basic_string<_CharT, _Traits, _Allocator>::
find_first_not_of (const_pointer __s, size_type __pos) const
{
    _RWSTD_ASSERT (__s != 0);

    if (__pos > size())
        return npos;

    typedef _RW::rw_traits<_CharT, _Traits> __rw_traits;
    
    size_type __i = __rw_traits::find_first_not_of(_C_data + __pos, __s)+ __pos;

    return __i >= size () ? npos : __i;
}


template <class _CharT, class _Traits , class _Allocator>
inline _TYPENAME basic_string<_CharT, _Traits, _Allocator>::size_type
basic_string<_CharT, _Traits, _Allocator>::
find_first_not_of (value_type __c, size_type __pos) const
{
    return find_first_not_of (&__c, __pos, 1);
}


template <class _CharT, class _Traits , class _Allocator>
inline _TYPENAME basic_string<_CharT, _Traits, _Allocator>::size_type
basic_string<_CharT, _Traits, _Allocator>::
find_last_not_of (value_type __c, size_type __pos) const
{
#if 0
    // disabled to work around a bug in several compilers
    const value_type __tmp [] = { __c, value_type () };
#else
    value_type __tmp [2];
    traits_type::assign (__tmp [0], __c);
    traits_type::assign (__tmp [1], value_type ());
#endif   // 0/1

    return find_last_not_of (__tmp, __pos);
}


template <class _CharT, class _Traits, class _Allocator>
inline void
basic_string<_CharT, _Traits, _Allocator>::
_C_clone (size_type __nc /* = npos */)
{
    size_type __len = size();
    _C_string_ref_type * __temp = _C_getRep (npos == __nc ? size () : __nc,
                                             __len > __nc ? __nc : __len);
    traits_type::copy (__temp->data(), _C_data, size());
    _C_unlink ();
    _C_data = __temp->data ();
}


template <class _CharT, class _Traits, class _Allocator>
inline int
basic_string<_CharT, _Traits, _Allocator>::
compare (const basic_string &__str) const
{
    int __res = traits_type::compare (data (), __str.data (),
                                      _STD::min (size (), __str.size ()));

    if (0 == __res)
        __res = size () < __str.size () ? -1 : size () != __str.size ();

    return __res;
}


template <class _CharT, class _Traits, class _Allocator>
inline basic_string<_CharT, _Traits, _Allocator>&
basic_string<_CharT, _Traits, _Allocator>::append (const basic_string &__str)
{
    size_type __len = size () + __str.size ();
    if (__len > capacity () || _C_pref ()->_C_ref_count () > 1)
        return append (__str, 0, __str.size ());

    traits_type::copy (_C_data + size (), __str.data (), __str.size () + 1);
    _C_pref ()->_C_size = __len;
    return *this;
}


// 21.3.7.1, p1
template <class _CharT, class _Traits , class _Allocator>
inline basic_string<_CharT, _Traits, _Allocator>
operator+ (const basic_string<_CharT, _Traits, _Allocator> &__lhs, 
           const basic_string<_CharT, _Traits, _Allocator> &__rhs)
{
    typedef basic_string<_CharT, _Traits, _Allocator> string_type;

    // prevent reference counting while creating a copy of lhs
    return string_type (__lhs.data (), __lhs.data () + __lhs.size ()) += __rhs;
}


// 21.3.7.1, p2
template <class _CharT, class _Traits , class _Allocator>
inline basic_string<_CharT, _Traits, _Allocator>
operator+ (const _CharT*                                    __lhs, 
           const basic_string<_CharT, _Traits, _Allocator>& __rhs)
{
    return basic_string<_CharT, _Traits, _Allocator>(__lhs) += __rhs;
}


// 21.3.7.1, p4
template <class _CharT, class _Traits , class _Allocator>
inline basic_string<_CharT, _Traits, _Allocator>
operator+ (_CharT                                           __lhs,
           const basic_string<_CharT, _Traits, _Allocator>& __rhs)
{
    return basic_string<_CharT, _Traits, _Allocator>(1, __lhs) += __rhs;
}


// 21.3.7.1, p5
template <class _CharT, class _Traits , class _Allocator>
inline basic_string<_CharT, _Traits, _Allocator>
operator+ (const basic_string<_CharT, _Traits, _Allocator>& __lhs, 
           const _CharT*                                    __rhs)
{
    typedef basic_string<_CharT, _Traits, _Allocator> string_type;

    // prevent reference counting while creating a copy of lhs
    return string_type (__lhs.data (), __lhs.data () + __lhs.size ()) += __rhs;
}


// 21.3.7.1, p7
template <class _CharT, class _Traits , class _Allocator>
inline basic_string<_CharT, _Traits, _Allocator>
operator+ (const basic_string<_CharT, _Traits, _Allocator>& __lhs, 
           _CharT                                           __rhs)
{
    typedef basic_string<_CharT, _Traits, _Allocator> string_type;

    // prevent reference counting while creating a copy of lhs
    return string_type (__lhs.data (), __lhs.data () + __lhs.size ()) += __rhs;
}


// 21.3.7.2, p1
template <class _CharT, class _Traits , class _Allocator>
inline bool
operator== (const basic_string<_CharT, _Traits, _Allocator>& __lhs, 
            const basic_string<_CharT, _Traits, _Allocator>& __rhs)
{
    return __lhs.size () == __rhs.size () && 0 == __lhs.compare (__rhs);
}


// 21.3.7.2, p2
template <class _CharT, class _Traits , class _Allocator>
inline bool
operator== (const _CharT*                                    __lhs, 
            const basic_string<_CharT, _Traits, _Allocator>& __rhs)
{
    return 0 == __rhs.compare (__lhs);
}


// 21.3.7.2, p3
template <class _CharT, class _Traits , class _Allocator>
inline bool
operator== (const basic_string<_CharT, _Traits, _Allocator>& __lhs, 
            const _CharT*                                    __rhs)
{
    return 0 == __lhs.compare (__rhs);
}


// 21.3.7.4, p1
template <class _CharT, class _Traits , class _Allocator>
inline bool
operator< (const basic_string<_CharT, _Traits, _Allocator>& __lhs, 
           const basic_string<_CharT, _Traits, _Allocator>& __rhs)
{
    return 0 > __lhs.compare (__rhs);
}


// 21.3.7.4, p2
template <class _CharT, class _Traits , class _Allocator>
inline bool
operator< (const _CharT*                                    __lhs, 
           const basic_string<_CharT, _Traits, _Allocator>& __rhs)
{
    return 0 < __rhs.compare (__lhs);
}


// 21.3.7.4, p3
template <class _CharT, class _Traits , class _Allocator>
inline bool
operator< (const basic_string<_CharT, _Traits, _Allocator>& __lhs,
           const _CharT*                                    __rhs)
{
    return 0 > __lhs.compare (__rhs);
}


// 21.3.7.3, p1
template <class _CharT, class _Traits , class _Allocator>
inline bool
operator!= (const basic_string<_CharT, _Traits, _Allocator>& __lhs, 
            const basic_string<_CharT, _Traits, _Allocator>& __rhs)
{
    return !(__lhs == __rhs);
}


// 21.3.7.5, p1
template <class _CharT, class _Traits , class _Allocator>
inline bool
operator> (const basic_string<_CharT, _Traits, _Allocator>& __lhs, 
           const basic_string<_CharT, _Traits, _Allocator>& __rhs)
{
    return __rhs < __lhs;
}


// 21.3.7.6, p1
template <class _CharT, class _Traits , class _Allocator>
inline bool
operator<= (const basic_string<_CharT, _Traits, _Allocator>& __lhs, 
            const basic_string<_CharT, _Traits, _Allocator>& __rhs)
{
    return !(__rhs < __lhs);
}


// 21.3.7.7, p1
template <class _CharT, class _Traits , class _Allocator>
inline bool
operator>= (const basic_string<_CharT, _Traits, _Allocator>& __lhs, 
            const basic_string<_CharT, _Traits, _Allocator>& __rhs)
{
    return !(__lhs < __rhs);
}

// 21.3.7.8, p1
#ifndef _RWSTD_NO_PART_SPEC_OVERLOAD

template <class _CharT, class _Traits, class _Allocator>
inline void swap (basic_string<_CharT, _Traits, _Allocator>& __a, 
                  basic_string<_CharT, _Traits, _Allocator>& __b)
{
    __a.swap (__b);
}

#endif   // _RWSTD_NO_PART_SPEC_OVERLOAD


// 21.3.7.3, p2
template <class _CharT, class _Traits , class _Allocator>
inline bool
operator!= (const _CharT*                                    __lhs, 
            const basic_string<_CharT, _Traits, _Allocator>& __rhs)
{
    return !(__lhs == __rhs);
}


// 21.3.7.3, p3
template <class _CharT, class _Traits , class _Allocator>
inline bool
operator!= (const basic_string<_CharT, _Traits, _Allocator>& __lhs, 
            const _CharT*                                    __rhs)
{
    return !(__lhs == __rhs);
}


// 21.3.7.5, p2
template <class _CharT, class _Traits , class _Allocator>
inline bool
operator> (const _CharT*                                    __lhs, 
           const basic_string<_CharT, _Traits, _Allocator>& __rhs)
{
    return __rhs < __lhs;
}


// 21.3.7.5, p3
template <class _CharT, class _Traits , class _Allocator>
inline bool
operator> (const basic_string<_CharT, _Traits, _Allocator>& __lhs, 
           const _CharT*                                    __rhs)
{
    return __rhs < __lhs;
}


// 21.3.7.6, p2
template <class _CharT, class _Traits , class _Allocator>
inline bool
operator<= (const _CharT*                                    __lhs, 
            const basic_string<_CharT, _Traits, _Allocator>& __rhs)
{
    return !(__rhs < __lhs);
}


// 21.3.7.6, p3
template <class _CharT, class _Traits , class _Allocator>
inline bool
operator<= (const basic_string<_CharT, _Traits, _Allocator>& __lhs, 
            const _CharT*                                    __rhs)
{
    return !(__rhs < __lhs);
}


// 21.3.7.7, p2
template <class _CharT, class _Traits , class _Allocator>
inline bool
operator>= (const _CharT*                                    __lhs, 
            const basic_string<_CharT, _Traits, _Allocator>& __rhs)
{
    return !(__lhs < __rhs);
}


// 21.3.7.7, p3
template <class _CharT, class _Traits , class _Allocator>
inline bool
operator>= (const basic_string<_CharT, _Traits, _Allocator>& __lhs, 
            const _CharT*                                    __rhs)
{
    return !(__lhs < __rhs);
}


// 21.3.7.9, p3 - declared here, defined inline in <ostream>
template<class _CharT, class _Traits, class _Allocator>
inline basic_ostream<_CharT, _Traits>&
operator<< (basic_ostream<_CharT, _Traits>&,
            const basic_string<_CharT, _Traits, _Allocator>&);


_RWSTD_NAMESPACE_END   // std


_RWSTD_NAMESPACE_BEGIN (__rw)

_USING (namespace std);


#ifndef _RWSTD_NO_FUNC_PARTIAL_SPEC

// more specialized version for basic_string<>; may be further specialized
// in user code for example on a user-defined allocator

template <class _CharT, class _Traits, class _Allocator>
inline size_t
__rw_new_capacity (size_t __size,
                   const basic_string<_CharT, _Traits, _Allocator>*)
{
    size_t __cap =
        _RWSTD_STATIC_CAST (size_t, _RWSTD_INCREASE_STRING_CAPACITY(__size)
                                    /*__size * _RWSTD_STRING_CAPACITY_RATIO*/);
    return (__size += _RWSTD_MINIMUM_STRING_CAPACITY) > __cap ? __size : __cap;
}

#else   // if defined (_RWSTD_NO_FUNC_PARTIAL_SPEC)

// the following specializations of the __rw_new_capacity<> function template
// are provided for char and wchar_t; the general case is given in the <memory>

_RWSTD_SPECIALIZED_FUNCTION
inline size_t __rw_new_capacity (size_t __size, const string*)
{
    size_t __cap =
        _RWSTD_STATIC_CAST (size_t, _RWSTD_INCREASE_STRING_CAPACITY(__size)
                                    /*__size * _RWSTD_STRING_CAPACITY_RATIO*/);
    return (__size += _RWSTD_MINIMUM_STRING_CAPACITY) > __cap ? __size : __cap;
}

_RWSTD_SPECIALIZED_FUNCTION
inline size_t __rw_new_capacity (size_t __size, const wstring*)
{
    size_t __cap =
        _RWSTD_STATIC_CAST (size_t, _RWSTD_INCREASE_STRING_CAPACITY(__size)
                                    /*__size * _RWSTD_STRING_CAPACITY_RATIO*/);
    return (__size += _RWSTD_MINIMUM_STRING_CAPACITY) > __cap  ? __size : __cap;
}

#endif   // _RWSTD_NO_FUNC_PARTIAL_SPEC

_RWSTD_NAMESPACE_END   // __rw


#if _RWSTD_DEFINE_TEMPLATE (BASIC_STRING)
#  include <string.cc>
#endif


_RWSTD_NAMESPACE_BEGIN (std)

_RWSTD_INSTANTIATE_3 (class _RWSTD_EXPORT
                      basic_string<char, char_traits<char>, allocator<char> >);

#ifndef _RWSTD_NO_WCHAR_T
_RWSTD_INSTANTIATE_3 (class _RWSTD_EXPORT
                      basic_string<wchar_t, char_traits<wchar_t>,
                                   allocator<wchar_t> >);
#endif   // _RWSTD_NO_WCHAR_T

_RWSTD_NAMESPACE_END   // std


#endif   // _RWSTD_STRING_INCLUDED

