/***************************************************************************
 *
 * string.cc - definitions of the C++ Standard Library string members
 *
 * $Id: string.cc 651447 2008-04-24 22:50:34Z sebor $
 *
 ***************************************************************************
 *
 * Licensed to the Apache Software  Foundation (ASF) under one or more
 * contributor  license agreements.  See  the NOTICE  file distributed
 * with  this  work  for  additional information  regarding  copyright
 * ownership.   The ASF  licenses this  file to  you under  the Apache
 * License, Version  2.0 (the  "License"); you may  not use  this file
 * except in  compliance with the License.   You may obtain  a copy of
 * the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the  License is distributed on an  "AS IS" BASIS,
 * WITHOUT  WARRANTIES OR CONDITIONS  OF ANY  KIND, either  express or
 * implied.   See  the License  for  the  specific language  governing
 * permissions and limitations under the License.
 *
 * Copyright 1994-2008 Rogue Wave Software, Inc.
 * 
 **************************************************************************/

#ifdef _MSC_VER
   // shut up the dumb MSVC warning C4345:
   // behavior change: an object with POD type constructed with
   // an initializer of the form () will be default-initialized
#  pragma warning (push)
#  pragma warning (disable: 4345)
#endif   // _MSC_VER


_RWSTD_NAMESPACE (std) {


#ifndef _RWSTD_NO_STATIC_CONST_MEMBER_INIT
#  if !defined (_MSC_VER) || _MSC_VER > 1300 || defined (__INTEL_COMPILER)
   // MSVC 7.0 allows initializers for static const integral members
   // but out-of-line definitions cause multiply defined symbol errors
   // (see PR #26562)

#    ifndef _RWSTD_NO_STRING_NPOS_TYPE

template <class _CharT, class _Traits, class _Allocator>
const _TYPENAME basic_string<_CharT, _Traits, _Allocator>::size_type
basic_string<_CharT, _Traits, _Allocator>::
npos /* = SIZE_MAX */;

#    else   // if defined (_RWSTD_NO_STRING_NPOS_TYPE)

template <class _CharT, class _Traits, class _Allocator>
const _RWSTD_SIZE_T
basic_string<_CharT, _Traits, _Allocator>::
npos /* = SIZE_MAX */;

#    endif   // _RWSTD_NO_STRING_NPOS_TYPE
#  endif   // MSVC > 7.0
#endif   // _RWSTD_NO_STATIC_CONST_MEMBER_INIT


#ifndef _RWSTD_NO_COLLAPSE_TEMPLATE_STATICS

template <class _CharT, class _Traits, class _Allocator>
_RW::__null_ref<_CharT, _Traits, _Allocator>
basic_string<_CharT, _Traits, _Allocator>::
_C_null_ref;

#endif   // _RWSTD_NO_COLLAPSE_TEMPLATE_STATICS


template <class _CharT, class _Traits, class _Allocator>
_TYPENAME basic_string<_CharT, _Traits, _Allocator>::_C_string_ref_type*
basic_string<_CharT, _Traits, _Allocator>::
_C_get_rep (size_type __cap, size_type __len)
{
    if (__cap > max_size ()) {
        __cap = __len;

        _RWSTD_REQUIRES (__cap <= max_size (),
                         (_RWSTD_ERROR_LENGTH_ERROR,
                          _RWSTD_FUNC ("basic_string::_C_get_rep (size_type, "
                                       "size_type)"),
                          __cap, max_size ()));
    }

    _RWSTD_REQUIRES (__len <= __cap,
                     (_RWSTD_ERROR_LENGTH_ERROR,
                      _RWSTD_FUNC ("basic_string::_C_get_rep (size_type, "
                                   "size_type)"),
                      __len, __cap));

    if (!__cap) {
        _RWSTD_ASSERT (!__len);
        return _C_nullref ();
    }

    // allocate, initialize the __string_ref, and initialize each character
    _C_string_ref_type* const __ret =
        _RWSTD_STATIC_CAST (_C_string_ref_type*,
            _RWSTD_STATIC_CAST (void*,
                _RWSTD_VALUE_ALLOC (_C_value_alloc_type, *this,
                    allocate (  __cap + sizeof (_C_string_ref_type)
                              / sizeof (value_type) + 2))));

    // avoid copy construction (mutex isn't copy-constructible)
    // _C_ref_alloc_type (*this).construct (__ret, _C_string_ref_type ());
    new (__ret) _C_string_ref_type ();

    // set initial reference count, capacity, and length
    __ret->_C_init (__cap, __len);

    _RWSTD_VALUE_ALLOC (_C_value_alloc_type, *this,
                        construct (__ret->data () + __len, value_type ()));

    return __ret;
}


template <class _CharT, class _Traits, class _Allocator>
basic_string<_CharT, _Traits, _Allocator>::
basic_string (const basic_string &__s, size_type __pos, size_type __n,
              const allocator_type& __alloc /* = allocator_type () */)
    : allocator_type (__alloc)
{
    _RWSTD_REQUIRES (__pos <= __s.size (),
                     (_RWSTD_ERROR_OUT_OF_RANGE,
                      _RWSTD_FUNC ("basic_string::basic_string (const "
                                   "basic_string&, size_type, size_type)"),
                      __pos, __s.size ()));

    size_type __slen = __s.size () - __pos;
    size_type __rlen = __n < __slen ? __n : __slen; 
    size_type __nlen =  __n == npos ? 0 : __n;
    size_type __maxlen = __nlen > __rlen ? __nlen : __rlen; 
    if (__maxlen) 
        _C_data = _C_get_rep (_C_grow (size_type (), __maxlen),
                              __rlen)->data ();
    else
        _C_data = _C_get_rep (__maxlen, __rlen)->data ();

    traits_type::copy (_C_data, &__s._C_data [__pos], __rlen);
}


template <class _CharT, class _Traits, class _Allocator>
basic_string<_CharT, _Traits, _Allocator>::
basic_string (size_type __n, value_type __c, 
              const allocator_type &__alloc /* = allocator_type () */)
    : allocator_type (__alloc)
{
    _RWSTD_REQUIRES (__n <= max_size (),
                     (_RWSTD_ERROR_LENGTH_ERROR,
                      _RWSTD_FUNC ("basic_string::basic_string (size_type, "
                                   "value_type)"),
                      __n, max_size ()));

    if (__n)
        _C_data = _C_get_rep (_C_grow (size_type (), __n), __n)->data ();
    else
        _C_data = _C_nullref ()->data ();

    traits_type::assign (_C_data, __n, __c);
}


template <class _CharT, class _Traits, class _Allocator>
basic_string<_CharT, _Traits, _Allocator>::
basic_string (const_pointer __s, size_type __n,
              const allocator_type &__alloc /* = allocator_type () */)
    : allocator_type (__alloc)
{
    // extension: if `s' is 0 then `n' uninitialized elements are allocated

    _RWSTD_REQUIRES (__n <= max_size (),
                     (_RWSTD_ERROR_LENGTH_ERROR,
                      _RWSTD_FUNC ("basic_string::basic_string (const_pointer,"
                                   "size_type, const allocator_type&)"),
                      __n, max_size ()));

    _C_data = __n ?
        _C_get_rep (_C_grow (size_type (), __n), __n)->data ()
      : _C_nullref ()->data ();

    if (__s)
        traits_type::copy (_C_data, __s, __n);
}


template <class _CharT, class _Traits, class _Allocator>
basic_string<_CharT, _Traits, _Allocator>::
basic_string (const_pointer __s,
              const allocator_type &__alloc /* = allocator_type () */)
    : allocator_type (__alloc)
{     
    _RWSTD_ASSERT (__s != 0);

    const size_type __n = traits_type::length (__s);

    _C_data = __n ?
        _C_get_rep (_C_grow (size_type (), __n), __n)->data ()
      : _C_nullref ()->data ();

    traits_type::copy (_C_data, __s, __n);
}


template <class _CharT, class _Traits, class _Allocator>
basic_string<_CharT, _Traits, _Allocator>::
basic_string (const_pointer __first, const_pointer __last, 
              const allocator_type &__alloc /* = allocator_type () */)
    : allocator_type (__alloc)
{
    const size_type __n = size_type (__last - __first);

    _C_data = __n ?
        _C_get_rep (_C_grow (size_type (), __n), __n)->data ()
      : _C_nullref ()->data ();

    traits_type::copy (_C_data, __first, __n);
}


template <class _CharT, class _Traits, class _Allocator>
basic_string<_CharT, _Traits, _Allocator>&
basic_string<_CharT, _Traits, _Allocator>::
operator= (const basic_string &__rhs)
{
    if (size_type (0) < size_type (__rhs._C_pref ()->_C_get_ref ())) {
        // `rhs' has reference counting enabled
        __rhs._C_pref ()->_C_inc_ref ();
        _C_unlink (__rhs._C_data);
    }
    else if (this != &__rhs)
        // `rhs' has reference counting disabled
        replace (size_type (), size (), __rhs.data (), __rhs.size ());

    return *this;
}


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

    const size_type __rlen = _C_min (__str.size () - __pos, __n);

    return replace (size_type (), size (), __str, __pos, __rlen);
}


template <class _CharT, class _Traits, class _Allocator>
basic_string<_CharT, _Traits, _Allocator>&
basic_string<_CharT, _Traits, _Allocator>::
insert (size_type __pos1,
        const basic_string& __str, size_type __pos2, size_type __n)
{
    _RWSTD_REQUIRES (__pos1 <= size () && __pos2 <= __str.size (),
                     (_RWSTD_ERROR_OUT_OF_RANGE,
                      _RWSTD_FUNC ("basic_string::insert (size_type, const "
                                   "basic_string&, size_type, size_type)"), 
                      __pos1 > size () ? __pos1:__pos2, __str.size ()));
    
    const size_type __rlen = _C_min (__str.size () - __pos2, __n);

    _RWSTD_REQUIRES (size () <= max_size () - __rlen,
                     (_RWSTD_ERROR_LENGTH_ERROR,
                      _RWSTD_FUNC ("basic_string::insert (size_type, const "
                                   "basic_string&, size_type, size_type)"), 
                      size (), max_size () - __rlen));

    return replace (__pos1, size_type (), __str, __pos2, __n);
}


template <class _CharT, class _Traits, class _Allocator>
basic_string<_CharT, _Traits, _Allocator>&
basic_string<_CharT, _Traits, _Allocator>::
insert (size_type __pos1, const basic_string &__str)
{
    _RWSTD_REQUIRES (__pos1 <= size (),
                     (_RWSTD_ERROR_OUT_OF_RANGE,
                      _RWSTD_FUNC ("basic_string::insert (size_type, const "
                                   "basic_string&)"),
                      __pos1, size ()));
    
    _RWSTD_REQUIRES (size () <= max_size () - __str.size (),
                     (_RWSTD_ERROR_LENGTH_ERROR,
                      _RWSTD_FUNC ("basic_string::insert (size_type, "
                                   "const basic_string&)"),
                      size (), max_size () - __str.size ()));

    return replace (__pos1, size_type (), __str);
}


template <class _CharT, class _Traits, class _Allocator>
basic_string<_CharT, _Traits, _Allocator>&
basic_string<_CharT, _Traits, _Allocator>::
replace (size_type __pos1, size_type __n1, const_pointer __s, size_type __n2)
{
    const size_type __size0 = size ();

    if (npos == __n2)
        __n2 = traits_type::length (__s);

    _RWSTD_REQUIRES (__pos1 <= __size0,
                     (_RWSTD_ERROR_OUT_OF_RANGE, 
                     _RWSTD_FUNC ("basic_string::replace (size_type, size_type"
                                  ", const_pointer, size_type)"), 
                      __pos1, __size0 > __n2 ? __size0 : __n2));

    // number of characters to delete
    const size_type __xlen = _C_min (__n1, __size0 - __pos1);

    _RWSTD_REQUIRES (__n2 <= max_size (),
                     (_RWSTD_ERROR_LENGTH_ERROR,
                     _RWSTD_FUNC ("basic_string::replace (size_type, size_type"
                                  ", const_pointer, size_type)"), 
                     __n2, max_size ()));

    _RWSTD_REQUIRES (__size0 - __xlen <= max_size () - __n2,
                     (_RWSTD_ERROR_LENGTH_ERROR,
                     _RWSTD_FUNC ("basic_string::replace (size_type, size_type"
                                  ", const_pointer, size_type)"), 
                      __size0 - __xlen, max_size () - __n2));

    // compute the resulting string size
    const size_type __size1 = __size0 - __xlen + __n2;

    if (__size1) {

        // compute the length of the bit at the end
        const size_type __rem = __size0 - __xlen - __pos1;

        // check for shared representation, insufficient capacity,
        // and overlapping regions
        if (   size_type (1) < size_type (_C_pref ()->_C_get_ref ())
            || capacity () < __size1
            || __s >= data () && __s < data () + __size0) {

            // Need to allocate a new reference.
            const size_type __cap = _C_grow (__size0, __size1);

            const pointer __data = _C_get_rep (__cap, __size1)->data ();

            traits_type::copy (__data, _C_data, __pos1);

            traits_type::copy (__data + __pos1, __s, __n2);

            traits_type::copy (__data + __pos1 + __n2,
                               _C_data + __pos1 + __n1, __rem);

            _C_unlink (__data);
        }
        else {
            // current reference has enough space

            const pointer __beg = _C_data + __pos1;

            traits_type::move (__beg + __n2, __beg + __n1, __rem);

            traits_type::copy (__beg, __s, __n2);

            traits_type::assign (_C_data [__size1], value_type ());

            _C_pref ()->_C_size._C_size = __size1;
        }
    }
    else {
        // special case a substitution that leaves the string empty.
        clear ();
    }

    return *this;
}


template <class _CharT, class _Traits, class _Allocator>
basic_string<_CharT, _Traits, _Allocator>&
basic_string<_CharT, _Traits, _Allocator>::
replace (size_type __pos, size_type __len, size_type __count, value_type __val)
{
    // replaces `len' characters at position `pos'
    // with `count' copies of the character `val'

    const size_type __size0 = size ();

    _RWSTD_REQUIRES (__pos <= __size0,
                     (_RWSTD_ERROR_OUT_OF_RANGE, 
                      _RWSTD_FUNC ("basic_string::replace (size_type, "
                                   "size_type, size_type, value_type)"),
                      __pos, __size0));

    const size_type __xlen = _C_min (__size0 - __pos, __len);

    _RWSTD_REQUIRES (__size0 - __xlen <= max_size () - __count,
                     (_RWSTD_ERROR_LENGTH_ERROR,
                      _RWSTD_FUNC ("basic_string::replace (size_type, "
                                   "size_type, size_type, value_type)"), 
                      __size0 - __xlen, max_size () - __count));

    // compute the resulting string size
    const size_type __size1 = __size0 - __xlen + __count;

    if (__size1) {

        // compute the length of the bit at the end
        const size_type __rem = __size0 - __xlen - __pos;

        // check for shared representation, insufficient capacity
        if (   capacity () < __size1
            || size_type (1) < size_type (_C_pref ()->_C_get_ref ())) {

            // need to allocate a new reference
            const size_type __cap = _C_grow (__size0, __size1);

            const pointer __data = _C_get_rep (__cap, __size1)->data ();

            traits_type::copy (__data, _C_data, __pos);

            traits_type::assign (__data + __pos, __count, __val);

            traits_type::copy (__data + (__pos + __count),
                               _C_data + (__pos + __len), __rem);

            _C_unlink (__data);
        }
        else {
            // current reference is not shared and has enough space

            const pointer __beg = _C_data + __pos;

            traits_type::move (__beg + __count, __beg + __len, __rem);

            traits_type::assign (__beg, __count, __val);

            // append the terminating NUL character
            traits_type::assign (_C_data [__size1], value_type ());

            _C_pref ()->_C_size._C_size = __size1;
        }
    }
    else {
        // special case a substitution that leaves the string empty.
        clear ();
    }

    return *this;
}


#ifndef _RWSTD_NO_MEMBER_TEMPLATES

#  ifdef _RWSTD_NO_STRING_OUTLINED_MEMBER_TEMPLATES

_EXPORT
template <class _CharT, class _Traits, class _Alloc,
          class _StringIter, class _InputIter>
_STD::basic_string<_CharT, _Traits, _Alloc>& 
__rw_replace (_STD::basic_string<_CharT, _Traits, _Alloc> &__s, 
              _StringIter __first1, _StringIter __last1,
              _InputIter __first2, _InputIter __last2) {

    typedef _Traits                               traits_type;
    typedef _TYPENAME traits_type::char_type      value_type;
    typedef _Alloc                                allocator_type;
    typedef _TYPENAME allocator_type::size_type   size_type;

    typedef _STD::basic_string<_CharT, _Traits, _Alloc> _C_string_type;

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


#  else   // !defined (_RWSTD_NO_STRING_OUTLINED_MEMBER_TEMPLATES)

template<class _CharT, class _Traits, class _Allocator>
template<class _InputIter>
basic_string<_CharT, _Traits, _Allocator>& 
basic_string<_CharT, _Traits, _Allocator>::
replace (iterator __first1, iterator __last1,
         _InputIter __first2, _InputIter __last2, void*)
{
    typedef basic_string _C_string_type;

    basic_string &__s = *this;

#  endif   // _RWSTD_NO_STRING_OUTLINED_MEMBER_TEMPLATES

    _RWSTD_ASSERT_RANGE (__first1,
                         __s._C_make_iter (__s._C_data + __s.size ()));
    _RWSTD_ASSERT_RANGE (__first1, __last1);
    _RWSTD_ASSERT_RANGE (__first2, __last2);

    if (__first2 == __last2) {
        if (__first1 == __last1)
            return __s;

        const size_type __pos = __s._C_off (__first1);
        const size_type __n = __s._C_off (__first1, __last1);
        return __s.replace (__pos, __n, size_type (), value_type ());
    }

     // use a (probably) faster algorithm if possible
    if (_STD::__is_bidirectional_iterator (_RWSTD_ITERATOR_CATEGORY(_InputIter,
                                                                    __last2)))
        return __s.__replace_aux (__first1, __last1, __first2, __last2);

    _C_string_type __s3;
    _TYPENAME _C_string_type::iterator __first3 = __s3.begin ();
    
    for ( ; !(__first2 == __last2); ++__first2, ++__first3) {

        const size_type __off = __s3._C_off (__first3);

        _RWSTD_REQUIRES (__off <= __s3.max_size (),
                         (_RWSTD_ERROR_LENGTH_ERROR,
                          _RWSTD_FUNC ("basic_string::replace (iterator, "
                                       "iterator, InputIterator, "
                                       "InputIterator)"),
                          __s3._C_off (__first3), __s3.max_size ()));
         
        // extend the string if necessary
        if (__s3.end () == __first3) {
            // compute the size of new buffer
            const size_type __cap = __s3._C_grow (__s3.size (), size_type ());

            // allocate a new buffer
            _C_string_ref_type *__tmp = __s3._C_get_rep (__cap, __cap);

            // copy data from old to new, leaving a hole for additions
            traits_type::copy (__tmp->data (), __s3._C_data, __off);
            __s3._C_unlink (__tmp->data ());
            __first3 = __s3._C_make_iter (__s3._C_data + __off);
        }

        // copy data over
        traits_type::assign (*__first3, *__first2);
    }

    const size_type __size = __s3._C_off (__first3);
    traits_type::assign (__s3._C_data [__size], value_type ());
    __s3._C_pref ()->_C_size._C_size = __size;

    return __s.__replace_aux (__first1, __last1, __s3.begin (), __s3.end ());
}

// Special function for random access and bi-directional iterators
// Avoids the possibility of multiple allocations
// We still have to copy characters over one at a time.

#  ifdef _RWSTD_NO_STRING_OUTLINED_MEMBER_TEMPLATES

_EXPORT
template <class _CharT, class _Traits, class _Alloc,
          class _StringIter, class _InputIter>
_STD::basic_string<_CharT, _Traits, _Alloc>& 
__rw_replace_aux (_STD::basic_string<_CharT, _Traits, _Alloc> &__s, 
                  _StringIter __first1, _StringIter __last1,
                  _InputIter __first2, _InputIter __last2)
{
    typedef _Traits                                   traits_type;
    typedef _TYPENAME traits_type::char_type          value_type;
    typedef _Alloc                                    allocator_type;
    typedef _TYPENAME allocator_type::size_type       size_type;
    typedef _TYPENAME allocator_type::difference_type difference_type;
    typedef _TYPENAME allocator_type::pointer         pointer;
    typedef _TYPENAME allocator_type::const_pointer   const_pointer;
    typedef _TYPENAME allocator_type::const_reference const_reference;

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

#  else   // if !defined (_RWSTD_NO_STRING_OUTLINED_MEMBER_TEMPLATES)

template<class _CharT, class _Traits, class _Allocator>
template<class _InputIter>
basic_string<_CharT, _Traits, _Allocator>& 
basic_string<_CharT, _Traits, _Allocator>::
__replace_aux (iterator __first1, iterator __last1, 
               _InputIter __first2, _InputIter __last2)
{
    basic_string &__s = *this;

#  endif  // _RWSTD_NO_STRING_OUTLINED_MEMBER_TEMPLATES

    _RWSTD_ASSERT_RANGE (__first1, __s._C_make_iter (__s._C_data 
                                                     + __s.size ()));
    _RWSTD_ASSERT_RANGE (__first1, __last1);
    _RWSTD_ASSERT_RANGE (__first2, __last2);

    const size_type  __n2 = _DISTANCE (__first2, __last2, size_type);
    const size_type  __n  = __s._C_off (__first1, __last1);
    const size_type __pos = __s._C_off (__first1);
    const size_type __ssize = __s.size ();

    _RWSTD_REQUIRES (__pos <= __ssize,
                     (_RWSTD_ERROR_OUT_OF_RANGE,
                      _RWSTD_FUNC ("basic_string::__replace_aux (iterator, "
                                   "iterator, InputIterator, InputIterator)"),
                      __pos, __ssize));

    size_type __slen = __ssize - __pos;
    size_type __xlen = __n < __slen ? __n : __slen; 

    _RWSTD_REQUIRES (__ssize - __xlen <= __s.max_size () - __n2,
                     (_RWSTD_ERROR_LENGTH_ERROR, 
                      _RWSTD_FUNC ("basic_string::__replace_aux (iterator, "
                                   "iterator, InputIterator, InputIterator)"),
                      __ssize - __xlen, __s.max_size () - __n2));

    size_type __len = __ssize - __xlen + __n2;  // Final string length.

    if (!__len) {
        // Special case a substitution that leaves the string empty.
        __s._C_unlink (__s._C_nullref ()->data ());
    }
    else {
        size_type __d = 0;
        // length of bit at the end
        size_type __rem = __ssize - __xlen - __pos;
        // Check for shared representation, insufficient capacity
        if (   __s.capacity () < __len
            || size_type (1) < size_type (__s._C_pref ()->_C_get_ref ()))
        {
            // Need to allocate a new reference.
            const size_type __cap = __s._C_grow (__ssize, __len);

            _C_string_ref_type * __temp = __s._C_get_rep (__cap, __len);
            if (__pos)
                traits_type::copy (__temp->data (), __s._C_data, __pos);
            for (__d = 0; __d < __n2; __d++)
                traits_type::assign (*(__temp->data ()+__pos + __d),
                                     *__first2++);
            if (__rem)
                traits_type::copy (__temp->data () + __pos + __n2,
                                   __s._C_data + __pos + __n, __rem);
            __s._C_unlink (__temp->data ());
        }
        else {
            // Current reference has enough room.
            if (__rem)
                traits_type::move (__s._C_data + __pos + __n2,
                                   __s._C_data + __pos + __n, 
                                   __rem);

            for (__d = 0; __d < __n2; __d++)
                traits_type::assign (*(__s._C_data + __pos + __d),
                                     *__first2++);

            __s._C_pref ()->_C_size._C_size = __len;
            traits_type::assign (__s._C_data [__len], value_type ());
        }
    }
    return __s;
}

#endif   // _RWSTD_NO_MEMBER_TEMPLATES


template <class _CharT, class _Traits, class _Allocator>
_TYPENAME basic_string<_CharT, _Traits, _Allocator>::size_type
basic_string<_CharT, _Traits, _Allocator>::
copy (pointer __s, size_type __n, size_type __pos) const
{
    _RWSTD_REQUIRES (__pos <= size (),
                     (_RWSTD_ERROR_OUT_OF_RANGE, 
                      _RWSTD_FUNC ("basic_string::copy (pointer, size_type, "
                                   "size_type)"),
                      __pos, size ()));

    const size_type __rlen = _C_min (size () - __pos, __n);

    traits_type::copy (__s, _C_data + __pos, __rlen);

    return __rlen;
}


template <class _CharT, class _Traits, class _Allocator>
_TYPENAME basic_string<_CharT, _Traits, _Allocator>::size_type
basic_string<_CharT, _Traits, _Allocator>::
find (const_pointer __seq, size_type __off, size_type __len) const
{
    const size_type __size = size ();

    if (__size < __off)
        return npos;

    _RWSTD_ASSERT (__seq != 0 || __len == 0);

    const const_pointer __end     = _C_data + __size;
    const const_pointer __seq_end = __seq + __len;

    // `first' is set to point to the first occurrence of the first
    // element of the sought sequence in the controlling sequence
    // if one exists, otherwise to 0
    const_pointer __first = const_pointer ();

    for (const_pointer __next = _C_data + __off; ; __next = __first) {

        // compute the legth of the rest of the controlling sequene
        // and break out when it's shorter than the sought sequence
        const size_type __ext = size_type (__end - __next);

        if (__ext < __len)
            break;

        __first = const_pointer ();

        for (const_pointer __n = __next, __s = __seq; ; ++__n, ++__s) {

            if (__seq_end == __s)
                return size_type (__next - _C_data);

            if (traits_type::eq (*__n, *__s)) {
                if (__next != __first && traits_type::eq (*__n, *__seq))
                    __first = __n + 1;
            }
            else {
                if (const_pointer () == __first) {
                    // look for the first occurrence of the first element
                    // of the sought sequence in the rest of the cotrolling
                    // sequence
                    __first = traits_type::find (__next + 1, __ext - 1, *__seq);

                    if (const_pointer () == __first)
                        return npos;
                }
                break;
            }
        }
    }

    return npos;
}


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

    if (size () < __n)
        return npos;
    
    size_type __slen = size () - __n;
    size_type __xpos_start = __slen < __pos ? __slen : __pos; 

    for (size_type __xpos = __xpos_start + 1; __xpos != 0 ; __xpos--) {
        if (!traits_type::compare (_C_data + __xpos - 1, __s, __n))
            return __xpos - 1;
    }

    return npos;
}


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

    for (size_type __xpos = __pos; __xpos < size () ; __xpos++) {
        for (size_type __i = 0; __i < __n ; __i++)
            if (traits_type::eq (_C_data [__xpos], __s [__i]))
                return __xpos;
    }

    return npos;
}


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

    if (size ()) {
        size_type __slen = size () - 1;
        size_type __xpos_start = __pos < __slen ? __pos : __slen; 
        for (size_type __xpos = __xpos_start+1; __xpos != 0 ; __xpos--) {
            for (size_type __i = 0; __i < __n ; __i++)
                if (traits_type::eq (_C_data [__xpos - 1], __s [__i]))
                    return __xpos - 1;
        }
    }

    return npos;
}


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

    for (size_type __xpos = __pos; __xpos < size () ; __xpos++) {
        bool __found = false;
        for (size_type __i = 0; __i < __n ; __i++) {
            if (traits_type::eq (_C_data [__xpos], __s [__i])) {
                __found = true;
                break;
            }
        }
        if (!__found)
            return __xpos;
    }

    return npos;
}


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

    if (size ()) {
        size_type __slen = size () - 1;
        size_type __xpos_start = __pos < __slen ? __pos : __slen; 
        for (size_type __xpos = __xpos_start + 1; __xpos != 0 ; __xpos--) {
            bool __found = false;
            for (size_type __i = 0; __i < __n ; __i++) {
                if (traits_type::eq (_C_data [__xpos - 1], __s [__i])) {
                    __found = true;
                    break;
                }
            }
            if (!__found)
                return __xpos - 1;
        }
    }

    return npos;
}


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

    size_type __slen = size () - __pos;
    size_type __rlen = __n < __slen ? __n : __slen;
    return basic_string (_C_data + __pos, __rlen);
}


template <class _CharT, class _Traits, class _Allocator>
int basic_string<_CharT, _Traits, _Allocator>::
compare (size_type __pos1, size_type __n1, 
         const basic_string& __str, size_type __pos2, size_type __n2) const
{
    _RWSTD_REQUIRES (__pos2 <= __str.size (),
                     (_RWSTD_ERROR_OUT_OF_RANGE, 
                      _RWSTD_FUNC ("basic_string::compare (size_type, "
                                   "size_type, const basic_string&, "
                                   "size_type, size_type) const"),
                      __pos2, __str.size ()));

    if (__str.size () - __pos2 < __n2)
        __n2 = __str.size () - __pos2;

    return compare (__pos1, __n1, __str.c_str () + __pos2, __n2);
}


template <class _CharT, class _Traits, class _Allocator>
int basic_string<_CharT, _Traits, _Allocator>::
compare (size_type __pos, size_type __n1,
         const_pointer __s, size_type __n2) const
{
    _RWSTD_REQUIRES (__pos <= size (),
                     (_RWSTD_ERROR_OUT_OF_RANGE, 
                      _RWSTD_FUNC ("basic_string::compare (size_type, "
                                   "size_type, const const_pointer, "
                                   "size_type) const"),
                      __pos, size ()));

    if (size () - __pos < __n1)
        __n1 = size () - __pos;
    size_type __rlen = __n1 < __n2 ? __n1 : __n2; 
    int __res = traits_type::compare (_C_data + __pos, __s, __rlen);

    if (__res == 0)
        __res = (__n1 < __n2) ? -1 : (__n1 != __n2);

    return __res;
}


}   // namespace std


#ifdef _MSC_VER
#  pragma warning (pop)
#endif   // _MSC_VER
