// Debugging string implementation -*- C++ -*-

// Copyright (C) 2003-2023 Free Software Foundation, Inc.
//
// This file is part of the GNU ISO C++ Library.  This library is free
// software; you can redistribute it and/or modify it under the
// terms of the GNU General Public License as published by the
// Free Software Foundation; either version 3, or (at your option)
// any later version.

// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// Under Section 7 of GPL version 3, you are granted additional
// permissions described in the GCC Runtime Library Exception, version
// 3.1, as published by the Free Software Foundation.

// You should have received a copy of the GNU General Public License and
// a copy of the GCC Runtime Library Exception along with this program;
// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
// <http://www.gnu.org/licenses/>.

/** @file debug/string
 *  This file is a GNU debug extension to the Standard C++ Library.
 */

#ifndef _GLIBCXX_DEBUG_STRING
#define _GLIBCXX_DEBUG_STRING 1

#pragma GCC system_header

#include <string>
#include <debug/safe_sequence.h>
#include <debug/safe_container.h>
#include <debug/safe_iterator.h>

#define _GLIBCXX_DEBUG_VERIFY_STR_COND_AT(_Cond,_File,_Line,_Func)	\
  if (! (_Cond))							\
    __gnu_debug::_Error_formatter::_S_at(_File, _Line, _Func)		\
      ._M_message(#_Cond)._M_error()

#if _GLIBCXX_USE_CXX11_ABI && __cplusplus >= 201103
# define _GLIBCXX_INSERT_RETURNS_ITERATOR 1
# define _GLIBCXX_INSERT_RETURNS_ITERATOR_ONLY(expr) expr
#else
# define _GLIBCXX_INSERT_RETURNS_ITERATOR 0
# define _GLIBCXX_INSERT_RETURNS_ITERATOR_ONLY(expr)
#endif

#ifdef _GLIBCXX_DEBUG_PEDANTIC
# if __cplusplus < 201103L
#  define __glibcxx_check_string(_String)			\
  _GLIBCXX_DEBUG_VERIFY_STR_COND_AT(_String != 0,		\
				    __FILE__, __LINE__,		\
				    __PRETTY_FUNCTION__);
#  define __glibcxx_check_string_len(_String,_Len)		\
  _GLIBCXX_DEBUG_VERIFY_STR_COND_AT(_String != 0 || _Len == 0,	\
				    __FILE__, __LINE__,		\
				    __PRETTY_FUNCTION__);
# else
#  define __glibcxx_check_string(_String)			\
  _GLIBCXX_DEBUG_VERIFY_STR_COND_AT(_String != nullptr,		\
				    __FILE__, __LINE__,		\
				    __PRETTY_FUNCTION__);
#  define __glibcxx_check_string_len(_String,_Len)		\
  _GLIBCXX_DEBUG_VERIFY_STR_COND_AT(_String != nullptr || _Len == 0,	\
				    __FILE__, __LINE__,		\
				    __PRETTY_FUNCTION__);
# endif
#else
# define __glibcxx_check_string(_String)
# define __glibcxx_check_string_len(_String,_Len)
#endif

namespace __gnu_debug
{
  /** Checks that __s is non-NULL or __n == 0, and then returns __s. */
  template<typename _CharT, typename _Integer>
    inline const _CharT*
    __check_string(const _CharT* __s,
		   _Integer __n __attribute__((__unused__)),
		   const char* __file __attribute__((__unused__)),
		   unsigned int __line __attribute__((__unused__)),
		   const char* __function __attribute__((__unused__)))
    {
#ifdef _GLIBCXX_DEBUG_PEDANTIC
# if __cplusplus < 201103L
      _GLIBCXX_DEBUG_VERIFY_STR_COND_AT(__s != 0 || __n == 0,
					__file, __line, __function);
# else
      _GLIBCXX_DEBUG_VERIFY_STR_COND_AT(__s != nullptr || __n == 0,
					__file, __line, __function);
# endif
#endif
      return __s;
    }

  /** Checks that __s is non-NULL and then returns __s. */
  template<typename _CharT>
    inline const _CharT*
    __check_string(const _CharT* __s,
		   const char* __file __attribute__((__unused__)),
		   unsigned int __line __attribute__((__unused__)),
		   const char* __function __attribute__((__unused__)))
    {
#ifdef _GLIBCXX_DEBUG_PEDANTIC
# if __cplusplus < 201103L
      _GLIBCXX_DEBUG_VERIFY_STR_COND_AT(__s != 0,
					__file, __line, __function);
# else
      _GLIBCXX_DEBUG_VERIFY_STR_COND_AT(__s != nullptr,
					__file, __line, __function);
# endif
#endif
      return __s;
    }

#define __glibcxx_check_string_n_constructor(_Str, _Size) \
  __check_string(_Str, _Size, __FILE__, __LINE__, __PRETTY_FUNCTION__)

#define __glibcxx_check_string_constructor(_Str) \
  __check_string(_Str, __FILE__, __LINE__, __PRETTY_FUNCTION__)

  /// Class std::basic_string with safety/checking/debug instrumentation.
  template<typename _CharT, typename _Traits = std::char_traits<_CharT>,
	   typename _Allocator = std::allocator<_CharT> >
    class basic_string
      : public __gnu_debug::_Safe_container<
	  basic_string<_CharT, _Traits, _Allocator>,
	  _Allocator, _Safe_sequence, bool(_GLIBCXX_USE_CXX11_ABI)>,
	public std::basic_string<_CharT, _Traits, _Allocator>
    {
      typedef std::basic_string<_CharT, _Traits, _Allocator>	_Base;
      typedef __gnu_debug::_Safe_container<
	basic_string, _Allocator, _Safe_sequence, bool(_GLIBCXX_USE_CXX11_ABI)>
      _Safe;

      template<typename _ItT, typename _SeqT, typename _CatT>
	friend class ::__gnu_debug::_Safe_iterator;

      // type used for positions in insert, erase etc.
      typedef __gnu_debug::_Safe_iterator<
	typename _Base::__const_iterator, basic_string> __const_iterator;

    public:
      // types:
      typedef _Traits					traits_type;
      typedef typename _Traits::char_type		value_type;
      typedef _Allocator				allocator_type;
      typedef typename _Base::size_type			size_type;
      typedef typename _Base::difference_type		difference_type;
      typedef typename _Base::reference			reference;
      typedef typename _Base::const_reference		const_reference;
      typedef typename _Base::pointer			pointer;
      typedef typename _Base::const_pointer		const_pointer;

      typedef __gnu_debug::_Safe_iterator<
	typename _Base::iterator, basic_string>		iterator;
      typedef __gnu_debug::_Safe_iterator<
	typename _Base::const_iterator, basic_string>	const_iterator;

      typedef std::reverse_iterator<iterator>		reverse_iterator;
      typedef std::reverse_iterator<const_iterator>	const_reverse_iterator;

      using _Base::npos;

      // 21.3.1 construct/copy/destroy:

      explicit
      basic_string(const _Allocator& __a) _GLIBCXX_NOEXCEPT
      : _Base(__a) { }

#if __cplusplus < 201103L
      basic_string() : _Base() { }

      basic_string(const basic_string& __str)
      : _Base(__str) { }

      ~basic_string() { }
#else
      basic_string() = default;
      basic_string(const basic_string&) = default;
      basic_string(basic_string&&) = default;

      basic_string(std::initializer_list<_CharT> __l,
		   const _Allocator& __a = _Allocator())
      : _Base(__l, __a)
      { }

      basic_string(const basic_string& __s, const _Allocator& __a)
      : _Base(__s, __a) { }

      basic_string(basic_string&& __s, const _Allocator& __a)
      noexcept(
	std::is_nothrow_constructible<_Base, _Base, const _Allocator&>::value )
      : _Safe(std::move(__s), __a),
	_Base(std::move(__s), __a)
      { }

      ~basic_string() = default;

      // Provides conversion from a normal-mode string to a debug-mode string
      basic_string(_Base&& __base) noexcept
      : _Base(std::move(__base)) { }
#endif // C++11

      // Provides conversion from a normal-mode string to a debug-mode string
      basic_string(const _Base& __base)
      : _Base(__base) { }

      // _GLIBCXX_RESOLVE_LIB_DEFECTS
      // 42. string ctors specify wrong default allocator
      basic_string(const basic_string& __str, size_type __pos,
		   size_type __n = _Base::npos,
		   const _Allocator& __a = _Allocator())
      : _Base(__str, __pos, __n, __a) { }

      basic_string(const _CharT* __s, size_type __n,
		   const _Allocator& __a = _Allocator())
      : _Base(__glibcxx_check_string_n_constructor(__s, __n), __n, __a) { }

      basic_string(const _CharT* __s, const _Allocator& __a = _Allocator())
      : _Base(__glibcxx_check_string_constructor(__s), __a)
      { }

      basic_string(size_type __n, _CharT __c,
		   const _Allocator& __a = _Allocator())
      : _Base(__n, __c, __a) { }

      template<typename _InputIterator>
	basic_string(_InputIterator __begin, _InputIterator __end,
		     const _Allocator& __a = _Allocator())
	: _Base(__gnu_debug::__base(
		  __glibcxx_check_valid_constructor_range(__begin, __end)),
		__gnu_debug::__base(__end), __a) { }

#if __cplusplus >= 201103L
      basic_string&
      operator=(const basic_string&) = default;

      basic_string&
      operator=(basic_string&&) = default;
#endif

      basic_string&
      operator=(const _CharT* __s)
      {
	__glibcxx_check_string(__s);
	_Base::operator=(__s);
	this->_M_invalidate_all();
	return *this;
      }

      basic_string&
      operator=(_CharT __c)
      {
	_Base::operator=(__c);
	this->_M_invalidate_all();
	return *this;
      }

#if __cplusplus >= 201103L
      basic_string&
      operator=(std::initializer_list<_CharT> __l)
      {
	_Base::operator=(__l);
	this->_M_invalidate_all();
	return *this;
      }
#endif // C++11

      // 21.3.2 iterators:
      iterator
      begin() // _GLIBCXX_NOEXCEPT
      { return iterator(_Base::begin(), this); }

      const_iterator
      begin() const _GLIBCXX_NOEXCEPT
      { return const_iterator(_Base::begin(), this); }

      iterator
      end() // _GLIBCXX_NOEXCEPT
      { return iterator(_Base::end(), this); }

      const_iterator
      end() const _GLIBCXX_NOEXCEPT
      { return const_iterator(_Base::end(), this); }

      reverse_iterator
      rbegin() // _GLIBCXX_NOEXCEPT
      { return reverse_iterator(end()); }

      const_reverse_iterator
      rbegin() const _GLIBCXX_NOEXCEPT
      { return const_reverse_iterator(end()); }

      reverse_iterator
      rend() // _GLIBCXX_NOEXCEPT
      { return reverse_iterator(begin()); }

      const_reverse_iterator
      rend() const _GLIBCXX_NOEXCEPT
      { return const_reverse_iterator(begin()); }

#if __cplusplus >= 201103L
      const_iterator
      cbegin() const noexcept
      { return const_iterator(_Base::begin(), this); }

      const_iterator
      cend() const noexcept
      { return const_iterator(_Base::end(), this); }

      const_reverse_iterator
      crbegin() const noexcept
      { return const_reverse_iterator(end()); }

      const_reverse_iterator
      crend() const noexcept
      { return const_reverse_iterator(begin()); }
#endif

      // 21.3.3 capacity:
      using _Base::size;
      using _Base::length;
      using _Base::max_size;

      void
      resize(size_type __n, _CharT __c)
      {
	_Base::resize(__n, __c);
	this->_M_invalidate_all();
      }

      void
      resize(size_type __n)
      { this->resize(__n, _CharT()); }

#if __cplusplus >= 201103L
      void
      shrink_to_fit() noexcept
      {
	if (capacity() > size())
	  {
	    __try
	      {
		reserve(0);
		this->_M_invalidate_all();
	      }
	    __catch(...)
	      { }
	  }
      }
#endif

      using _Base::capacity;
      using _Base::reserve;

      void
      clear() // _GLIBCXX_NOEXCEPT
      {
	_Base::clear();
	this->_M_invalidate_all();
      }

      using _Base::empty;

      // 21.3.4 element access:
      const_reference
      operator[](size_type __pos) const _GLIBCXX_NOEXCEPT
      {
	_GLIBCXX_DEBUG_VERIFY(__pos <= this->size(),
			      _M_message(__gnu_debug::__msg_subscript_oob)
			      ._M_sequence(*this, "this")
			      ._M_integer(__pos, "__pos")
			      ._M_integer(this->size(), "size"));
	return _Base::operator[](__pos);
      }

      reference
      operator[](size_type __pos) // _GLIBCXX_NOEXCEPT
      {
#if __cplusplus < 201103L && defined(_GLIBCXX_DEBUG_PEDANTIC)
	__glibcxx_check_subscript(__pos);
#else
	// as an extension v3 allows s[s.size()] when s is non-const.
	_GLIBCXX_DEBUG_VERIFY(__pos <= this->size(),
			      _M_message(__gnu_debug::__msg_subscript_oob)
			      ._M_sequence(*this, "this")
			      ._M_integer(__pos, "__pos")
			      ._M_integer(this->size(), "size"));
#endif
	return _Base::operator[](__pos);
      }

      using _Base::at;

#if __cplusplus >= 201103L
      using _Base::front;
      using _Base::back;
#endif

      // 21.3.5 modifiers:
      basic_string&
      operator+=(const basic_string& __str)
      {
	_Base::operator+=(__str);
	this->_M_invalidate_all();
	return *this;
      }

      basic_string&
      operator+=(const _CharT* __s)
      {
	__glibcxx_check_string(__s);
	_Base::operator+=(__s);
	this->_M_invalidate_all();
	return *this;
      }

      basic_string&
      operator+=(_CharT __c)
      {
	_Base::operator+=(__c);
	this->_M_invalidate_all();
	return *this;
      }

#if __cplusplus >= 201103L
      basic_string&
      operator+=(std::initializer_list<_CharT> __l)
      {
	_Base::operator+=(__l);
	this->_M_invalidate_all();
	return *this;
      }
#endif // C++11

      basic_string&
      append(const basic_string& __str)
      {
	_Base::append(__str);
	this->_M_invalidate_all();
	return *this;
      }

      basic_string&
      append(const basic_string& __str, size_type __pos, size_type __n)
      {
	_Base::append(__str, __pos, __n);
	this->_M_invalidate_all();
	return *this;
      }

      basic_string&
      append(const _CharT* __s, size_type __n)
      {
	__glibcxx_check_string_len(__s, __n);
	_Base::append(__s, __n);
	this->_M_invalidate_all();
	return *this;
      }

      basic_string&
      append(const _CharT* __s)
      {
	__glibcxx_check_string(__s);
	_Base::append(__s);
	this->_M_invalidate_all();
	return *this;
      }

      basic_string&
      append(size_type __n, _CharT __c)
      {
	_Base::append(__n, __c);
	this->_M_invalidate_all();
	return *this;
      }

      template<typename _InputIterator>
	basic_string&
	append(_InputIterator __first, _InputIterator __last)
	{
	  typename __gnu_debug::_Distance_traits<_InputIterator>::__type __dist;
	  __glibcxx_check_valid_range2(__first, __last, __dist);

	  if (__dist.second >= __dp_sign)
	    _Base::append(__gnu_debug::__unsafe(__first),
			  __gnu_debug::__unsafe(__last));
	  else
	    _Base::append(__first, __last);

	  this->_M_invalidate_all();
	  return *this;
	}

      // _GLIBCXX_RESOLVE_LIB_DEFECTS
      // 7. string clause minor problems
      void
      push_back(_CharT __c)
      {
	_Base::push_back(__c);
	this->_M_invalidate_all();
      }

      basic_string&
      assign(const basic_string& __x)
      {
	_Base::assign(__x);
	this->_M_invalidate_all();
	return *this;
      }

#if __cplusplus >= 201103L
      basic_string&
      assign(basic_string&& __x)
      noexcept(noexcept(std::declval<_Base&>().assign(std::move(__x))))
      {
	_Base::assign(std::move(__x));
	this->_M_invalidate_all();
	return *this;
      }
#endif // C++11

      basic_string&
      assign(const basic_string& __str, size_type __pos, size_type __n)
      {
	_Base::assign(__str, __pos, __n);
	this->_M_invalidate_all();
	return *this;
      }

      basic_string&
      assign(const _CharT* __s, size_type __n)
      {
	__glibcxx_check_string_len(__s, __n);
	_Base::assign(__s, __n);
	this->_M_invalidate_all();
	return *this;
      }

      basic_string&
      assign(const _CharT* __s)
      {
	__glibcxx_check_string(__s);
	_Base::assign(__s);
	this->_M_invalidate_all();
	return *this;
      }

      basic_string&
      assign(size_type __n, _CharT __c)
      {
	_Base::assign(__n, __c);
	this->_M_invalidate_all();
	return *this;
      }

      template<typename _InputIterator>
	basic_string&
	assign(_InputIterator __first, _InputIterator __last)
	{
	  typename __gnu_debug::_Distance_traits<_InputIterator>::__type __dist;
	  __glibcxx_check_valid_range2(__first, __last, __dist);

	  if (__dist.second >= __dp_sign)
	    _Base::assign(__gnu_debug::__unsafe(__first),
			  __gnu_debug::__unsafe(__last));
	  else
	    _Base::assign(__first, __last);

	  this->_M_invalidate_all();
	  return *this;
	}

#if __cplusplus >= 201103L
      basic_string&
      assign(std::initializer_list<_CharT> __l)
      {
	_Base::assign(__l);
	this->_M_invalidate_all();
	return *this;
      }
#endif // C++11

      basic_string&
      insert(size_type __pos1, const basic_string& __str)
      {
	_Base::insert(__pos1, __str);
	this->_M_invalidate_all();
	return *this;
      }

      basic_string&
      insert(size_type __pos1, const basic_string& __str,
	     size_type __pos2, size_type __n)
      {
	_Base::insert(__pos1, __str, __pos2, __n);
	this->_M_invalidate_all();
	return *this;
      }

      basic_string&
      insert(size_type __pos, const _CharT* __s, size_type __n)
      {
	__glibcxx_check_string(__s);
	_Base::insert(__pos, __s, __n);
	this->_M_invalidate_all();
	return *this;
      }

      basic_string&
      insert(size_type __pos, const _CharT* __s)
      {
	__glibcxx_check_string(__s);
	_Base::insert(__pos, __s);
	this->_M_invalidate_all();
	return *this;
      }

      basic_string&
      insert(size_type __pos, size_type __n, _CharT __c)
      {
	_Base::insert(__pos, __n, __c);
	this->_M_invalidate_all();
	return *this;
      }

      iterator
      insert(__const_iterator __p, _CharT __c)
      {
	__glibcxx_check_insert(__p);
	typename _Base::iterator __res = _Base::insert(__p.base(), __c);
	this->_M_invalidate_all();
	return iterator(__res, this);
      }

#if __cplusplus >= 201103L
      iterator
      insert(const_iterator __p, size_type __n, _CharT __c)
      {
	__glibcxx_check_insert(__p);
#if _GLIBCXX_USE_CXX11_ABI
	typename _Base::iterator __res = _Base::insert(__p.base(), __n, __c);
#else
	const size_type __offset = __p.base() - _Base::cbegin();
	_Base::insert(_Base::begin() + __offset, __n, __c);
	typename _Base::iterator __res = _Base::begin() + __offset;
#endif
	this->_M_invalidate_all();
	return iterator(__res, this);
      }
#else
      void
      insert(iterator __p, size_type __n, _CharT __c)
      {
	__glibcxx_check_insert(__p);
	_Base::insert(__p.base(), __n, __c);
	this->_M_invalidate_all();
      }
#endif

      template<typename _InputIterator>
	iterator
	insert(__const_iterator __p,
	       _InputIterator __first, _InputIterator __last)
	{
	  typename __gnu_debug::_Distance_traits<_InputIterator>::__type __dist;
	  __glibcxx_check_insert_range(__p, __first, __last, __dist);

	  typename _Base::iterator __res;
#if ! _GLIBCXX_INSERT_RETURNS_ITERATOR
	  const size_type __offset = __p.base() - _Base::begin();
#endif
	  if (__dist.second >= __dp_sign)
	    {
	      _GLIBCXX_INSERT_RETURNS_ITERATOR_ONLY(__res =)
		_Base::insert(__p.base(), __gnu_debug::__unsafe(__first),
			      __gnu_debug::__unsafe(__last));
	    }
	  else
	    {
	      _GLIBCXX_INSERT_RETURNS_ITERATOR_ONLY(__res =)
		_Base::insert(__p.base(), __first, __last);
	    }

#if ! _GLIBCXX_INSERT_RETURNS_ITERATOR
	  __res = _Base::begin() + __offset;
#endif
	  this->_M_invalidate_all();
	  return iterator(__res, this);
	}

#if __cplusplus >= 201103L
      iterator
      insert(const_iterator __p, std::initializer_list<_CharT> __l)
      {
	__glibcxx_check_insert(__p);
#if _GLIBCXX_USE_CXX11_ABI
	const auto __res = _Base::insert(__p.base(), __l);
#else
	const size_type __offset = __p.base() - _Base::cbegin();
	_Base::insert(_Base::begin() + __offset, __l);
	auto __res = _Base::begin() + __offset;
#endif
	this->_M_invalidate_all();
	return iterator(__res, this);
      }
#endif // C++11

      basic_string&
      erase(size_type __pos = 0, size_type __n = _Base::npos)
      {
	_Base::erase(__pos, __n);
	this->_M_invalidate_all();
	return *this;
      }

      iterator
      erase(__const_iterator __position)
      {
	__glibcxx_check_erase(__position);
	typename _Base::iterator __res = _Base::erase(__position.base());
	this->_M_invalidate_all();
	return iterator(__res, this);
      }

      iterator
      erase(__const_iterator __first, __const_iterator __last)
      {
	// _GLIBCXX_RESOLVE_LIB_DEFECTS
	// 151. can't currently clear() empty container
	__glibcxx_check_erase_range(__first, __last);
	typename _Base::iterator __res = _Base::erase(__first.base(),
						      __last.base());
	this->_M_invalidate_all();
	return iterator(__res, this);
      }

#if __cplusplus >= 201103L
      void
      pop_back() // noexcept
      {
	__glibcxx_check_nonempty();
	_Base::pop_back();
	this->_M_invalidate_all();
      }
#endif // C++11

      basic_string&
      replace(size_type __pos1, size_type __n1, const basic_string& __str)
      {
	_Base::replace(__pos1, __n1, __str);
	this->_M_invalidate_all();
	return *this;
      }

      basic_string&
      replace(size_type __pos1, size_type __n1, const basic_string& __str,
	      size_type __pos2, size_type __n2)
      {
	_Base::replace(__pos1, __n1, __str, __pos2, __n2);
	this->_M_invalidate_all();
	return *this;
      }

      basic_string&
      replace(size_type __pos, size_type __n1, const _CharT* __s,
	      size_type __n2)
      {
	__glibcxx_check_string_len(__s, __n2);
	_Base::replace(__pos, __n1, __s, __n2);
	this->_M_invalidate_all();
	return *this;
      }

      basic_string&
      replace(size_type __pos, size_type __n1, const _CharT* __s)
      {
	__glibcxx_check_string(__s);
	_Base::replace(__pos, __n1, __s);
	this->_M_invalidate_all();
	return *this;
      }

      basic_string&
      replace(size_type __pos, size_type __n1, size_type __n2, _CharT __c)
      {
	_Base::replace(__pos, __n1, __n2, __c);
	this->_M_invalidate_all();
	return *this;
      }

      basic_string&
      replace(__const_iterator __i1, __const_iterator __i2,
	      const basic_string& __str)
      {
	__glibcxx_check_erase_range(__i1, __i2);
	_Base::replace(__i1.base(), __i2.base(), __str);
	this->_M_invalidate_all();
	return *this;
      }

      basic_string&
      replace(__const_iterator __i1, __const_iterator __i2,
	      const _CharT* __s, size_type __n)
      {
	__glibcxx_check_erase_range(__i1, __i2);
	__glibcxx_check_string_len(__s, __n);
	_Base::replace(__i1.base(), __i2.base(), __s, __n);
	this->_M_invalidate_all();
	return *this;
      }

      basic_string&
      replace(__const_iterator __i1, __const_iterator __i2,
	      const _CharT* __s)
      {
	__glibcxx_check_erase_range(__i1, __i2);
	__glibcxx_check_string(__s);
	_Base::replace(__i1.base(), __i2.base(), __s);
	this->_M_invalidate_all();
	return *this;
      }

      basic_string&
      replace(__const_iterator __i1, __const_iterator __i2,
	      size_type __n, _CharT __c)
      {
	__glibcxx_check_erase_range(__i1, __i2);
	_Base::replace(__i1.base(), __i2.base(), __n, __c);
	this->_M_invalidate_all();
	return *this;
      }

      template<typename _InputIterator>
	basic_string&
	replace(__const_iterator __i1, __const_iterator __i2,
		_InputIterator __j1, _InputIterator __j2)
	{
	  __glibcxx_check_erase_range(__i1, __i2);

	  typename __gnu_debug::_Distance_traits<_InputIterator>::__type __dist;
	  __glibcxx_check_valid_range2(__j1, __j2, __dist);

	  if (__dist.second >= __dp_sign)
	    _Base::replace(__i1.base(), __i2.base(),
			   __gnu_debug::__unsafe(__j1),
			   __gnu_debug::__unsafe(__j2));
	  else
	    _Base::replace(__i1.base(), __i2.base(), __j1, __j2);

	  this->_M_invalidate_all();
	  return *this;
	}

#if __cplusplus >= 201103L
      basic_string&
      replace(__const_iterator __i1, __const_iterator __i2,
	      std::initializer_list<_CharT> __l)
      {
	__glibcxx_check_erase_range(__i1, __i2);
	_Base::replace(__i1.base(), __i2.base(), __l);
	this->_M_invalidate_all();
	return *this;
      }
#endif // C++11

      size_type
      copy(_CharT* __s, size_type __n, size_type __pos = 0) const
      {
	__glibcxx_check_string_len(__s, __n);
	return _Base::copy(__s, __n, __pos);
      }

      void
      swap(basic_string& __x)
	_GLIBCXX_NOEXCEPT_IF(std::__is_nothrow_swappable<_Base>::value)
      {
	_Safe::_M_swap(__x);
	_Base::swap(__x);
      }

      // 21.3.6 string operations:
      const _CharT*
      c_str() const _GLIBCXX_NOEXCEPT
      {
	const _CharT* __res = _Base::c_str();
	this->_M_invalidate_all();
	return __res;
      }

      const _CharT*
      data() const _GLIBCXX_NOEXCEPT
      {
	const _CharT* __res = _Base::data();
	this->_M_invalidate_all();
	return __res;
      }

      using _Base::get_allocator;

      using _Base::find;

      _GLIBCXX20_CONSTEXPR
      size_type
      find(const _CharT* __s, size_type __pos, size_type __n) const
	_GLIBCXX_NOEXCEPT
      {
	__glibcxx_check_string(__s);
	return _Base::find(__s, __pos, __n);
      }

      _GLIBCXX20_CONSTEXPR
      size_type
      find(const _CharT* __s, size_type __pos = 0) const _GLIBCXX_NOEXCEPT
      {
	__glibcxx_check_string(__s);
	return _Base::find(__s, __pos);
      }

      using _Base::rfind;

      _GLIBCXX20_CONSTEXPR
      size_type
      rfind(const _CharT* __s, size_type __pos, size_type __n) const
      {
	__glibcxx_check_string_len(__s, __n);
	return _Base::rfind(__s, __pos, __n);
      }

      _GLIBCXX20_CONSTEXPR
      size_type
      rfind(const _CharT* __s, size_type __pos = _Base::npos) const
      {
	__glibcxx_check_string(__s);
	return _Base::rfind(__s, __pos);
      }

      using _Base::find_first_of;

      _GLIBCXX20_CONSTEXPR
      size_type
      find_first_of(const _CharT* __s, size_type __pos, size_type __n) const
	_GLIBCXX_NOEXCEPT
      {
	__glibcxx_check_string(__s);
	return _Base::find_first_of(__s, __pos, __n);
      }

      _GLIBCXX20_CONSTEXPR
      size_type
      find_first_of(const _CharT* __s, size_type __pos = 0) const _GLIBCXX_NOEXCEPT
      {
	__glibcxx_check_string(__s);
	return _Base::find_first_of(__s, __pos);
      }

      using _Base::find_last_of;

      _GLIBCXX20_CONSTEXPR
      size_type
      find_last_of(const _CharT* __s, size_type __pos, size_type __n) const
	_GLIBCXX_NOEXCEPT
      {
	__glibcxx_check_string(__s);
	return _Base::find_last_of(__s, __pos, __n);
      }

      _GLIBCXX20_CONSTEXPR
      size_type
      find_last_of(const _CharT* __s, size_type __pos = _Base::npos) const
	_GLIBCXX_NOEXCEPT
      {
	__glibcxx_check_string(__s);
	return _Base::find_last_of(__s, __pos);
      }

      using _Base::find_first_not_of;

      _GLIBCXX20_CONSTEXPR
      size_type
      find_first_not_of(const _CharT* __s, size_type __pos, size_type __n) const
	_GLIBCXX_NOEXCEPT
      {
	__glibcxx_check_string_len(__s, __n);
	return _Base::find_first_not_of(__s, __pos, __n);
      }

      _GLIBCXX20_CONSTEXPR
      size_type
      find_first_not_of(const _CharT* __s, size_type __pos = 0) const
	_GLIBCXX_NOEXCEPT
      {
	__glibcxx_check_string(__s);
	return _Base::find_first_not_of(__s, __pos);
      }

      using _Base::find_last_not_of;

      _GLIBCXX20_CONSTEXPR
      size_type
      find_last_not_of(const _CharT* __s, size_type __pos, size_type __n) const
	_GLIBCXX_NOEXCEPT
      {
	__glibcxx_check_string(__s);
	return _Base::find_last_not_of(__s, __pos, __n);
      }

      _GLIBCXX20_CONSTEXPR
      size_type
      find_last_not_of(const _CharT* __s, size_type __pos = _Base::npos) const
	_GLIBCXX_NOEXCEPT
      {
	__glibcxx_check_string(__s);
	return _Base::find_last_not_of(__s, __pos);
      }

      basic_string
      substr(size_type __pos = 0, size_type __n = _Base::npos) const
      { return basic_string(_Base::substr(__pos, __n)); }

      using _Base::compare;

      _GLIBCXX20_CONSTEXPR
      int
      compare(const _CharT* __s) const _GLIBCXX_NOEXCEPT
      {
	__glibcxx_check_string(__s);
	return _Base::compare(__s);
      }

      //  _GLIBCXX_RESOLVE_LIB_DEFECTS
      //  5. string::compare specification questionable
      _GLIBCXX20_CONSTEXPR
      int
      compare(size_type __pos1, size_type __n1, const _CharT* __s) const
      {
	__glibcxx_check_string(__s);
	return _Base::compare(__pos1, __n1, __s);
      }

      //  _GLIBCXX_RESOLVE_LIB_DEFECTS
      //  5. string::compare specification questionable
      _GLIBCXX20_CONSTEXPR
      int
      compare(size_type __pos1, size_type __n1,const _CharT* __s,
	      size_type __n2) const
      {
	__glibcxx_check_string_len(__s, __n2);
	return _Base::compare(__pos1, __n1, __s, __n2);
      }

      _Base&
      _M_base() _GLIBCXX_NOEXCEPT		{ return *this; }

      const _Base&
      _M_base() const _GLIBCXX_NOEXCEPT	{ return *this; }

      using _Safe::_M_invalidate_all;
    };

  template<typename _CharT, typename _Traits, typename _Allocator>
    inline basic_string<_CharT,_Traits,_Allocator>
    operator+(const basic_string<_CharT,_Traits,_Allocator>& __lhs,
	      const basic_string<_CharT,_Traits,_Allocator>& __rhs)
    { return basic_string<_CharT,_Traits,_Allocator>(__lhs) += __rhs; }

  template<typename _CharT, typename _Traits, typename _Allocator>
    inline basic_string<_CharT,_Traits,_Allocator>
    operator+(const _CharT* __lhs,
	      const basic_string<_CharT,_Traits,_Allocator>& __rhs)
    {
      __glibcxx_check_string(__lhs);
      return basic_string<_CharT,_Traits,_Allocator>(__lhs) += __rhs;
    }

  template<typename _CharT, typename _Traits, typename _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; }

  template<typename _CharT, typename _Traits, typename _Allocator>
    inline basic_string<_CharT,_Traits,_Allocator>
    operator+(const basic_string<_CharT,_Traits,_Allocator>& __lhs,
	      const _CharT* __rhs)
    {
      __glibcxx_check_string(__rhs);
      return basic_string<_CharT,_Traits,_Allocator>(__lhs) += __rhs;
    }

  template<typename _CharT, typename _Traits, typename _Allocator>
    inline basic_string<_CharT,_Traits,_Allocator>
    operator+(const basic_string<_CharT,_Traits,_Allocator>& __lhs,
	      _CharT __rhs)
    { return basic_string<_CharT,_Traits,_Allocator>(__lhs) += __rhs; }

  template<typename _CharT, typename _Traits, typename _Allocator>
    inline bool
    operator==(const basic_string<_CharT,_Traits,_Allocator>& __lhs,
	       const basic_string<_CharT,_Traits,_Allocator>& __rhs)
    { return __lhs._M_base() == __rhs._M_base(); }

  template<typename _CharT, typename _Traits, typename _Allocator>
    inline bool
    operator==(const _CharT* __lhs,
	       const basic_string<_CharT,_Traits,_Allocator>& __rhs)
    {
      __glibcxx_check_string(__lhs);
      return __lhs == __rhs._M_base();
    }

  template<typename _CharT, typename _Traits, typename _Allocator>
    inline bool
    operator==(const basic_string<_CharT,_Traits,_Allocator>& __lhs,
	       const _CharT* __rhs)
    {
      __glibcxx_check_string(__rhs);
      return __lhs._M_base() == __rhs;
    }

  template<typename _CharT, typename _Traits, typename _Allocator>
    inline bool
    operator!=(const basic_string<_CharT,_Traits,_Allocator>& __lhs,
	       const basic_string<_CharT,_Traits,_Allocator>& __rhs)
    { return __lhs._M_base() != __rhs._M_base(); }

  template<typename _CharT, typename _Traits, typename _Allocator>
    inline bool
    operator!=(const _CharT* __lhs,
	       const basic_string<_CharT,_Traits,_Allocator>& __rhs)
    {
      __glibcxx_check_string(__lhs);
      return __lhs != __rhs._M_base();
    }

  template<typename _CharT, typename _Traits, typename _Allocator>
    inline bool
    operator!=(const basic_string<_CharT,_Traits,_Allocator>& __lhs,
	       const _CharT* __rhs)
    {
      __glibcxx_check_string(__rhs);
      return __lhs._M_base() != __rhs;
    }

  template<typename _CharT, typename _Traits, typename _Allocator>
    inline bool
    operator<(const basic_string<_CharT,_Traits,_Allocator>& __lhs,
	      const basic_string<_CharT,_Traits,_Allocator>& __rhs)
    { return __lhs._M_base() < __rhs._M_base(); }

  template<typename _CharT, typename _Traits, typename _Allocator>
    inline bool
    operator<(const _CharT* __lhs,
	      const basic_string<_CharT,_Traits,_Allocator>& __rhs)
    {
      __glibcxx_check_string(__lhs);
      return __lhs < __rhs._M_base();
    }

  template<typename _CharT, typename _Traits, typename _Allocator>
    inline bool
    operator<(const basic_string<_CharT,_Traits,_Allocator>& __lhs,
	      const _CharT* __rhs)
    {
      __glibcxx_check_string(__rhs);
      return __lhs._M_base() < __rhs;
    }

  template<typename _CharT, typename _Traits, typename _Allocator>
    inline bool
    operator<=(const basic_string<_CharT,_Traits,_Allocator>& __lhs,
	       const basic_string<_CharT,_Traits,_Allocator>& __rhs)
    { return __lhs._M_base() <= __rhs._M_base(); }

  template<typename _CharT, typename _Traits, typename _Allocator>
    inline bool
    operator<=(const _CharT* __lhs,
	       const basic_string<_CharT,_Traits,_Allocator>& __rhs)
    {
      __glibcxx_check_string(__lhs);
      return __lhs <= __rhs._M_base();
    }

  template<typename _CharT, typename _Traits, typename _Allocator>
    inline bool
    operator<=(const basic_string<_CharT,_Traits,_Allocator>& __lhs,
	       const _CharT* __rhs)
    {
      __glibcxx_check_string(__rhs);
      return __lhs._M_base() <= __rhs;
    }

  template<typename _CharT, typename _Traits, typename _Allocator>
    inline bool
    operator>=(const basic_string<_CharT,_Traits,_Allocator>& __lhs,
	       const basic_string<_CharT,_Traits,_Allocator>& __rhs)
    { return __lhs._M_base() >= __rhs._M_base(); }

  template<typename _CharT, typename _Traits, typename _Allocator>
    inline bool
    operator>=(const _CharT* __lhs,
	       const basic_string<_CharT,_Traits,_Allocator>& __rhs)
    {
      __glibcxx_check_string(__lhs);
      return __lhs >= __rhs._M_base();
    }

  template<typename _CharT, typename _Traits, typename _Allocator>
    inline bool
    operator>=(const basic_string<_CharT,_Traits,_Allocator>& __lhs,
	       const _CharT* __rhs)
    {
      __glibcxx_check_string(__rhs);
      return __lhs._M_base() >= __rhs;
    }

  template<typename _CharT, typename _Traits, typename _Allocator>
    inline bool
    operator>(const basic_string<_CharT,_Traits,_Allocator>& __lhs,
	      const basic_string<_CharT,_Traits,_Allocator>& __rhs)
    { return __lhs._M_base() > __rhs._M_base(); }

  template<typename _CharT, typename _Traits, typename _Allocator>
    inline bool
    operator>(const _CharT* __lhs,
	      const basic_string<_CharT,_Traits,_Allocator>& __rhs)
    {
      __glibcxx_check_string(__lhs);
      return __lhs > __rhs._M_base();
    }

  template<typename _CharT, typename _Traits, typename _Allocator>
    inline bool
    operator>(const basic_string<_CharT,_Traits,_Allocator>& __lhs,
	      const _CharT* __rhs)
    {
      __glibcxx_check_string(__rhs);
      return __lhs._M_base() > __rhs;
    }

  // 21.3.7.8:
  template<typename _CharT, typename _Traits, typename _Allocator>
    inline void
    swap(basic_string<_CharT,_Traits,_Allocator>& __lhs,
	 basic_string<_CharT,_Traits,_Allocator>& __rhs)
    { __lhs.swap(__rhs); }

  template<typename _CharT, typename _Traits, typename _Allocator>
    std::basic_ostream<_CharT, _Traits>&
    operator<<(std::basic_ostream<_CharT, _Traits>& __os,
	       const basic_string<_CharT, _Traits, _Allocator>& __str)
    { return __os << __str._M_base(); }

  template<typename _CharT, typename _Traits, typename _Allocator>
    std::basic_istream<_CharT,_Traits>&
    operator>>(std::basic_istream<_CharT,_Traits>& __is,
	       basic_string<_CharT,_Traits,_Allocator>& __str)
    {
      std::basic_istream<_CharT,_Traits>& __res = __is >> __str._M_base();
      __str._M_invalidate_all();
      return __res;
    }

  template<typename _CharT, typename _Traits, typename _Allocator>
    std::basic_istream<_CharT,_Traits>&
    getline(std::basic_istream<_CharT,_Traits>& __is,
	    basic_string<_CharT,_Traits,_Allocator>& __str, _CharT __delim)
    {
      std::basic_istream<_CharT,_Traits>& __res = getline(__is,
							  __str._M_base(),
							__delim);
      __str._M_invalidate_all();
      return __res;
    }

  template<typename _CharT, typename _Traits, typename _Allocator>
    std::basic_istream<_CharT,_Traits>&
    getline(std::basic_istream<_CharT,_Traits>& __is,
	    basic_string<_CharT,_Traits,_Allocator>& __str)
    {
      std::basic_istream<_CharT,_Traits>& __res = getline(__is,
							  __str._M_base());
      __str._M_invalidate_all();
      return __res;
    }

  typedef basic_string<char>    string;

  typedef basic_string<wchar_t> wstring;

#ifdef _GLIBCXX_USE_CHAR8_T
  /// A string of @c char8_t
  typedef basic_string<char8_t> u8string;
#endif

#if __cplusplus >= 201103L
  /// A string of @c char16_t
  typedef basic_string<char16_t> u16string;

  /// A string of @c char32_t
  typedef basic_string<char32_t> u32string;
#endif

  template<typename _CharT, typename _Traits, typename _Allocator>
    struct _Insert_range_from_self_is_safe<
      __gnu_debug::basic_string<_CharT, _Traits, _Allocator> >
      { enum { __value = 1 }; };

} // namespace __gnu_debug

#if __cplusplus >= 201103L
namespace std _GLIBCXX_VISIBILITY(default)
{
_GLIBCXX_BEGIN_NAMESPACE_VERSION

  /// std::hash specialization for __gnu_debug::basic_string.
  template<typename _CharT>
    struct hash<__gnu_debug::basic_string<_CharT>>
    : public hash<std::basic_string<_CharT>>
    { };

  template<typename _CharT>
    struct __is_fast_hash<hash<__gnu_debug::basic_string<_CharT>>>
    : __is_fast_hash<hash<std::basic_string<_CharT>>>
    { };

_GLIBCXX_END_NAMESPACE_VERSION
}
#endif /* C++11 */

#undef _GLIBCXX_INSERT_RETURNS_ITERATOR
#undef _GLIBCXX_INSERT_RETURNS_ITERATOR_ONLY

#endif
