// bslstl_string.h                                                    -*-C++-*-
#ifndef INCLUDED_BSLSTL_STRING
#define INCLUDED_BSLSTL_STRING

#include <bsls_ident.h>
BSLS_IDENT("$Id: $")

//@PURPOSE: Provide a standard-compliant 'basic_string' class template.
//
//@CLASSES:
//  bsl::basic_string: C++ standard compliant 'basic_string' implementation
//  bsl::string: 'typedef' for 'bsl::basic_string<char>'
//  bsl::wstring: 'typedef' for 'bsl::basic_string<wchar_t>'/
//
//@CANONICAL_HEADER: bsl_string.h
//
//@SEE_ALSO: ISO C++ Standard, Section 21 [strings]
//
//@DESCRIPTION: This component defines a single class template 'basic_string',
// implementing standard containers, 'std::string' and 'std::wstring', that
// hold a sequence of characters.
//
// An instantiation of 'basic_string' is an allocator-aware, value-semantic
// type whose salient attributes are its size (number of characters) and the
// sequence of characters that the string contains.  The 'basic_string' 'class'
// is parameterized by the character type, 'CHAR_TYPE', that character type's
// traits, 'CHAR_TRAITS', and an allocator, 'ALLOCATOR'.  The traits for each
// character type provide functions that assign, compare, and copy a sequence
// of those characters.
//
// A 'basic_string' meets the requirements of a sequential container with
// random access iterators as specified in the [basic.string] section of the
// C++ standard [21.4].  The 'basic_string' implemented here adheres to the
// C++11 standard, except that it does not have template specializations
// 'std::u16string' and 'std::u32string'.  Note that excluded C++11 features
// are those that require (or are greatly simplified by) C++11 compiler
// support.
//
///Memory Allocation
///-----------------
// The type supplied as a 'basic_string's 'ALLOCATOR' template parameter
// determines how that 'basic_string' will allocate memory.  The 'basic_string'
// template supports allocators meeting the requirements of the C++11 standard,
// in addition it supports scoped-allocators derived from the
// 'bslma::Allocator' memory allocation protocol.  Clients intending to use
// 'bslma' style allocators should use the template's default 'ALLOCATOR' type:
// The default type for the 'ALLOCATOR' template parameter, 'bsl::allocator',
// provides a C++11 standard-compatible adapter for a 'bslma::Allocator'
// object.
//
///'bslma'-Style Allocators
/// - - - - - - - - - - - -
// If the (template parameter) type 'ALLOCATOR' of an 'basic_string'
// instantiation is 'bsl::allocator', then objects of that 'basic_string' type
// will conform to the standard behavior of a 'bslma'-allocator-enabled type.
// Such a 'basic_string' accepts an optional 'bslma::Allocator' argument at
// construction.  If the address of a 'bslma::Allocator' object is explicitly
// supplied at construction, it is used to supply memory for the 'basic_string'
// throughout its lifetime; otherwise, the 'basic_string' will use the default
// allocator installed at the time of the 'basic_string''s construction (see
// 'bslma_default').
//
///Lexicographical Comparisons
///---------------------------
// Two 'basic_string's 'lhs' and 'rhs' are lexicographically compared by first
// determining 'N', the smaller of the lengths of 'lhs' and 'rhs', and
// comparing characters at each position between 0 and 'N - 1', using
// 'CHAR_TRAITS::lt' in lexicographical fashion.  If 'CHAR_TRAITS::lt'
// determines that strings are non-equal (smaller or larger), then this is the
// result.  Otherwise, the lengths of the strings are compared and the shorter
// string is declared the smaller.  Lexicographical comparison returns equality
// only when both strings have the same length and the same character value in
// each respective position.
//
///Operations
///----------
// This section describes the run-time complexity of operations on instances of
// 'basic_string':
//..
//  Legend
//  ------
//  'V'              - the 'CHAR_TYPE' template parameter type of the
//                     'basic_string'
//  'a', 'b'         - two distinct objects of type 'basic_string<V>'
//  'k'              - an integral number
//  'al'             - an STL-style memory allocator
//  'i1', 'i2'       - two iterators defining a sequence of 'CHAR_TYPE'
//                     characters
//  'v'              - an object of type 'V'
//  'p1', 'p2'       - two iterators belonging to 'a'
//  distance(i1,i2)  - the number of values in the range [i1, i2)
//
//  +-----------------------------------------+-------------------------------+
//  | Operation                               | Complexity                    |
//  |=========================================+===============================|
//  | basic_string<V> a (default construction)| O[1]                          |
//  | basic_string<V> a(al)                   |                               |
//  |-----------------------------------------+-------------------------------|
//  | basic_string<V> a(b) (copy construction)| O[n]                          |
//  | basic_string<V> a(b, al)                |                               |
//  |-----------------------------------------+-------------------------------|
//  | basic_string<V> a(std::move(b))         | O[1]                          |
//  | (move construction)                     |                               |
//  |-----------------------------------------+-------------------------------|
//  | basic_string<V> a(std::move(b), a1)     | O[n]                          |
//  | (extended move construction)            |                               |
//  |-----------------------------------------+-------------------------------|
//  | basic_string<V> a(k)                    | O[n]                          |
//  | basic_string<V> a(k, al)                |                               |
//  |-----------------------------------------+-------------------------------|
//  | basic_string<V> a(i1, i2)               | O[distance(i1,i2)]            |
//  | basic_string<V> a(i1, i2, al)           |                               |
//  |-----------------------------------------+-------------------------------|
//  | a.~basic_string<V>()  (destruction)     | O[1]                          |
//  |-----------------------------------------+-------------------------------|
//  | get_allocator()                         | O[1]                          |
//  |-----------------------------------------+-------------------------------|
//  | a.begin(), a.end(),                     | O[1]                          |
//  | a.cbegin(), a.cend(),                   |                               |
//  | a.rbegin(), a.rend(),                   |                               |
//  | a.crbegin(), a.crend()                  |                               |
//  |-----------------------------------------+-------------------------------|
//  | a.size()                                | O[1]                          |
//  |-----------------------------------------+-------------------------------|
//  | a.max_size()                            | O[1]                          |
//  |-----------------------------------------+-------------------------------|
//  | a.resize(k)                             | O[k]                          |
//  | a.resize(k, v)                          |                               |
//  |-----------------------------------------+-------------------------------|
//  | a.empty()                               | O[1]                          |
//  |-----------------------------------------+-------------------------------|
//  | a.reserve(k)                            | O[1]                          |
//  |-----------------------------------------+-------------------------------|
//  | a.shrink_to_fit()                       | O[n]                          |
//  |-----------------------------------------+-------------------------------|
//  | a[k]                                    | O[1]                          |
//  |-----------------------------------------+-------------------------------|
//  | a.at(k)                                 | O[1]                          |
//  |-----------------------------------------+-------------------------------|
//  | a.front()                               | O[1]                          |
//  |-----------------------------------------+-------------------------------|
//  | a.back()                                | O[1]                          |
//  |-----------------------------------------+-------------------------------|
//  | a.push_back()                           | O[1]                          |
//  |-----------------------------------------+-------------------------------|
//  | a.pop_back()                            | O[1]                          |
//  |-----------------------------------------+-------------------------------|
//  | a += b;                                 | O[n]                          |
//  |-----------------------------------------+-------------------------------|
//  | a.append(b);                            | O[n]                          |
//  |-----------------------------------------+-------------------------------|
//  | a.assign(b);                            | O[n]                          |
//  |-----------------------------------------+-------------------------------|
//  | a.assign(std::move(b));                 | O[1] if the allocator can be  |
//  |                                         | propagated on container move  |
//  |                                         | assignment or 'a' and 'b' use |
//  |                                         | the same allocator; O[n]      |
//  |                                         | otherwise                     |
//  |-----------------------------------------+-------------------------------|
//  | a.assign(k, v)                          | O[k]                          |
//  |-----------------------------------------+-------------------------------|
//  | a.assign(i1, i2)                        | O[distance(i1,i2)]            |
//  |-----------------------------------------+-------------------------------|
//  | a.insert(p1, v)                         | O[1 + distance(p1, a.end())]  |
//  |-----------------------------------------+-------------------------------|
//  | a.insert(p1, k, v)                      | O[k + distance(p1, a.end())]  |
//  |-----------------------------------------+-------------------------------|
//  | a.insert(p1, i1, i2)                    | O[distance(i1, i2)            |
//  |                                         |      + distance(p1, a.end())] |
//  |-----------------------------------------+-------------------------------|
//  | a.erase(p1)                             | O[1 + distance(p1, a.end())]  |
//  |-----------------------------------------+-------------------------------|
//  | a.erase(p1, p2)                         | O[1 + distance(p1, a.end())]  |
//  |-----------------------------------------+-------------------------------|
//  | a.swap(b), swap(a, b)                   | O[1] if 'a' and 'b' allocators|
//  |                                         | compare equal, O[n + m]       |
//  |                                         | otherwise                     |
//  |-----------------------------------------+-------------------------------|
//  | a.clear()                               | O[1]                          |
//  |-----------------------------------------+-------------------------------|
//  | a = b;              (assignment)        | O[n]                          |
//  |-----------------------------------------+-------------------------------|
//  | a = std::move(b);   (move assignment)   | O[1] if the allocator can be  |
//  |                                         | propagated on container move  |
//  |                                         | assignment or 'a' and 'b' use |
//  |                                         | the same allocator; O[n]      |
//  |                                         | otherwise                     |
//  |-----------------------------------------+-------------------------------|
//  | a == b, a != b                          | O[n]                          |
//  |-----------------------------------------+-------------------------------|
//  | a < b, a <= b, a > b, a >= b            | O[n]                          |
//  +-----------------------------------------+-------------------------------+
//..
//
///User-defined literals
///---------------------
// The user-defined literal operators are declared for the 'bsl::string' and
// 'bsl::wstring' types.  The ud-suffix '_s' is chosen to distinguish between
// the 'bsl'-string's user-defined literal operators and the 'std'-string's
// user-defined literal 'operator ""s' introduced in the C++14 standard and
// implemented in the standard library provided by the compiler vendor.  Note
// that the 'bsl'-string's 'operator "" _s', unlike the 'std'-string's
// 'operator ""s', can be used in a client's code if the compiler supports the
// C++11 standard.  Also note that if the compiler supports the C++14 standard
// then the 'std'-string's 'operator ""s' can be used to initialize a
// 'bsl'-string as follows:
//..
// using namespace std::string_literals;
// bsl::string str = "test"s;
//..
// however such initialization introduces significant performance overhead due
// to extra 'std'-string object creation/destruction.
//
// Also note that 'bsl'-string's user-defined literal operators are declared in
// the 'bsl::literals::string_literals' namespace, where 'literals' and
// 'string_literals' are inline namespaces.  Access to these operators can be
// gained with either 'using namespace bsl::literals',
// 'using namespace bsl::string_literals' or
// 'using namespace bsl::literals::string_literals'.  But we recommend
// 'using namespace bsl::string_literals' to minimize the scope of the using
// declaration:
//..
// using namespace bsl::string_literals;
// bsl::string str = "test"_s;
//..
//
///Memory Allocation For a File-Scope Strings
/// - - - - - - - - - - - - - - - - - - - - -
// The 'operator "" _s' uses the currently installed default allocator to
// supply memory.  Note that the default allocator can become locked prior to
// entering 'main' as a side-effect of initializing a file-scope static string
// object using 'operator "" _s'.  To avoid the default allocator locking an
// 'operator "" _S' can be used instead.  This operator uses the global
// allocator to supply memory and has no side-effects.  (See the "Default
// Allocator" section in the 'bslma::Default' component-level documentation for
// details.)  For Example:
//..
// using namespace bsl::string_literals;
// static const bsl::string s = "Use '_S' to initialize a file-scope string"_S;
//..
//
///Usage
///-----
// In this section we show intended use of this component.
//
///Example 1: Basic Syntax
///- - - - - - - - - - - -
// In this example, we will show how to create and use the 'string' typedef.
//
// First, we will default-construct a 'string' object:
//..
//  bsl::string s;
//  assert(s.empty());
//  assert(0  == s.size());
//  assert("" == s);
//..
// Then, we will construct a 'string' object from a string literal:
//..
//  bsl::string t = "Hello World";
//  assert(!t.empty());
//  assert(11 == t.size());
//  assert("Hello World" == t);
//..
// Next, we will clear the contents of 't' and assign it a couple of values:
// first from a string literal; and second from another 'string' object:
//..
//  t.clear();
//  assert(t.empty());
//  assert("" == t);
//
//  t = "Good Morning";
//  assert(!t.empty());
//  assert("Good Morning" == t);
//
//  t = s;
//  assert(t.empty());
//  assert("" == t);
//  assert(t == s);
//..
// Then, we will create three 'string' objects: the first representing a street
// name, the second a state, and the third a ZIP code.  We will then
// concatenate them into a single address 'string' and print the contents of
// that 'string' on standard output:
//..
//  const bsl::string street  = "731 Lexington Avenue";
//  const bsl::string state   = "NY";
//  const bsl::string zipCode = "10022";
//
//  const bsl::string fullAddress = street + " " + state + " " + zipCode;
//
//  bsl::cout << fullAddress << bsl::endl;
//..
// The above print statement should produce a single line of output:
//..
//  731 Lexington Avenue NY 10022
//..
// Then, we search the contents of 'address' (using the 'find' function) to
// determine if it lies on a specified street:
//..
//  const bsl::string streetName = "Lexington";
//
//  if (bsl::string::npos != fullAddress.find(streetName, 0)) {
//      bsl::cout << "The address " << fullAddress << " is located on "
//                << streetName << "." << bsl::endl;
//  }
//..
// Next, we show how to get a reference providing modifiable access to the
// null-terminated string literal stored by a 'string' object using the 'c_str'
// function.  Note that the returned string literal can be passed to various
// standard functions expecting a null-terminated string:
//..
//  const bsl::string  v = "Another string";
//  const char        *cs = v.c_str();
//  assert(bsl::strlen(cs) == v.size());
//..
// Then, we construct two 'string' objects, 'x' and 'y', using a user-specified
// allocator:
//..
//  bslma::TestAllocator allocator1, allocator2;
//
//  const char *SHORT_STRING = "A small string";
//  const char *LONG_STRING  = "This long string would definitely cause "
//                             "memory to be allocated on creation";
//
//  const bsl::string x(SHORT_STRING, &allocator1);
//  const bsl::string y(LONG_STRING,  &allocator2);
//
//  assert(SHORT_STRING == x);
//  assert(LONG_STRING  == y);
//..
// Notice that, no memory was allocated from the allocator for object 'x'
// because of the short-string optimization used in the 'string' type.
//
// Finally, we can track memory usage of 'x' and 'y' using 'allocator1' and
// 'allocator2' and check that memory was allocated only by 'allocator2':
//..
//  assert(0 == allocator1.numBlocksInUse());
//  assert(1 == allocator2.numBlocksInUse());
//..
//
///Example 2: 'string' as a data member
///- - - - - - - - - - - - - - - - - -
// The most common use of 'string' objects are as data members in user-defined
// classes.  In this example, we will show how 'string' objects can be used as
// data members.
//
// First, we begin to define a 'class', 'Employee', that represents the data
// corresponding to an employee of a company:
//..
//  class Employee {
//      // This simply constrained (value-semantic) attribute class represents
//      // the information about an employee.  An employee's first and last
//      // name are represented as 'string' objects and their employee
//      // identification number is represented by an 'int'.  Note that the
//      // class invariants are identically the constraints on the individual
//      // attributes.
//      //
//      // This class:
//      //: o supports a complete set of *value-semantic* operations
//      //:   o except for BDEX serialization
//      //: o is *exception-neutral* (agnostic)
//      //: o is *alias-safe*
//      //: o is 'const' *thread-safe*
//
//      // DATA
//      bsl::string d_firstName;       // first name
//      bsl::string d_lastName;        // last name
//      int         d_id;              // identification number
//..
//  Next, we define the creators for this class:
//..
//    public:
//      // CREATORS
//      Employee(bslma::Allocator *basicAllocator = 0);
//          // Create a 'Employee' object having the (default) attribute
//          // values:
//          //..
//          //  firstName() == ""
//          //  lastName()  == ""
//          //  id()        == 0
//          //..
//          // Optionally specify a 'basicAllocator' used to supply memory.  If
//          // 'basicAllocator' is 0, the currently installed default
//          // allocator is used.
//
//      Employee(const bsl::string_view&  firstName,
//               const bsl::string_view&  lastName,
//               int                      id,
//               bslma::Allocator        *basicAllocator = 0);
//          // Create a 'Employee' object having the specified 'firstName',
//          // 'lastName', and 'id'' attribute values.  Optionally specify a
//          // 'basicAllocator' used to supply memory.  If 'basicAllocator' is
//          // 0, the currently installed default allocator is used.
//
//      Employee(const Employee&   original,
//               bslma::Allocator *basicAllocator = 0);
//          // Create a 'Employee' object having the same value as the
//          // specified 'original' object.  Optionally specify a
//          // 'basicAllocator' used to supply memory.  If 'basicAllocator' is
//          // 0, the currently installed default allocator is used.
//
//      //! ~Employee() = default;
//          // Destroy this object.
//..
// Notice that all constructors of the 'Employee' class are optionally provided
// an allocator that is then passed through to the 'string' data members of
// 'Employee'.  This allows the user to control how memory is allocated by
// 'Employee' objects.  Also note that the type of the 'firstName' and
// 'lastName' arguments of the value constructor is 'bsl::string_view'.  The
// 'bsl::string_view' allows specifying a 'string' or a 'const char *' to
// represent a string value.  For the sake of brevity its implementation is
// not explored here.
//
// Then, declare the remaining methods of the class:
//..
//      // MANIPULATORS
//      Employee& operator=(const Employee& rhs);
//          // Assign to this object the value of the specified 'rhs' object,
//          // and return a reference providing modifiable access to this
//          // object.
//
//      void setFirstName(const bsl::string_view& value);
//          // Set the 'firstName' attribute of this object to the specified
//          // 'value'.
//
//      void setLastName(const bsl::string_view& value);
//          // Set the 'lastName' attribute of this object to the specified
//          // 'value'.
//
//      void setId(int value);
//          // Set the 'id' attribute of this object to the specified 'value'.
//
//      // ACCESSORS
//      const bsl::string& firstName() const;
//          // Return a reference providing non-modifiable access to the
//          // 'firstName' attribute of this object.
//
//      const bsl::string& lastName() const;
//          // Return a reference providing non-modifiable access to the
//          // 'lastName' attribute of this object.
//
//      int id() const;
//          // Return the value of the 'id' attribute of this object.
//  };
//..
// Next, we declare the free operators for 'Employee':
//..
//  inline
//  bool operator==(const Employee& lhs, const Employee& rhs);
//      // Return 'true' if the specified 'lhs' and 'rhs' objects have the same
//      // value, and 'false' otherwise.  Two 'Employee' objects have the
//      // same value if all of their corresponding values of their
//      // 'firstName', 'lastName', and 'id' attributes are the same.
//
//  inline
//  bool operator!=(const Employee& lhs, const Employee& rhs);
//      // Return 'true' if the specified 'lhs' and 'rhs' objects do not have
//      // the same value, and 'false' otherwise.  Two 'Employee' objects do
//      // not have the same value if any of the corresponding values of their
//      // 'firstName', 'lastName', or 'id' attributes are not the same.
//..
// Then, we implement the various methods of the 'Employee' class:
//..
//  // CREATORS
//  inline
//  Employee::Employee(bslma::Allocator *basicAllocator)
//  : d_firstName(basicAllocator)
//  , d_lastName(basicAllocator)
//  , d_id(0)
//  {
//  }
//
//  inline
//  Employee::Employee(const bsl::string_view&  firstName,
//                     const bsl::string_view&  lastName,
//                     int                      id,
//                     bslma::Allocator        *basicAllocator)
//  : d_firstName(firstName.begin(), firstName.end(), basicAllocator)
//  , d_lastName(lastName.begin(), lastName.end(), basicAllocator)
//  , d_id(id)
//  {
//      BSLS_ASSERT_SAFE(!firstName.empty());
//      BSLS_ASSERT_SAFE(!lastName.empty());
//  }
//
//  inline
//  Employee::Employee(const Employee&   original,
//                     bslma::Allocator *basicAllocator)
//  : d_firstName(original.d_firstName, basicAllocator)
//  , d_lastName(original.d_lastName, basicAllocator)
//  , d_id(original.d_id)
//  {
//  }
//..
// Notice that the 'basicAllocator' parameter can simply be passed as an
// argument to the constructor of 'bsl::string'.
//
// Now, we implement the remaining manipulators of the 'Employee' class:
//..
//  // MANIPULATORS
//  inline
//  Employee& Employee::operator=(const Employee& rhs)
//  {
//      d_firstName = rhs.d_firstName;
//      d_lastName  = rhs.d_lastName;
//      d_id        = rhs.d_id;
//      return *this;
//  }
//
//  inline
//  void Employee::setFirstName(const bsl::string_view& value)
//  {
//      BSLS_ASSERT_SAFE(!value.empty());
//
//      d_firstName.assign(value.begin(), value.end());
//  }
//
//  inline
//  void Employee::setLastName(const bsl::string_view& value)
//  {
//      BSLS_ASSERT_SAFE(!value.empty());
//
//      d_lastName.assign(value.begin(), value.end());
//  }
//
//  inline
//  void Employee::setId(int value)
//  {
//      d_id = value;
//  }
//
//  // ACCESSORS
//  inline
//  const bsl::string& Employee::firstName() const
//  {
//      return d_firstName;
//  }
//
//  inline
//  const bsl::string& Employee::lastName() const
//  {
//      return d_lastName;
//  }
//
//  inline
//  int Employee::id() const
//  {
//      return d_id;
//  }
//..
// Finally, we implement the free operators for 'Employee' class:
//..
//  inline
//  bool operator==(const Employee& lhs, const Employee& rhs)
//  {
//      return lhs.firstName() == rhs.firstName()
//          && lhs.lastName()  == rhs.lastName()
//          && lhs.id()        == rhs.id();
//  }
//
//  inline
//  bool operator!=(const Employee& lhs, const Employee& rhs)
//  {
//      return lhs.firstName() != rhs.firstName()
//          || lhs.lastName()  != rhs.lastName()
//          || lhs.id()        != rhs.id();
//  }
//..
//
///Example 3: A stream text replacement filter
///- - - - - - - - - - - - - - - - - - - - - -
// In this example, we will utilize the 'string' type and its associated
// utility functions to define a function that reads data from an input stream,
// replaces all occurrences of a specified text fragment with another text
// fragment, and writes the resulting text to an output stream.
//
// First, we define the signature of the function, 'replace':
//..
//  void replace(bsl::ostream&      outputStream,
//               bsl::istream&      inputStream,
//               const bsl::string& oldString,
//               const bsl::string& newString)
//      // Read data from the specified 'inputStream' and replace all
//      // occurrences of the text contained in the specified 'oldString' in
//      // the stream with the text contained in the specified 'newString'.
//      // Write the modified data to the specified 'outputStream'.
//..
// Then, we provide the implementation for 'replace':
//..
//  {
//      const bsl::string::size_type oldStringSize = oldString.size();
//      const bsl::string::size_type newStringSize = newString.size();
//      bsl::string                  line;
//
//      bsl::getline(inputStream, line);
//..
// Notice that we can use the 'getline' free function defined in this component
// to read a single line of data from an input stream into a 'bsl::string'.
//..
//      if (!inputStream) {
//          return;                                                   // RETURN
//      }
//
//      do {
//..
// Next, we use the 'find' function to search the contents of 'line' for
// characters matching the contents of 'oldString':
//..
//          int pos = line.find(oldString);
//          while (bsl::string::npos != pos) {
//..
// Now, we use the 'replace' method to modify the contents of 'line' matching
// 'oldString' to 'newString':
//..
//              line.replace(pos, oldStringSize, newString);
//              pos = line.find(oldString, pos + newStringSize);
//..
// Notice that we provide 'find' with the starting position from which to start
// searching.
//..
//          }
//..
// Finally, we write the updated contents of 'line' to the output stream:
//..
//          outputStream << line;
//
//          bsl::getline(inputStream, line);
//      } while (inputStream);
//  }
//..

#include <bslscm_version.h>

#include <bslstl_hash.h>
#include <bslstl_iterator.h>
#include <bslstl_iteratorutil.h>
#include <bslstl_stdexceptutil.h>
#include <bslstl_stringrefdata.h>
#include <bslstl_stringview.h>

#include <bslalg_containerbase.h>
#include <bslalg_scalarprimitives.h>
#include <bslalg_typetraithasstliterators.h>

#include <bslh_hash.h>

#include <bslma_allocator.h>
#include <bslma_allocatortraits.h>
#include <bslma_isstdallocator.h>
#include <bslma_stdallocator.h>
#include <bslma_usesbslmaallocator.h>

#include <bslmf_assert.h>
#include <bslmf_enableif.h>
#include <bslmf_isbitwisemoveable.h>
#include <bslmf_isconvertible.h>
#include <bslmf_issame.h>
#include <bslmf_matchanytype.h>
#include <bslmf_matcharithmetictype.h>
#include <bslmf_movableref.h>
#include <bslmf_nestedtraitdeclaration.h>
#include <bslmf_nil.h>

#include <bsls_alignedbuffer.h>
#include <bsls_alignment.h>
#include <bsls_alignmentfromtype.h>
#include <bsls_assert.h>
#include <bsls_compilerfeatures.h>
#include <bsls_keyword.h>
#include <bsls_libraryfeatures.h>
#include <bsls_performancehint.h>
#include <bsls_performancehint.h>
#include <bsls_platform.h>

#if defined(BSLS_COMPILERFEATURES_SUPPORT_GENERALIZED_INITIALIZERS)
# include <initializer_list>
#endif

#include <algorithm>  // for 'std::swap'
#include <istream>    // for 'std::basic_istream', 'sentry'
#include <limits>     // for 'std::numeric_limits'
#include <locale>     // for 'std::ctype', 'locale'
#include <ostream>    // for 'std::basic_ostream', 'sentry'
#include <string>     // for 'std::char_traits'

#ifndef BDE_OMIT_INTERNAL_DEPRECATED
#ifndef BDE_DONT_ALLOW_TRANSITIVE_INCLUDES

#include <bsls_nativestd.h>

#include <exception>
#include <stdexcept>

#if defined(BDE_BUILD_TARGET_STLPORT)
// Code in Robo depends on these headers included transitively with <string>
// and it fails to build otherwise in the stlport4 mode on Sun.

# include <stdio.h>
# include <stdlib.h>
# include <string.h>
#endif

#endif // BDE_DONT_ALLOW_TRANSITIVE_INCLUDES
#endif // BDE_OMIT_INTERNAL_DEPRECATED

namespace bsl {

// Import 'char_traits' into the 'bsl' namespace so that 'basic_string' and
// 'char_traits' are always in the same namespace.
using std::char_traits;

template <class CHAR_TYPE,
          class CHAR_TRAITS = char_traits<CHAR_TYPE>,
          class ALLOCATOR   = allocator<CHAR_TYPE> >
class basic_string;

// TYPEDEFS
typedef basic_string<char>     string;
typedef basic_string<wchar_t>  wstring;

#if defined(BSLS_COMPILERFEATURES_SUPPORT_UTF8_CHAR_TYPE)
typedef basic_string<char8_t>  u8string;
#endif

#if defined(BSLS_COMPILERFEATURES_SUPPORT_UNICODE_CHAR_TYPES)
typedef basic_string<char16_t> u16string;
typedef basic_string<char32_t> u32string;
#endif

#if defined(BSLS_LIBRARYFEATURES_STDCPP_LIBCSTD)
template <class ORIGINAL_TRAITS>
class String_Traits {
    // This 'class' provides an implementation of the 'find' function for the
    // (template parameter) type 'ORIGINAL_TRAITS'.  This is an alternate
    // representation for Sun's 'char_traits::find' that returns an incorrect
    // result for character types other than 'char' (such as 'wchar').

    // PRIVATE TYPES
    typedef typename ORIGINAL_TRAITS::char_type char_type;
    typedef std::size_t                         size_type;

  public:
    // CLASS METHODS
    static const char_type *find(const char_type  *s,
                                 size_type         n,
                                 const char_type&  a);
        // Return an address providing non-modifiable access to the first
        // character that matches the specified character 'a' in the specified
        // 'n' characters of the specified 's' string.  The behavior is
        // undefined unless 's' holds at least 'n' characters.
};

template <>
class String_Traits<std::char_traits<char> > {
    // Sun implemented 'find' for 'char' properly, so this specialization
    // simply forwards the call to Sun.

    // PRIVATE TYPES
    typedef std::size_t size_type;

  public:
    // CLASS METHODS
    static const char *find(const char *s, size_type n, const char& a);
        // Return an address providing non-modifiable access to the first
        // character that matches the specified character 'a' in the specified
        // 'n' characters of the specified 's' string.  The behavior is
        // undefined unless 's' holds at least 'n' characters.
};

// CLASS METHODS
template <class ORIGINAL_TRAITS>
const typename ORIGINAL_TRAITS::char_type *
String_Traits<ORIGINAL_TRAITS>::find(const char_type  *s,
                                     size_type         n,
                                     const char_type&  a)
{
    while (n > 0 && !ORIGINAL_TRAITS::eq(*s, a)) {
        --n;
        ++s;
    }
    return n > 0 ? s : 0;
}

inline
const char *
String_Traits<std::char_traits<char> >::find(const char  *s,
                                                    size_type    n,
                                                    const char&  a)
{
    return std::char_traits<char>::find(s, n, a);
}

#define BSLSTL_CHAR_TRAITS String_Traits<CHAR_TRAITS>

#else

#define BSLSTL_CHAR_TRAITS CHAR_TRAITS

#endif

#ifdef BSLS_COMPILERFEATURES_SUPPORT_RVALUE_REFERENCES
// The usual practice of using a 'bslmf::MovableRef<>' cannot be applied, since
// compilers on Solaris cannot compile such heavy code. Therefore, it was
// decided to add 'operator+' accepting rvalue references only for platforms
// and compilers that support them.

#define BSLSTL_STRING_SUPPORT_RVALUE_ADDITION_OPERATORS
#endif

                    // =======================================
                    // struct String_IsConvertibleToStringView
                    // =======================================

template <class CHAR_TYPE, class CHAR_TRAITS, class TYPE>
struct String_IsConvertibleToStringView
: bsl::is_convertible<TYPE, bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS> > {
    // This component-private 'struct' template implements a meta-function to
    // determine if the (template parameter) 'TYPE' is convertible to the
    // 'bsl::string_view<'CHAR_TYPE', CHAR_TRAITS>'.
};

template <class CHAR_TYPE, class CHAR_TRAITS>
struct String_IsConvertibleToStringView<CHAR_TYPE,
                                        CHAR_TRAITS,
                                        const CHAR_TYPE (&)[]>
: bsl::true_type {
    // This partial specialization of 'String_IsConvertibleToStringView' is
    // instantiated when 'const CHAR_TYPE (&)[]' is tested for convertibility
    // to the 'bsl::string_view<'CHAR_TYPE', CHAR_TRAITS>'.
};

                    // ====================================
                    // struct String_IsConvertibleToCString
                    // ====================================

template <class CHAR_TYPE, class TYPE>
struct String_IsConvertibleToCString
: bsl::is_convertible<TYPE, const CHAR_TYPE *> {
    // This component-private 'struct' template implements a meta-function to
    // determine if the (template parameter) 'TYPE' is convertible to the
    // (template parameter) 'const CHAR_TYPE *'.
};


template <class CHAR_TYPE>
struct String_IsConvertibleToCString<CHAR_TYPE, const CHAR_TYPE (&)[]>
: bsl::true_type {
    // This partial specialization of 'String_IsConvertibleToStringView' is
    // instantiated when 'const CHAR_TYPE (&)[]' is tested for convertibility
    // to the 'const CHAR_TYPE *'.
};

#if defined(BSLS_PLATFORM_CMP_MSVC) && BSLS_PLATFORM_CMP_VERSION <= 1900
#define BSLSTL_STRING_DEFINE_STRINGVIEW_LIKE_TYPE_IF_COMPLETE                 \
  const STRING_VIEW_LIKE_TYPE &
    // MSVC 2015's limited SFINAE support means we are cannot use 'sizeof' to
    // detect incomplete types. In this case it is safe to not perform this
    // detection, as it is only required for the C++03 deficiencies in Sun and
    // AIX compilers.
#else
#define BSLSTL_STRING_DEFINE_STRINGVIEW_LIKE_TYPE_IF_COMPLETE                 \
typename bsl::enable_if<0 != sizeof(STRING_VIEW_LIKE_TYPE),                   \
                        const STRING_VIEW_LIKE_TYPE&>::type
    // We need to use an intermediate completeness test to work around
    // deficiencies with SFINAE in the Sun and AIX compilers.
#endif

#define BSLSTL_STRING_DEFINE_ONLY_CONVERTIBLE_TO_STRINGVIEW_RETURN_TYPE       \
    typename bsl::enable_if<                                                  \
        String_IsConvertibleToStringView<                                     \
               CHAR_TYPE,                                                     \
               CHAR_TRAITS,                                                   \
               BSLSTL_STRING_DEFINE_STRINGVIEW_LIKE_TYPE_IF_COMPLETE>::value  \
     && !String_IsConvertibleToCString<                                       \
              CHAR_TYPE,                                                      \
              BSLSTL_STRING_DEFINE_STRINGVIEW_LIKE_TYPE_IF_COMPLETE>::value,  \
         basic_string<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>&>::type

#define BSLSTL_STRING_DECLARE_CONVERTIBLE_TO_STRINGVIEW_PARAM_VOID ,          \
    typename bsl::enable_if<                                                  \
        String_IsConvertibleToStringView<                                     \
               CHAR_TYPE,                                                     \
               CHAR_TRAITS,                                                   \
               BSLSTL_STRING_DEFINE_STRINGVIEW_LIKE_TYPE_IF_COMPLETE>::value  \
    >::type * = 0

#define BSLSTL_STRING_DEFINE_CONVERTIBLE_TO_STRINGVIEW_PARAM_VOID ,           \
    typename bsl::enable_if<                                                  \
        String_IsConvertibleToStringView<                                     \
               CHAR_TYPE,                                                     \
               CHAR_TRAITS,                                                   \
               BSLSTL_STRING_DEFINE_STRINGVIEW_LIKE_TYPE_IF_COMPLETE>::value  \
    >::type *

#define BSLSTL_STRING_DECLARE_ONLY_CONVERTIBLE_TO_STRINGVIEW_PARAM_VOID ,     \
    typename bsl::enable_if<                                                  \
        String_IsConvertibleToStringView<                                     \
               CHAR_TYPE,                                                     \
               CHAR_TRAITS,                                                   \
               BSLSTL_STRING_DEFINE_STRINGVIEW_LIKE_TYPE_IF_COMPLETE>::value  \
     && !String_IsConvertibleToCString<                                       \
              CHAR_TYPE,                                                      \
              BSLSTL_STRING_DEFINE_STRINGVIEW_LIKE_TYPE_IF_COMPLETE>::value   \
    >::type * = 0

#define BSLSTL_STRING_DEFINE_ONLY_CONVERTIBLE_TO_STRINGVIEW_PARAM_VOID ,      \
    typename bsl::enable_if<                                                  \
        String_IsConvertibleToStringView<                                     \
               CHAR_TYPE,                                                     \
               CHAR_TRAITS,                                                   \
               BSLSTL_STRING_DEFINE_STRINGVIEW_LIKE_TYPE_IF_COMPLETE>::value  \
     && !String_IsConvertibleToCString<                                       \
              CHAR_TYPE,                                                      \
              BSLSTL_STRING_DEFINE_STRINGVIEW_LIKE_TYPE_IF_COMPLETE>::value   \
    >::type *

#define BSLSTL_STRING_DECLARE_ONLY_CONVERTIBLE_TO_STRINGVIEW_PARAM_ALLOC ,    \
    typename bsl::enable_if<                                                  \
        String_IsConvertibleToStringView<                                     \
               CHAR_TYPE,                                                     \
               CHAR_TRAITS,                                                   \
               BSLSTL_STRING_DEFINE_STRINGVIEW_LIKE_TYPE_IF_COMPLETE>::value  \
     && !String_IsConvertibleToCString<                                       \
              CHAR_TYPE,                                                      \
              BSLSTL_STRING_DEFINE_STRINGVIEW_LIKE_TYPE_IF_COMPLETE>::value   \
    , const ALLOCATOR&>::type basicAllocator = ALLOCATOR()

#define BSLSTL_STRING_DEFINE_ONLY_CONVERTIBLE_TO_STRINGVIEW_PARAM_ALLOC ,     \
    typename bsl::enable_if<                                                  \
        String_IsConvertibleToStringView<                                     \
               CHAR_TYPE,                                                     \
               CHAR_TRAITS,                                                   \
               BSLSTL_STRING_DEFINE_STRINGVIEW_LIKE_TYPE_IF_COMPLETE>::value  \
     && !String_IsConvertibleToCString<                                       \
              CHAR_TYPE,                                                      \
              BSLSTL_STRING_DEFINE_STRINGVIEW_LIKE_TYPE_IF_COMPLETE>::value   \
    , const ALLOCATOR&>::type basicAllocator

                              // ================
                              // class String_Imp
                              // ================

template <class CHAR_TYPE, class SIZE_TYPE>
class String_Imp {
    // This component private 'class' describes the basic data layout for a
    // string class and provides methods to help encapsulate internal string
    // implementation details.  It is parameterized by 'CHAR_TYPE' and
    // 'SIZE_TYPE' only, and implements the portion of 'basic_string' that does
    // not need to know about its (template parameter) types 'CHAR_TRAITS' or
    // 'ALLOCATOR'.  It contains the following data fields: pointer to string,
    // short string buffer, length, and capacity.  The purpose of the short
    // string buffer is to implement a "short string optimization" such that
    // strings with lengths shorter than a certain number of characters are
    // stored directly inside the string object (inside the short string
    // buffer), and thereby avoid memory allocations/deallocations.

  public:
    // TYPES
    enum ShortBufferConstraints {
        // This 'enum' contains values necessary to calculate the size of the
        // short string buffer.  The starting value is
        // 'SHORT_BUFFER_MIN_BYTES', which defines the minimal number of bytes
        // (or 'char' values) that the short string buffer should be able to
        // contain.  Then this value is aligned to a word boundary.  Then we
        // make sure that it fits at least one 'CHAR_TYPE' character (because
        // the default state of the string object requires that the first
        // character is initialized with a NULL-terminator).  The final output
        // of this enum used by 'String_Imp' is the 'SHORT_BUFFER_CAPACITY'
        // value.  It defines the capacity of the short string buffer and also
        // the capacity of the default-constructed empty string object.

        SHORT_BUFFER_MIN_BYTES  = 20, // minimum required size of the short
                                      // string buffer in bytes

        SHORT_BUFFER_NEED_BYTES =
                              (SHORT_BUFFER_MIN_BYTES + sizeof(SIZE_TYPE) - 1)
                                                    & ~(sizeof(SIZE_TYPE) - 1),
                                    // round it to a word boundary

        SHORT_BUFFER_BYTES      = sizeof(CHAR_TYPE) < SHORT_BUFFER_NEED_BYTES
                                  ? SHORT_BUFFER_NEED_BYTES
                                  : sizeof(CHAR_TYPE),
                                    // in case 'CHAR_TYPE' is very large

        SHORT_BUFFER_LENGTH     = SHORT_BUFFER_BYTES / sizeof(CHAR_TYPE),

        SHORT_BUFFER_CAPACITY   = SHORT_BUFFER_LENGTH - 1
                                    // short string buffer capacity (not
                                    // including the null-terminator)
    };

    // Make sure the buffer is large enough to fit a pointer.
    BSLMF_ASSERT(SHORT_BUFFER_BYTES >= sizeof(CHAR_TYPE *));

    enum ConfigurableParameters {
        // These configurable parameters define various aspects of the string
        // behavior when it's not strictly defined by the Standard.

        BASIC_STRING_DEALLOCATE_IN_CLEAR  = false,
        BASIC_STRING_HONOR_SHRINK_REQUEST = false
    };

    // DATA
    union {
        // This is the union of the string storage options: it can either be
        // stored inside the short string buffer, 'd_short', or in the
        // externally allocated memory, pointed to by 'd_start_p'.

        BloombergLP::bsls::AlignedBuffer<
                        SHORT_BUFFER_BYTES,
                        BloombergLP::bsls::AlignmentFromType<CHAR_TYPE>::VALUE>
                   d_short;     // short string buffer
        CHAR_TYPE *d_start_p;   // pointer to the data on heap
    };

    SIZE_TYPE      d_length;    // length of the string
    SIZE_TYPE      d_capacity;  // capacity to which the string can grow
                                // without reallocation

    // TRAITS
    BSLMF_NESTED_TRAIT_DECLARATION(String_Imp,
                                   BloombergLP::bslmf::IsBitwiseMoveable);
        // 'CHAR_TYPE' is required to be a POD as per the Standard, which makes
        // 'CHAR_TYPE' bitwise-movable, so 'String_Imp' is also
        // bitwise-movable.

    // CLASS METHODS
    static SIZE_TYPE computeNewCapacity(SIZE_TYPE newLength,
                                        SIZE_TYPE oldCapacity,
                                        SIZE_TYPE maxSize);
        // Compute and return the capacity required for a string having the
        // specified 'newLength' and using the specified 'oldCapacity' to
        // exercise an exponential capacity growth necessary to ensure the
        // amortized linear complexity of 'push_back' and other operations and
        // ensuring that the new capacity does not exceed the specified
        // 'maxSize'.  Note that the behavior is undefined unless
        // 'newLength > oldCapacity', 'newLength < maxSize', and
        // 'oldCapacity < maxSize'.

    // CREATORS
    String_Imp();
        // Create a 'String_Imp' object having (default) attribute values
        // except that the 'd_capacity' attribute is initialized with
        // 'SHORT_BUFFER_CAPACITY'.

    String_Imp(SIZE_TYPE length, SIZE_TYPE capacity);
        // Create a 'String_Imp' object and initialize the 'd_length' and
        // 'd_capacity' attributes with the specified 'length' and specified
        // 'capacity', respectively.  If 'capacity' is less than
        // 'SHORT_BUFFER_CAPACITY', then d_capacity is set to
        // 'SHORT_BUFFER_CAPACITY'.  The value of the 'd_short' and 'd_start_p'
        // fields are left uninitialized.  'basic_string' is required to assign
        // either d_short or d_start_p to a proper value before using any
        // methods of this class.

    //! String_Imp(const String_Imp& original) = default;
        // Create a 'String_Imp' object having the same value as the specified
        // 'original' object.  Note that this copy constructor is generated by
        // the compiler.

    //! ~String_Imp() = default;
        // Destroy this object.  Note that this destructor is generated by the
        // compiler.

    //! String_Imp& operator=(const String_Imp& rhs) = default;
        // Assign to this object the value of the specified 'rhs' object, and
        // return a reference providing modifiable access to this object.  Note
        // that this assignment operator is generated by the compiler.

    // MANIPULATORS
    void swap(String_Imp& other);
        // Efficiently exchange the value of this object with the value of the
        // specified 'other' object.  This method provides the no-throw
        // exception-safety guarantee.

    void resetFields();
        // Reset all fields of this object to their default-constructed state.

    CHAR_TYPE *dataPtr();
        // Return an address providing modifiable access to the NULL-terminated
        // C-string stored by this string object.  Note that the returned
        // address can point to either the internal short string buffer or the
        // externally allocated memory depending on the type of the string
        // defined by the return value of 'isShortString'.

    // ACCESSORS
    bool isShortString() const;
        // Return 'true' if this object contains a short string and the string
        // data is stored in the short string buffer, and 'false' if the object
        // contains a long string (and the short string buffer contains a
        // pointer to the string data allocated externally).

    const CHAR_TYPE *dataPtr() const;
        // Return an address providing non-modifiable access to the
        // NULL-terminated C-string stored by this string object.  Note that
        // the returned address can point to either the internal short string
        // buffer or the externally allocated memory depending on the type of
        // the string defined by the return value of 'isShortString'.
};

template<class FULL_STRING_TYPE>
class String_ClearProctor {
    // This component private 'class' implements a proctor that sets the length
    // of a string to zero, and, if 'release' is not called, will restore that
    // string upon it's destruction.  The intended usage is to implement
    // 'assign' methods in terms of 'append' (by clearing the string before
    // appending to it), while maintaining the strong exceptions guarantee.
    // Note that after constructing this proctor for a string 's', the
    // invariant 's[s.length()] == CHAR_TYPE()' is violated for non-empty 's'.
    // This invariant will be restored by either a successful 'append' or by
    // the proctor's destructor if an exception is thrown.  Note that the
    // template parameter was renamed from STRING_TYPE to FULL_STRING_TYPE due
    // to a name clash with a define elsewhere in the code base (see DRQS
    // 112049582).

    // PRIVATE TYPES
    typedef typename FULL_STRING_TYPE::size_type size_type;

    // DATA
    FULL_STRING_TYPE *d_string_p;        // pointer to the string supplied at
                                         // construction (held, not owned)

    size_type         d_originalLength;  // original length of the string
                                         // supplied at construction

  public:
    // CREATORS
    explicit String_ClearProctor(FULL_STRING_TYPE *stringPtr);
        // Create a 'String_ClearProctor' for the specified 'stringPtr', and
        // set both the length of 'stringPtr' to 0 and the first character of
        // 'stringPtr' to 'CHAR_TYPE()'.

    ~String_ClearProctor();
        // Destroy this object, and if 'release' has not been called, restore
        // the original state of the string supplied at construction.

    // MANIPULATORS
    void release();
        // Release the proctor indicating that the string state need not to be
        // restored.
};

                        // =======================
                        // class bsl::basic_string
                        // =======================

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
class basic_string
    : private String_Imp<CHAR_TYPE,
                         typename allocator_traits<ALLOCATOR>::size_type>
    , public BloombergLP::bslalg::ContainerBase<ALLOCATOR>
{
    // This class template provides an STL-compliant 'string' that conforms to
    // the 'bslma::Allocator' model.  For the requirements of a string class,
    // consult the second revision of the ISO/IEC 14882 Programming Language
    // C++ (2003).  Note that the (template parameter) 'CHAR_TYPE' must be
    // *equal* to 'ALLOCATOR::value_type'.  In addition, this implementation
    // offers strong exception guarantees (see below), with the general rules
    // that:
    //
    //: 1 any method that would result in a string of length larger than the
    //:   size returned by 'max_size' throws 'std::length_error', and
    //:
    //: 2 any method that attempts to access a position outside the valid range
    //:   of a string throws 'std::out_of_range'.
    //
    // Circumstances where a method throws 'bsl::length_error' (1) are clear
    // and not repeated in the individual function-level documentations below.
    //
    // More generally, this class supports an almost complete set of *in-core*
    // *value* *semantic* operations, including copy construction, assignment,
    // equality comparison (but excluding 'ostream' printing since this
    // component is below STL).  A precise operational definition of when two
    // objects have the same value can be found in the description of
    // 'operator==' for the class.  This class is *exception* *neutral* with
    // full guarantee of rollback: if an exception is thrown during the
    // invocation of a method on a pre-existing object, the object is left
    // unchanged.  In no event is memory leaked.
    //
    // Note that *aliasing* (e.g., using all or part of an object as both
    // source and destination) is supported in all cases in the public
    // interface of 'basic_string'.  However, the private interface ('...Raw'
    // methods) should be assumed to be not alias-safe unless specifically
    // noted otherwise.

    // PRIVATE TYPES
    typedef BloombergLP::bslmf::MovableRefUtil         MoveUtil;
        // This 'typedef' is a convenient alias for the utility associated with
        // movable references.

    typedef bsl::allocator_traits<ALLOCATOR>           AllocatorTraits;
        // This 'typedef' is an alias for the allocator traits type associated
        // with this container.

  public:
    // PUBLIC TYPES
    typedef CHAR_TRAITS                                traits_type;
    typedef typename CHAR_TRAITS::char_type            value_type;

    typedef ALLOCATOR                                  allocator_type;
    typedef typename AllocatorTraits::size_type        size_type;
    typedef typename AllocatorTraits::difference_type  difference_type;
    typedef typename AllocatorTraits::pointer          pointer;
    typedef typename AllocatorTraits::const_pointer    const_pointer;

    typedef value_type&                                reference;
    typedef const value_type&                          const_reference;
    typedef CHAR_TYPE                                 *iterator;
    typedef const CHAR_TYPE                           *const_iterator;
    typedef bsl::reverse_iterator<iterator>            reverse_iterator;
    typedef bsl::reverse_iterator<const_iterator>      const_reverse_iterator;
        // These types satisfy the 'ReversibleSequence' requirements.

    // TRAITS
    BSLMF_NESTED_TRAIT_DECLARATION_IF(
                      basic_string,
                      BloombergLP::bslmf::IsBitwiseMoveable,
                      BloombergLP::bslmf::IsBitwiseMoveable<ALLOCATOR>::value);
        // 'CHAR_TYPE' is required to be a POD as per the Standard, which makes
        // 'CHAR_TYPE' bitwise-movable, so 'basic_string' is bitwise-movable as
        // long as the (template parameter) type 'ALLOCATOR' is also
        // bitwise-movable.

  private:
    // PRIVATE TYPES
    typedef String_Imp<CHAR_TYPE, size_type>                     Imp;

    typedef BloombergLP::bslalg::ContainerBase<ALLOCATOR>        ContainerBase;

    // FRIENDS
    friend string to_string(int);
    friend string to_string(long);
    friend string to_string(long long);
    friend string to_string(unsigned);
    friend string to_string(unsigned long);
    friend string to_string(unsigned long long);
        // 'to_string' functions are made friends to allow access to the
        // internal short string buffer.

    friend class String_ClearProctor<basic_string>;
        // String_ClearProctor is made friend to allow access to internal
        // buffer and length.

    // PRIVATE CLASS METHODS
    static void privateThrowLengthError(bool        maxLengthExceeded,
                                        const char *message);
        // Throw 'length_error' with the specified 'message' if the specified
        // 'maxLengthExceeded' is 'true'.  Otherwise, this method has no
        // effect.

    static void privateThrowOutOfRange(bool outOfRange, const char *message);
        // Throw 'out_of_range' with the specified 'message' if the specified
        // 'outOfRange' is 'true'.   Otherwise, this method has no effect.

    // PRIVATE MANIPULATORS

    // Note: '...Raw' functions are low level private manipulators and they do
    // not perform checks for exceptions.  '...Dispatch' functions perform
    // overload selection for iterator types in order to resolve ambiguities
    // between template and non-template method overloads.

    CHAR_TYPE *privateAllocate(size_type numChars);
        // Allocate and return a buffer capable of holding the specified
        // 'numChars' number of characters.

    void privateDeallocate();
        // Deallocate the internal string buffer, which was allocated with
        // 'privateAllocate' and stored in 'String_Imp::d_start_p' without
        // modifying any data members.

    void privateCopyFromOutOfPlaceBuffer(const basic_string& original);
        // Copy the specified 'original' string content into this string
        // object, assuming that the default copy constructor of the
        // 'String_Imp' base class and the appropriate copy constructor of the
        // 'ContainerBase' base class have just been run.  The behavior is
        // undefined unless 'original' holds an out-of-place representation of
        // a string.  Note that the out-of-place representation may be short
        // enough to fit into the small buffer storage.

    basic_string& privateAppend(const CHAR_TYPE *characterString,
                                size_type        numChars,
                                const char      *message);
        // Append to this string the specified initial 'numChars' characters
        // from the specified 'characterString', and return a reference
        // providing modifiable access to this string.  Throw 'length_error'
        // with the specified 'message' if 'numChars > max_size() - length()'.
        // The behavior is undefined unless 'characterString' is at least
        // 'numChars' long.

    basic_string& privateAppend(size_type   numChars,
                                CHAR_TYPE   character,
                                const char *message);
        // Append the specified 'numChars' copies of the specified 'character'
        // to this string.  Return a reference providing modifiable access to
        // this string.  Throw 'length_error' with the specified 'message' if
        // 'numChars > max_size() - length()'.

    basic_string& privateAppend(iterator    first,
                                iterator    last,
                                const char *message,
                                std::forward_iterator_tag);
    basic_string& privateAppend(const_iterator  first,
                                const_iterator  last,
                                const char     *message,
                                std::forward_iterator_tag);
        // Append the characters from the string represented by the specified
        // 'first' and 'last' iterators.  Throw 'length_error' with the
        // specified 'message' if 'length() > max_size() - (last - first)'.
        // The behavior is undefined unless 'first' and 'last' refer to a
        // sequence of valid values where 'first' is at a position at or before
        // 'last'.

    template <class INPUT_ITER>
    basic_string& privateAppend(INPUT_ITER  first,
                                INPUT_ITER  last,
                                const char *message,
                                std::input_iterator_tag);
        // Specialized append for input iterators, using repeated 'push_back'
        // operations.   Throw 'length_error' with the specified 'message' if
        // 'length() > max_size() - distance(first, last)'.

    template <class INPUT_ITER>
    basic_string& privateAppend(INPUT_ITER  first,
                                INPUT_ITER  last,
                                const char *message,
                                std::forward_iterator_tag);
        // Specialized append for forward, bidirectional, and random-access
        // iterators.  Throw 'length_error' with the specified 'message' if
        // 'length() > max_size() - distance(first, last)'.

    template<class INPUT_ITER>
    basic_string& privateAppend(INPUT_ITER  first,
                                INPUT_ITER  last,
                                const char *message);
        // Dispatch the append operation to the correct 'privateAppend'
        // overload using 'privateAppendDispatch'.

    template <class INPUT_ITER>
    basic_string& privateAppendDispatch(
                              INPUT_ITER                               first,
                              INPUT_ITER                               last,
                              const char                              *message,
                              BloombergLP::bslmf::MatchArithmeticType,
                              BloombergLP::bslmf::Nil);
        // Match integral type for 'INPUT_ITER'.

    template <class INPUT_ITER>
    basic_string& privateAppendDispatch(
                                     INPUT_ITER                        first,
                                     INPUT_ITER                        last,
                                     const char                       *message,
                                     BloombergLP::bslmf::MatchAnyType,
                                     BloombergLP::bslmf::MatchAnyType);
        // Match non-integral type for 'INPUT_ITER'.

    template<class FIRST_TYPE, class SECOND_TYPE>
    basic_string& privateAssignDispatch(FIRST_TYPE   first,
                                        SECOND_TYPE  second,
                                        const char  *message);
        // Assign to this string the value of the string described by the
        // specified 'first' and 'second' values, and return a reference
        // providing modifiable access to this string.  The (template
        // parameter) types 'FIRST_TYPE' and 'SECOND_TYPE' may resolve to
        // 'const CHAR_TYPE *' and 'size_type', 'size_type' and 'CHAR_TYPE', or
        // a pair of iterators.  This method clears the string and then
        // dispatches to the corresponding 'privateAppend' function.  Throw
        // 'length_error' with the specified 'message' if the length of the
        // string described by 'first' and 'second' is greater than
        // 'max_size()'.

    Imp& privateBase();
        // Return a reference providing modifiable access to the base object
        // of this string.

    void privateClear(bool deallocateBufferFlag);
        // Reset this string object to its default-constructed value and
        // deallocate its string buffer if the specified 'deallocateBufferFlag'
        // is 'true'.

    void privateInsertDispatch(const_iterator position,
                               iterator       first,
                               iterator       last);
    void privateInsertDispatch(const_iterator position,
                               const_iterator first,
                               const_iterator last);
        // Insert into this object at the specified 'position' a string
        // represented by the specified 'first' and 'last' iterators using the
        // 'privateInsertRaw' method for insertion.  The behavior is undefined
        // unless 'first' and 'last' refer to a sequence of valid values where
        // 'first' is at a position at or before 'last'.

    template <class INPUT_ITER>
    void privateInsertDispatch(const_iterator position,
                               INPUT_ITER     first,
                               INPUT_ITER     last);
        // Insert into this object at the specified 'position' a string
        // represented by the specified 'first' and 'last' iterators.  The
        // behavior is undefined unless 'first' and 'last' refer to a sequence
        // of valid values where 'first' is at a position at or before 'last'.
        // Note that since the (template parameter) type 'INPUT_ITER' can also
        // resolve to an integral type, use the 'privateReplaceDispatch' to
        // disambiguate between the integral type and iterator types.

    basic_string& privateInsertRaw(size_type        outPosition,
                                   const CHAR_TYPE *characterString,
                                   size_type        numChars);
        // Insert into this object at the specified 'outPosition' the specified
        // initial 'numChars' from the specified 'characterString'.  The
        // behavior is undefined unless 'numChars <= max_size() - length()' and
        // 'characterString' is at least 'numChars' long.  Note that this
        // method is alias-safe, i.e., it works correctly even if
        // 'characterString' points into this string object.

    basic_string& privateReplaceRaw(size_type        outPosition,
                                    size_type        outNumChars,
                                    const CHAR_TYPE *characterString,
                                    size_type        numChars);
        // Replace the specified 'outNumChars' characters of this string
        // starting at the specified 'outPosition' with the specified initial
        // 'numChars' from the specified 'characterString', and return a
        // reference providing modifiable access to this string.  The behavior
        // is undefined unless 'outPosition <= length()',
        // 'outNumChars <= length()', 'outPosition <= length() - outNumChars',
        // 'numChars <= max_size()',
        // 'length() - outNumChars <= max_size() - numChars', and
        // 'characterString' is at least 'numChars' long.  Note that this
        // method is alias-safe, i.e., it works correctly even if
        // 'characterString' points into this string object.

    basic_string& privateReplaceRaw(size_type outPosition,
                                    size_type outNumChars,
                                    size_type numChars,
                                    CHAR_TYPE character);
        // Replace the specified 'outNumChars' characters of this string
        // starting at the specified 'outPosition' with the specified
        // 'numChars' copies of the specified 'character', and return a
        // reference providing modifiable access to this string.  The behavior
        // is undefined unless 'outPosition <= length()',
        // 'outNumChars <= length()', 'outPosition <= length() - outNumChars',
        // and 'length() <= max_size() - numChars'.

    template <class INPUT_ITER>
    basic_string& privateReplaceDispatch(
                              size_type                               position,
                              size_type                               numChars,
                              INPUT_ITER                              first,
                              INPUT_ITER                              last,
                              BloombergLP::bslmf::MatchArithmeticType ,
                              BloombergLP::bslmf::Nil                 );
        // Match integral type for 'INPUT_ITER'.

    template <class INPUT_ITER>
    basic_string& privateReplaceDispatch(
                                     size_type                        position,
                                     size_type                        numChars,
                                     INPUT_ITER                       first,
                                     INPUT_ITER                       last,
                                     BloombergLP::bslmf::MatchAnyType ,
                                     BloombergLP::bslmf::MatchAnyType );
        // Match non-integral type for 'INPUT_ITER'.

    template <class INPUT_ITER>
    basic_string& privateReplace(size_type  position,
                                 size_type  numChars,
                                 INPUT_ITER first,
                                 INPUT_ITER last,
                                 std::input_iterator_tag);
        // Specialized replacement for input iterators, using repeated
        // 'push_back' operations.

    template <class INPUT_ITER>
    basic_string& privateReplace(size_type  position,
                                 size_type  numChars,
                                 INPUT_ITER first,
                                 INPUT_ITER last,
                                 std::forward_iterator_tag);
        // Specialized replacement for forward, bidirectional, and
        // random-access iterators.  Throw 'length_error' if
        // 'length() - numChars > max_size() - distance(first, last)'.

    basic_string& privateReplace(size_type      position,
                                 size_type      numChars,
                                 iterator       first,
                                 iterator       last,
                                 std::forward_iterator_tag);
    basic_string& privateReplace(size_type      position,
                                 size_type      numChars,
                                 const_iterator first,
                                 const_iterator last,
                                 std::forward_iterator_tag);
        // Replace the specified 'numChars' characters of this object starting
        // at the specified 'position' with the string represented by the
        // specified 'first' and 'last' iterators.  The behavior is undefined
        // unless 'first' and 'last' refer to a sequence of valid values where
        // 'first' is at a position at or before 'last'.

    void privateReserveRaw(size_type newCapacity);
        // Update the capacity of this object to be a value greater than or
        // equal to the specified 'newCapacity'.  The behavior is undefined
        // unless 'newCapacity <= max_size()'.  Note that a null-terminating
        // character is not counted in 'newCapacity', and that this method has
        // no effect unless 'newCapacity > capacity()'.

    CHAR_TYPE *privateReserveRaw(size_type *storage,
                                 size_type  newCapacity,
                                 size_type  numChars);
        // Update the capacity of this object and load into the specified
        // 'storage' to be a value greater than or equal to the specified
        // 'newCapacity'.  Upon reallocation, copy the first specified
        // 'numChars' from the previous buffer to the new buffer, and load
        // 'storage' with the new capacity.  If '*storage >= newCapacity', this
        // method has no effect.  Return the new buffer if reallocation, and 0
        // otherwise.  The behavior is undefined unless 'numChars <= length()'
        // and 'newCapacity <= max_size()'.  Note that a null-terminating
        // character is not counted in '*storage' nor 'newCapacity'.  Also note
        // that the previous buffer is *not* deallocated, nor is the string
        // representation changed (in case the previous buffer may contain data
        // that must be copied): it is the responsibility of the caller to do
        // so upon reallocation.

    basic_string& privateResizeRaw(size_type newLength, CHAR_TYPE character);
        // Change the length of this string to the specified 'newLength'.  If
        // 'newLength > length()', fill in the new positions by copies of the
        // specified 'character'.  Do not change the capacity unless
        // 'newLength' exceeds the current capacity.  The behavior is undefined
        // unless 'newLength <= max_size()'.

    void quickSwapExchangeAllocators(basic_string& other);
        // Efficiently exchange the value and allocator of this object with the
        // value and allocator of the specified 'other' object.  This method
        // provides the no-throw exception-safety guarantee, *unless* swapping
        // the allocator objects can throw.  Note that this method should not
        // be called unless the allocator traits support allocator propagation.

    void quickSwapRetainAllocators(basic_string& other);
        // Efficiently exchange the value of this object with the value of the
        // specified 'other' object.  This method provides the no-throw
        // exception-safety guarantee.  The behavior is undefined unless
        // '*this' and 'other' allocators compare equal.

    // PRIVATE ACCESSORS
    int privateCompareRaw(size_type        lhsPosition,
                          size_type        lhsNumChars,
                          const CHAR_TYPE *other,
                          size_type        otherNumChars) const;
        // Lexicographically compare the substring of this string starting at
        // the specified 'lhsPosition' of length 'lhsNumChars' with the
        // specified initial 'otherNumChars' characters in the specified
        // 'other' string, and return a negative value if the indicated
        // substring of this string is less than 'other', a positive value if
        // it is greater than 'other', and 0 in case of equality.  The behavior
        // is undefined unless 'lhsPosition <= length()',
        // 'lhsNumChars <= length()', and
        // 'lhsPosition <= length() - lhsNumChars'.

    // INVARIANTS
    BSLMF_ASSERT((bsl::is_same<CHAR_TYPE,
                               typename ALLOCATOR::value_type>::value));
        // This is required by the C++ standard (23.1, clause 1).

  public:
    // PUBLIC CLASS DATA
    static const size_type npos = ~size_type(0);
        // Value used to denote "not-a-position", guaranteed to be outside the
        // range '[0 .. max_size()]'.

    // CREATORS

                   // *** 21.3.2 construct/copy/destroy: ***

    basic_string() BSLS_KEYWORD_NOEXCEPT;
    explicit basic_string(const ALLOCATOR& basicAllocator)
                                                         BSLS_KEYWORD_NOEXCEPT;
        // Create an empty string.  Optionally specify the 'basicAllocator'
        // used to supply memory.  If 'basicAllocator' is not specified, a
        // default-constructed allocator is used.

    basic_string(const basic_string& original);
        // Create a string that has the same value as the specified 'original'
        // string.  Use the allocator returned by
        // 'bsl::allocator_traits<ALLOCATOR>::
        // select_on_container_copy_construction(original.get_allocator())' to
        // supply memory.

    basic_string(const basic_string& original,
                 const ALLOCATOR&    basicAllocator);
        // Create a string that has the same value as the specified 'original'
        // string and uses the specified 'basicAllocator' to supply memory.
        //
        // Note that it is important to have two copy constructors instead of a
        // single:
        //..
        //  basic_string(const basic_string& original,
        //               const ALLOCATOR&    basicAllocator = ALLOCATOR());
        //..
        // When the copy constructor with the default allocator is used, xlC10
        // gets confused and refuses to use the return value optimization,
        // which then causes extra allocations when returning by value in
        // 'operator+'.

    basic_string(BloombergLP::bslmf::MovableRef<basic_string> original)
                                                         BSLS_KEYWORD_NOEXCEPT;
        // Create a string that has the same value as the specified 'original'
        // string by moving (in constant time) the contents of 'original' to
        // the new string.  The allocator associated with 'original' is
        // propagated for use in the newly-created string.  'original' is left
        // in a valid but unspecified state.

    basic_string(BloombergLP::bslmf::MovableRef<basic_string> original,
                 const ALLOCATOR&                             basicAllocator);
        // Create a string that has the same value as the specified 'original'
        // string that uses the specified 'basicAllocator' to supply memory.
        // The contents of 'original' are moved (in constant time) to the new
        // string if 'basicAllocator == original.get_allocator()', and are
        // copied (in linear time) using 'basicAllocator' otherwise.
        // 'original' is left in a valid but unspecified state.

    basic_string(const basic_string& original,
                 size_type           position,
                 const ALLOCATOR&    basicAllocator = ALLOCATOR());
        // Create a string that has the same value as the substring starting at
        // the specified 'position' in the specified 'original' string.
        // Optionally specify the 'basicAllocator' used to supply memory.  If
        // 'basicAllocator' is not specified, a default-constructed allocator
        // is used.  Throw 'out_of_range' if 'position > original.length()'.

    basic_string(const basic_string& original,
                 size_type           position,
                 size_type           numChars,
                 const ALLOCATOR&    basicAllocator = ALLOCATOR());
        // Create a string that has the same value as the substring of the
        // specified 'numChars' length starting at the specified 'position' in
        // the specified 'original' string.  If 'numChars' equals 'npos', then
        // the remaining length of the string is used (i.e., 'numChars' is set
        // to 'original.length() - position').  Optionally specify the
        // 'basicAllocator' used to supply memory.  If 'basicAllocator' is not
        // specified, a default-constructed allocator is used.  Throw
        // 'out_of_range' if 'position > original.length()'.

#ifdef BSLS_COMPILERFEATURES_SUPPORT_CTAD
    template <class = bsl::enable_if_t<bsl::IsStdAllocator<ALLOCATOR>::value>>
#endif
    basic_string(const CHAR_TYPE  *characterString,
                 const ALLOCATOR&  basicAllocator = ALLOCATOR());   // IMPLICIT
        // Create a string having the same value as the specified
        // null-terminated 'characterString' (of length
        // 'CHAR_TRAITS::length(characterString)').  Optionally specify a
        // 'basicAllocator' used to supply memory.  If 'basicAllocator' is not
        // specified, a default-constructed allocator is used.

    basic_string(const CHAR_TYPE  *characterString,
                 size_type         numChars,
                 const ALLOCATOR&  basicAllocator = ALLOCATOR());
        // Create a string that has the same value as the substring of the
        // optionally specified 'numChars' length starting at the beginning of
        // the specified 'characterString'.  If 'numChars' is not specified,
        // 'CHAR_TRAITS::length(characterString)' is used.  Optionally specify
        // the 'basicAllocator' used to supply memory.  If 'basicAllocator' is
        // not specified, a default-constructed allocator is used.  Throw
        // 'out_of_range' if 'numChars >= npos'.

#ifdef BSLS_COMPILERFEATURES_SUPPORT_CTAD
    template <class = bsl::enable_if_t<bsl::IsStdAllocator<ALLOCATOR>::value>>
#endif
    basic_string(size_type        numChars,
                 CHAR_TYPE        character,
                 const ALLOCATOR& basicAllocator = ALLOCATOR());
        // Create a string of the specified 'numChars' length whose every
        // position contains the specified 'character'.  Optionally specify a
        // 'basicAllocator' used to supply memory.  If 'basicAllocator' is not
        // specified, a default-constructed allocator is used.

    template <class INPUT_ITER>
    basic_string(INPUT_ITER       first,
                 INPUT_ITER       last,
                 const ALLOCATOR& basicAllocator = ALLOCATOR());
        // Create a string from the characters in the range starting at the
        // specified 'first' iterator and ending right before the specified
        // 'last' iterator of the (template parameter) type 'INPUT_ITER'.
        // Optionally specify a 'basicAllocator' used to supply memory.  If
        // 'basicAllocator' is not specified, a default-constructed allocator
        // is used.  The behavior is undefined unless 'first' and 'last' refer
        // to a sequence of valid values where 'first' is at a position at or
        // before 'last'.

    template <class ALLOC2>
    basic_string(
               const std::basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOC2>& original,
               const ALLOCATOR& basicAllocator = ALLOCATOR());      // IMPLICIT
        // Create a string that has the same value as the specified 'original'
        // string, where the type 'original' is the string type native to the
        // compiler's library, instantiated with the same character type and
        // traits type, but not necessarily the same allocator type.  The
        // resulting string will contain the same sequence of characters as
        // 'original'.  Optionally specify a 'basicAllocator' used to supply
        // memory.  If 'basicAllocator' is not specified, then a
        // default-constructed allocator is used.

    basic_string(const BloombergLP::bslstl::StringRefData<CHAR_TYPE>& strRef,
                 const ALLOCATOR& basicAllocator = ALLOCATOR());    // IMPLICIT
        // Create a string that has the same value as the specified 'strRef'
        // string.  The resulting string will contain the same sequence of
        // characters as 'strRef'.  Optionally specify a 'basicAllocator' used
        // to supply memory.  If 'basicAllocator' is not specified, then a
        // default-constructed allocator is used.

    template <class STRING_VIEW_LIKE_TYPE>
    explicit basic_string(
             const STRING_VIEW_LIKE_TYPE& object
             BSLSTL_STRING_DECLARE_ONLY_CONVERTIBLE_TO_STRINGVIEW_PARAM_ALLOC);
        // Create a string that has the same value as the specified 'object'.
        // Optionally specify a 'basicAllocator' used to supply memory.  If
        // 'basicAllocator' is not specified, then a default-constructed
        // allocator is used.

    template <class STRING_VIEW_LIKE_TYPE>
    basic_string(const STRING_VIEW_LIKE_TYPE& object,
                 size_type                    position,
                 size_type                    numChars,
                 const ALLOCATOR&             basicAllocator = ALLOCATOR()
                 BSLSTL_STRING_DECLARE_CONVERTIBLE_TO_STRINGVIEW_PARAM_VOID);
        // Create a string that has the same value as the substring of the
        // specified 'numChars' length starting at the specified 'position' in
        // the specified 'object'.  Optionally specify a 'basicAllocator' used
        // to supply memory.  If the 'basicAllocator' is not specified, a
        // default-constructed allocator is used.  Throw 'out_of_range' if
        // 'position > original.object()'.

#if defined(BSLS_COMPILERFEATURES_SUPPORT_GENERALIZED_INITIALIZERS)
    basic_string(std::initializer_list<CHAR_TYPE> values,
                 const ALLOCATOR&                 basicAllocator =
                                                                  ALLOCATOR());
        // Create a string and insert (in order) each 'CHAR_TYPE' object in the
        // specified 'values' initializer list.  Optionally specify a
        // 'basicAllocator' used to supply memory.  If 'basicAllocator' is not
        // specified, then a default-constructed allocator is used.
#endif

    ~basic_string();
        // Destroy this string object.

    // MANIPULATORS

                    // *** 21.3.2 construct/copy/destroy: ***

    basic_string& operator=(const basic_string& rhs);
        // Assign to this string the value of the specified 'rhs' string,
        // propagate to this object the allocator of 'rhs' if the 'ALLOCATOR'
        // type has trait 'propagate_on_container_copy_assignment', and return
        // a reference providing modifiable access to this string.

    basic_string& operator=(BloombergLP::bslmf::MovableRef<basic_string> rhs)
        BSLS_KEYWORD_NOEXCEPT_SPECIFICATION(
            AllocatorTraits::propagate_on_container_move_assignment::value ||
            AllocatorTraits::is_always_equal::value);
        // Assign to this string the value of the specified 'rhs' string,
        // propagate to this object the allocator of 'rhs' if the 'ALLOCATOR'
        // type has trait 'propagate_on_container_move_assignment', and return
        // a reference providing modifiable access to this string.  The content
        // of 'rhs' is moved (in constant time) to this string if
        // 'get_allocator() == rhs.get_allocator()' (after accounting for the
        // aforementioned trait).  'rhs' is left in a valid but unspecified
        // state.

    template <class STRING_VIEW_LIKE_TYPE>
    BSLSTL_STRING_DEFINE_ONLY_CONVERTIBLE_TO_STRINGVIEW_RETURN_TYPE
    operator=(const STRING_VIEW_LIKE_TYPE& rhs);
        // Assign to this string the value of the specified 'rhs' object, and
        // return a reference providing modifiable access to this string.

    basic_string& operator=(const CHAR_TYPE *rhs);
        // Assign to this string the value of the specified null-terminated
        // 'rhs' string (of length 'CHAR_TRAITS::length(characterString)'), and
        // return a reference providing modifiable access to this string.

    basic_string& operator=(CHAR_TYPE character);
        // Assign to this string the value of the string of length one
        // consisting of the specified 'character', and return a reference
        // providing modifiable access to this string.

    template <class ALLOC2>
    basic_string& operator=(
                 const std::basic_string<CHAR_TYPE, CHAR_TRAITS, ALLOC2>& rhs);
        // Assign to this string the value of the specified 'rhs' string, and
        // return a reference providing modifiable access to this string.

#if defined(BSLS_COMPILERFEATURES_SUPPORT_GENERALIZED_INITIALIZERS)
    basic_string& operator=(std::initializer_list<CHAR_TYPE> values);
        // Assign to this string the value resulting from first clearing this
        // string and then inserting (in order) each 'CHAR_TYPE' object in the
        // specified 'values' initializer list.
#endif

                          // *** 21.3.4 capacity: ***

    void resize(size_type newLength, CHAR_TYPE character);
        // Change the length of this string to the specified 'newLength',
        // erasing characters at the end if 'newLength < length()' or appending
        // the appropriate number of copies of the specified 'character' at the
        // end if 'length() < newLength'.

    void resize(size_type newLength);
        // Change the length of this string to the specified 'newLength',
        // erasing characters at the end if 'newLength < length()' or appending
        // the appropriate number of copies of 'CHAR_TYPE()' at the end if
        // 'length() < newLength'.

    void reserve(size_type newCapacity = 0);
        // Change the capacity of this string to the specified 'newCapacity'.
        // Note that the capacity of a string is the maximum length it can
        // accommodate without reallocation.  The actual storage allocated may
        // be higher.

    void shrink_to_fit();
        // Request the removal of unused capacity by causing reallocation.
        // Note that this method has no effect if the capacity is equal to the
        // size.  Also note that if (and only if) reallocation occurs, all
        // iterators, including the past the end iterator, and all references
        // to the elements are invalidated.

    void clear() BSLS_KEYWORD_NOEXCEPT;
        // Reset this string to an empty value.  Note that the capacity may
        // change (or not if 'BASIC_STRING_DEALLOCATE_IN_CLEAR' is 'false').
        // Note that the Standard doesn't allow to reduce capacity on 'clear'.

                          // *** 21.3.3 iterators: ***

    iterator begin() BSLS_KEYWORD_NOEXCEPT;
        // Return an iterator referring to the first character in this
        // modifiable string (or the past-the-end iterator if this string is
        // empty).

    iterator end() BSLS_KEYWORD_NOEXCEPT;
        // Return the past-the-end iterator for this modifiable string.

    reverse_iterator rbegin() BSLS_KEYWORD_NOEXCEPT;
        // Return a reverse iterator referring to the last character in this
        // modifiable string (or the past-the-end reverse iterator if this
        // string is empty).

    reverse_iterator rend() BSLS_KEYWORD_NOEXCEPT;
        // Return the past-the-end reverse iterator for this modifiable string.

                       // *** 21.3.5 element access: ***

    reference operator[](size_type position);
        // Return a reference providing modifiable access to the character at
        // the specified 'position' in this string if 'position < length()', or
        // a reference providing non-modifiable access to the null-terminating
        // character if 'position == length()'.  The behavior is undefined
        // unless 'position <= length()', and, in the case of
        // 'position == length()', the null-terminating character is not
        // modified through the returned reference.

    reference at(size_type position);
        // Return a reference providing modifiable access to the character at
        // the specified 'position' in this string.  Throw 'out_of_range' if
        // 'position >= length()'.

    CHAR_TYPE& front();
        // Return a reference providing modifiable access to the character at
        // the first position in this string.  The behavior is undefined if
        // this string is empty.

    CHAR_TYPE& back();
        // Return a reference providing modifiable access to the character at
        // the last position in this string.  The behavior is undefined if this
        // string is empty.  Note that the last position is 'length() - 1'.

                         // *** 21.3.6 modifiers: ***

    basic_string& operator+=(const basic_string& rhs);
        // Append the specified 'rhs' string to this string, and return a
        // reference providing modifiable access to this string.

    basic_string& operator+=(const CHAR_TYPE *rhs);
        // Append the specified null-terminated 'rhs' string (of length
        // 'CHAR_TRAITS::length(rhs)') to this string, and return a reference
        // providing modifiable access to this string.

    basic_string& operator+=(CHAR_TYPE character);
        // Append the specified 'character' to this string, and return a
        // reference providing modifiable access to this string.

    template <class STRING_VIEW_LIKE_TYPE>
    BSLSTL_STRING_DEFINE_ONLY_CONVERTIBLE_TO_STRINGVIEW_RETURN_TYPE
    operator+=(const STRING_VIEW_LIKE_TYPE& rhs);
        // Append the specified 'rhs' to this string, and return a reference
        // providing modifiable access to this string.

    template <class ALLOC2>
    basic_string& operator+=(
                 const std::basic_string<CHAR_TYPE, CHAR_TRAITS, ALLOC2>& rhs);
        // Append the specified 'rhs' string to this string, and return a
        // reference providing modifiable access to this string.

    basic_string& append(const basic_string& suffix);
        // Append to this string the specified 'suffix', and return a reference
        // providing modifiable access to this string.

    basic_string& append(const basic_string& suffix,
                         size_type           position,
                         size_type           numChars = npos);
        // Append to this string the optionally specified 'numChars' characters
        // starting at the specified 'position' in the specified 'suffix', or
        // the tail of 'suffix' starting at 'position' if
        // 'position + numChars > suffix.length()'.  If 'numChars' is not
        // specified, 'npos' is used.  Return a reference providing modifiable
        // access to this string.  Throw 'out_of_range' if
        // 'position > suffix.length()'.

    basic_string& append(const CHAR_TYPE *characterString,
                         size_type        numChars);
        // Append to this string the specified initial 'numChars' characters
        // from the specified 'characterString', and return a reference
        // providing modifiable access to this string.  The behavior is
        // undefined unless 'characterString' is at least 'numChars' long.

    basic_string& append(const CHAR_TYPE *characterString);
        // Append the specified null-terminated 'characterString' (of length
        // 'CHAR_TRAITS::length(characterString)') to this string, and return a
        // reference providing modifiable access to this string.

    basic_string& append(size_type numChars, CHAR_TYPE character);
        // Append the specified 'numChars' copies of the specified 'character'
        // to this string, and return a reference providing modifiable access
        // to this string.

    template <class STRING_VIEW_LIKE_TYPE>
    BSLSTL_STRING_DEFINE_ONLY_CONVERTIBLE_TO_STRINGVIEW_RETURN_TYPE
    append(const STRING_VIEW_LIKE_TYPE& suffix);
        // Append to this string the 'bsl::string_view' object, obtained from
        // the specified 'suffix', and return a reference providing modifiable
        // access to this string.  Throw 'length_error' if the length of the
        // resulting string exceeds 'max_size()'.

    template <class STRING_VIEW_LIKE_TYPE>
    BSLSTL_STRING_DEFINE_ONLY_CONVERTIBLE_TO_STRINGVIEW_RETURN_TYPE
    append(const STRING_VIEW_LIKE_TYPE& suffix,
           size_type                    position,
           size_type                    numChars = npos);
        // Append to this string the optionally specified 'numChars' characters
        // starting at the specified 'position' in the 'bsl::string_view'
        // object, obtained from the specified 'suffix', or its tail starting
        // at 'position' if 'numChars' exceeds the length of this tail.  If
        // 'numChars' is not specified, 'npos' is used.  Return a reference
        // providing modifiable access to this string.  Throw 'out_of_range' if
        // 'position > strView.length()'.  Throw 'length_error' if the length
        // of the resulting string exceeds 'max_size()'.

    template <class INPUT_ITER>
    basic_string& append(INPUT_ITER first, INPUT_ITER last);
        // Append to this string the characters in the range starting at the
        // specified 'first' iterator and ending right before the specified
        // 'last' iterator of the (template parameter) type 'INPUT_ITER'.
        // Return a reference providing modifiable access to this string.  The
        // behavior is undefined unless 'first' and 'last' refer to a sequence
        // of valid values where 'first' is at a position at or before 'last'.

#if defined(BSLS_COMPILERFEATURES_SUPPORT_GENERALIZED_INITIALIZERS)
    basic_string& append(std::initializer_list<CHAR_TYPE> values);
        // Append to this string each 'CHAR_TYPE' object in the specified
        // 'values' initializer list, and return a reference providing
        // modifiable access to this string.
#endif

    void push_back(CHAR_TYPE character);
        // Append the specified 'character' to this string.

    basic_string& assign(const basic_string& replacement);
        // Assign to this string the value of the specified 'replacement'
        // string, propagate to this object the allocator of 'replacement' if
        // the 'ALLOCATOR' type has trait
        // 'propagate_on_container_copy_assignment', and return a reference
        // providing modifiable access to this string.  Note that this method
        // has exactly the same behavior as the corresponding 'operator='.

    basic_string& assign(
                      BloombergLP::bslmf::MovableRef<basic_string> replacement)
                                    BSLS_KEYWORD_NOEXCEPT_SPECIFICATION(false);
        // Assign to this string the value of the specified 'replacement'
        // string, propagate to this object the allocator of 'replacement' if
        // the 'ALLOCATOR' type has trait
        // 'propagate_on_container_move_assignment', and return a reference
        // providing modifiable access to this string.  The content of
        // 'replacement' is moved (in constant time) to this string if
        // 'get_allocator() == rhs.get_allocator()' (after accounting for the
        // aforementioned trait).  'replacement' is left in a valid but
        // unspecified state.  Note that this method has exactly the same
        // behavior as the corresponding 'operator='.

    basic_string& assign(const basic_string& replacement,
                         size_type           position,
                         size_type           numChars = npos);
        // Assign to this string the value of the optionally specified
        // 'numChars' characters starting at the specified 'position' in the
        // specified 'replacement' string, or the suffix of 'replacement'
        // starting at 'position' if
        // 'position + numChars > replacement.length()'.  If 'numChars' is not
        // specified, 'npos' is used.  Return a reference providing modifiable
        // access to this string.  Throw 'out_of_range' if
        // 'position > replacement.length()'.

    basic_string& assign(const CHAR_TYPE *characterString);
        // Assign to this string the value of the specified null-terminated
        // 'characterString' (of length
        // 'CHAR_TRAITS::length(characterString)'), and return a reference
        // providing modifiable access to this string.

    basic_string& assign(const CHAR_TYPE *characterString,
                         size_type        numChars);
        // Assign to this string the specified initial 'numChars' characters in
        // the specified 'characterString', and return a reference providing
        // modifiable access to this string.  The behavior is undefined unless
        // 'characterString' is at least 'numChars' long.

    template <class STRING_VIEW_LIKE_TYPE>
    BSLSTL_STRING_DEFINE_ONLY_CONVERTIBLE_TO_STRINGVIEW_RETURN_TYPE
    assign(const STRING_VIEW_LIKE_TYPE& replacement);
        // Assign to this string the value of the specified 'replacement', and
        // return a reference providing modifiable access to this string.  Note
        // that this method has exactly the same behavior as the corresponding
        // 'operator='.

    template <class STRING_VIEW_LIKE_TYPE>
    BSLSTL_STRING_DEFINE_ONLY_CONVERTIBLE_TO_STRINGVIEW_RETURN_TYPE
    assign(const STRING_VIEW_LIKE_TYPE& replacement,
           size_type                    position,
           size_type                    numChars = npos);
        // Assign to this string the value of the optionally specified
        // 'numChars' characters starting at the specified 'position' in the
        // specified 'replacement', or the suffix of the 'replacement' starting
        // at 'position' if 'position + numChars > replacement.length()'.  If
        // 'numChars' is not specified, 'npos' is used.  Return a reference
        // providing modifiable access to this string.  Throw 'out_of_range' if
        // 'position > replacement.length()'.

    template <class ALLOC2>
    basic_string& assign(
              const std::basic_string<CHAR_TYPE, CHAR_TRAITS, ALLOC2>& string);
        // Assign to this string the value of the specified 'string', and
        // return a reference providing modifiable access to this string.

    basic_string& assign(size_type numChars, CHAR_TYPE character);
        // Assign to this string the value of a string of the specified
        // 'numChars' length whose every character is equal to the specified
        // 'character', and return a reference providing modifiable access to
        // this string.

    template <class INPUT_ITER>
    basic_string& assign(INPUT_ITER first, INPUT_ITER last);
        // Assign to this string the characters in the range starting at the
        // specified 'first' iterator and ending right before the specified
        // 'last' iterator of the (template parameter) type 'INPUT_ITER'.
        // Return a reference providing modifiable access to this string.  The
        // behavior is undefined unless 'first' and 'last' refer to a sequence
        // of valid values where 'first' is at a position at or before 'last'.

#if defined(BSLS_COMPILERFEATURES_SUPPORT_GENERALIZED_INITIALIZERS)
    basic_string& assign(std::initializer_list<CHAR_TYPE> values);
        // Assign to this string the value resulting from first clearing this
        // string and then inserting (in order) each 'CHAR_TYPE' object in the
        // specified 'values' initializer list.  Return a reference providing
        // modifiable access to this string.
#endif

    basic_string& insert(size_type position, const basic_string& other);
        // Insert at the specified 'position' in this string a copy of the
        // specified 'other' string, and return a reference providing
        // modifiable access to this string.  Throw 'out_of_range' if
        // 'position > length()'.

    basic_string& insert(size_type           position,
                         const basic_string& other,
                         size_type           sourcePosition,
                         size_type           numChars = npos);
        // Insert at the specified 'position' in this string the optionally
        // specified 'numChars' characters starting at the specified
        // 'sourcePosition' in the specified 'other' string, or the suffix of
        // 'other' starting at 'sourcePosition' if
        // 'sourcePosition + numChars > other.length()'.  If 'numChars' is not
        // specified, 'npos' is used.  Return a reference providing modifiable
        // access to this string.  Throw 'out_of_range' if
        // 'position > length()' or 'sourcePosition > other.length()'.

    basic_string& insert(size_type        position,
                         const CHAR_TYPE *characterString,
                         size_type        numChars);
        // Insert at the specified 'position' in this string the specified
        // initial 'numChars' characters in the specified 'characterString',
        // and return a reference providing modifiable access to this string.
        // Throw 'out_of_range' if 'position > length()'.  The behavior is
        // undefined unless 'characterString' is at least 'numChars' long.

    basic_string& insert(size_type        position,
                         const CHAR_TYPE *characterString);
        // Insert at the specified 'position' in this string the specified
        // null-terminated 'characterString' (of length
        // 'CHAR_TRAITS::length(characterString)'), and return a reference
        // providing modifiable access to this string.  Throw 'out_of_range' if
        // 'position > length()'.

    basic_string& insert(size_type position,
                         size_type numChars,
                         CHAR_TYPE character);
        // Insert at the specified 'position' in this string the specified
        // 'numChars' copies of the specified 'character', and return a
        // reference providing modifiable access to this string.  Throw
        // 'out_of_range' if 'position > length()'.

    iterator insert(const_iterator position, CHAR_TYPE character);
        // Insert the specified 'character' at the specified 'position' in this
        // string, and return an iterator providing modifiable access to the
        // inserted character.  The behavior is undefined unless 'position' is
        // a valid iterator on this string.

    template <class INPUT_ITER>
    iterator insert(const_iterator position,
                    INPUT_ITER     first,
                    INPUT_ITER     last);
        // Insert at the specified 'position' in this string the characters in
        // the range starting at the specified 'first' iterator and ending
        // right before the specified 'last' iterator of the (template
        // parameter) type 'INPUT_ITER', and return an iterator providing
        // modifiable access to the first inserted character, or a non-'const'
        // copy of 'position' if 'first == last'.  The behavior is undefined
        // unless 'position' is a valid iterator on this string, and 'first'
        // and 'last' refer to a sequence of valid values where 'first' is at a
        // position at or before 'last'.

    iterator insert(const_iterator position,
                    size_type      numChars,
                    CHAR_TYPE      character);
        // Insert at the specified 'position' in this string the specified
        // 'numChars' copies of the specified 'character', and return an
        // iterator providing modifiable access to the first inserted
        // character, or a non-'const' copy of 'position' if '0 == numChars'.
        // The behavior is undefined unless 'position' is a valid iterator on
        // this string.

    template <class STRING_VIEW_LIKE_TYPE>
    BSLSTL_STRING_DEFINE_ONLY_CONVERTIBLE_TO_STRINGVIEW_RETURN_TYPE
    insert(size_type position, const STRING_VIEW_LIKE_TYPE& other);
        // Insert at the specified 'position' in this string the
        // 'bsl::string_view' object, obtained from the specified 'other', and
        // return a reference providing modifiable access to this string.
        // Throw 'out_of_range' if 'position > length()'.  Throw 'length_error'
        // if the length of the resulting string exceeds 'max_size()'.

    template <class STRING_VIEW_LIKE_TYPE>
    BSLSTL_STRING_DEFINE_ONLY_CONVERTIBLE_TO_STRINGVIEW_RETURN_TYPE
    insert(size_type                    position,
           const STRING_VIEW_LIKE_TYPE& other,
           size_type                    sourcePosition,
           size_type                    numChars = npos);
        // Insert at the specified 'position' in this string the optionally
        // specified 'numChars' characters starting at the specified
        // 'sourcePosition' in the 'bsl::string_view' object, obtained from the
        // specified 'other', or the suffix of this object starting at
        // 'sourcePosition' if 'sourcePosition + numChars > other.length()'.
        // If 'numChars' is not specified, 'npos' is used.  Return a reference
        // providing modifiable access to this string.  Throw 'out_of_range' if
        // 'position > length()' or 'sourcePosition > other.length()'. Throw
        // 'length_error' if the length of the resulting string exceeds
        // 'max_size()'.

#if defined(BSLS_COMPILERFEATURES_SUPPORT_GENERALIZED_INITIALIZERS)
    iterator insert(const_iterator                   position,
                    std::initializer_list<CHAR_TYPE> values);
        // Insert at the specified 'position' in this string each 'CHAR_TYPE'
        // object in the specified 'values' initializer list, and return an
        // iterator to the first newly-inserted character.  If an exception is
        // thrown (other than by the copy constructor, move constructor,
        // assignment operator, and move assignment operator of 'CHAR_TYPE'),
        // '*this' is unaffected.  The behavior is undefined unless 'position'
        // is an iterator in the range '[begin() .. end()]' (both endpoints
        // included).
#endif

    basic_string& erase(size_type position = 0, size_type numChars = npos);
        // Erase from this string the substring of length the optionally
        // specified 'numChars' or 'original.length() - position', whichever is
        // smaller, starting at the optionally specified 'position'.  If
        // 'position' is not specified, the first position is used (i.e.,
        // 'position' is set to 0).  Return a reference providing modifiable
        // access to this string.  If 'numChars' equals 'npos', then the
        // remaining length of the string is erased (i.e., 'numChars' is set to
        // 'length() - position').  Throw 'out_of_range' if
        // 'position > length()'.

    iterator erase(const_iterator position);
        // Erase a character at the specified 'position' from this string, and
        // return an iterator providing modifiable access to the character at
        // 'position' prior to erasing.  If no such character exists, return
        // 'end()'.  The behavior is undefined unless 'position' is within the
        // half-open range '[cbegin() .. cend())'.

    iterator erase(const_iterator first, const_iterator last);
        // Erase from this string a substring defined by the specified pair of
        // 'first' and 'last' iterators within this string.  Return an iterator
        // providing modifiable access to the character at the 'last' position
        // prior to erasing.  If no such character exists, return 'end()'.
        // This method invalidates existing iterators pointing to 'first' or a
        // subsequent position.  The behavior is undefined unless 'first' and
        // 'last' are both within the range '[cbegin() .. cend()]' and 'first
        // <= last'.

    void pop_back();
        // Erase the last character from this string.  The behavior is
        // undefined if this string is empty.

    basic_string& replace(size_type           outPosition,
                          size_type           outNumChars,
                          const basic_string& replacement);
        // Replace the specified 'outNumChars' characters starting at the
        // specified 'outPosition' in this string (or the suffix of this string
        // starting at 'outPosition' if 'outPosition + outNumChars > length()')
        // with the specified 'replacement' string, and return a reference
        // providing modifiable access to this string.  Throw 'out_of_range' if
        // 'outPosition > length()'.

    basic_string& replace(size_type           outPosition,
                          size_type           outNumChars,
                          const basic_string& replacement,
                          size_type           position,
                          size_type           numChars = npos);
        // Replace the specified 'outNumChars' characters starting at the
        // specified 'outPosition' in this string (or the suffix of this string
        // starting at 'outPosition' if 'outPosition + outNumChars > length()')
        // with the optionally specified 'numChars' characters starting at the
        // specified 'position' in the specified 'replacement' string (or the
        // suffix of 'replacement' starting at 'position' if
        // 'position + numChars > replacement.length()').  If 'numChars' is not
        // specified, 'npos' is used.  Return a reference providing modifiable
        // access to this string.  Throw 'out_of_range' if
        // 'outPosition > length()' or 'position > replacement.length()'.

    basic_string& replace(size_type        outPosition,
                          size_type        outNumChars,
                          const CHAR_TYPE *characterString,
                          size_type        numChars);
        // Replace the specified 'outNumChars' characters starting at the
        // specified 'outPosition' in this string (or the suffix of this string
        // starting at 'outPosition' if 'outPosition + outNumChars > length()')
        // with the specified initial 'numChars' characters in the specified
        // 'characterString'.  Return a reference providing modifiable access
        // to this string.  Throw 'out_of_range' if 'outPosition > length()'.
        // The behavior is undefined unless 'characterString' is at least
        // 'numChars' long.

    basic_string& replace(size_type        outPosition,
                          size_type        outNumChars,
                          const CHAR_TYPE *characterString);
        // Replace the specified 'outNumChars' characters starting at the
        // specified 'outPosition' in this string (or the suffix of this string
        // starting at 'outPosition' if 'outPosition + outNumChars > length()')
        // with the specified null-terminated 'characterString' (of length
        // 'CHAR_TRAITS::length(characterString)').  Return a reference
        // providing modifiable access to this string.  Throw 'out_of_range' if
        // 'outPosition > length()'.

    basic_string& replace(size_type outPosition,
                          size_type outNumChars,
                          size_type numChars,
                          CHAR_TYPE character);
        // Replace the specified 'outNumChars' characters starting at the
        // specified 'outPosition' in this string (or the suffix of this string
        // starting at 'outPosition' if 'outPosition + outNumChars > length()')
        // with the specified 'numChars' copies of the specified 'character'.
        // Return a reference providing modifiable access to this string.
        // Throw 'out_of_range' if 'outPosition > length()'.

    template <class STRING_VIEW_LIKE_TYPE>
    BSLSTL_STRING_DEFINE_ONLY_CONVERTIBLE_TO_STRINGVIEW_RETURN_TYPE
    replace(size_type                    outPosition,
            size_type                    outNumChars,
            const STRING_VIEW_LIKE_TYPE& replacement);
        // Replace the specified 'outNumChars' characters starting at the
        // specified 'outPosition' in this string (or the suffix of this string
        // starting at 'outPosition' if 'outPosition + outNumChars > length()')
        // with the specified 'replacement', and return a reference providing
        // modifiable access to this string.  Throw 'out_of_range' if
        // 'outPosition > length()'.


    template <class STRING_VIEW_LIKE_TYPE>
    BSLSTL_STRING_DEFINE_ONLY_CONVERTIBLE_TO_STRINGVIEW_RETURN_TYPE
    replace(size_type                    outPosition,
            size_type                    outNumChars,
            const STRING_VIEW_LIKE_TYPE& replacement,
            size_type                    position,
            size_type                    numChars = npos);
        // Replace the specified 'outNumChars' characters starting at the
        // specified 'outPosition' in this string (or the suffix of this string
        // starting at 'outPosition' if 'outPosition + outNumChars > length()')
        // with the optionally specified 'numChars' characters starting at the
        // specified 'position' in the specified 'replacement' (or the suffix
        // of 'replacement' starting at 'position' if
        // 'position + numChars > replacement.length()').  If 'numChars' is not
        // specified, 'npos' is used.  Return a reference providing modifiable
        // access to this string.  Throw 'out_of_range' if
        // 'outPosition > length()' or 'position > replacement.length()'.

    basic_string& replace(const_iterator      first,
                          const_iterator      last,
                          const basic_string& replacement);
        // Replace the substring in the range starting at the specified 'first'
        // position and ending right before the specified 'last' position with
        // the specified 'replacement' string.  Return a reference providing
        // modifiable access to this string.  The behavior is undefined unless
        // 'first' and 'last' are both within the range '[cbegin() .. cend()]'
        // and 'first <= last'.

    template <class STRING_VIEW_LIKE_TYPE>
    BSLSTL_STRING_DEFINE_ONLY_CONVERTIBLE_TO_STRINGVIEW_RETURN_TYPE
    replace(const_iterator               first,
            const_iterator               last,
            const STRING_VIEW_LIKE_TYPE& replacement);
        // Replace the substring in the range starting at the specified 'first'
        // position and ending right before the specified 'last' position with
        // the specified 'replacement'.  Return a reference providing
        // modifiable access to this string.  The behavior is undefined unless
        // 'first' and 'last' are both within the range '[cbegin() .. cend()]'
        // and 'first <= last'.

    basic_string& replace(const_iterator   first,
                          const_iterator   last,
                          const CHAR_TYPE *characterString,
                          size_type        numChars);
        // Replace the substring in the range starting at the specified 'first'
        // position and ending right before the specified 'last' position with
        // the specified initial 'numChars' characters in the specified
        // 'characterString'.  Return a reference providing modifiable access
        // to this string.  The behavior is undefined unless 'first' and 'last'
        // are both within the range '[cbegin() .. cend()]', 'first <= last',
        // and 'characterString' is at least 'numChars' long.

    basic_string& replace(const_iterator   first,
                          const_iterator   last,
                          const CHAR_TYPE *characterString);
        // Replace the substring in the range starting at the specified 'first'
        // position and ending right before the specified 'last' position with
        // the specified null-terminated 'characterString' (of length
        // 'CHAR_TRAITS::length(characterString)').  Return a reference
        // providing modifiable access to this string.  The behavior is
        // undefined unless 'first' and 'last' are both within the range
        // '[cbegin() .. cend()]' and 'first <= last'.

    basic_string& replace(const_iterator first,
                          const_iterator last,
                          size_type      numChars,
                          CHAR_TYPE      character);
        // Replace the substring in the range starting at the specified 'first'
        // position and ending right before the specified 'last' position with
        // the specified 'numChars' copies of the specified 'character'.
        // Return a reference providing modifiable access to this string.  The
        // behavior is undefined unless 'first' and 'last' are both within the
        // range '[cbegin() .. cend()]' and 'first <= last'.

    template <class INPUT_ITER>
    basic_string& replace(const_iterator first,
                          const_iterator last,
                          INPUT_ITER     stringFirst,
                          INPUT_ITER     stringLast);
        // Replace the substring in the range starting at the specified 'first'
        // position and ending right before the specified 'last' position with
        // the characters in the range starting at the specified 'stringFirst'
        // iterator and ending right before the specified 'stringLast' iterator
        // of the (template parameter) type 'INPUT_ITER'.  Return a reference
        // providing modifiable access to this string.  The behavior is
        // undefined unless 'first' and 'last' are both within the range
        // '[cbegin() .. cend()]', 'first <= last', and 'stringFirst' and
        // 'stringLast' refer to a sequence of valid values where 'stringFirst'
        // is at a position at or before 'stringLast'.

                     // *** 21.3.7 string operations: ***

    CHAR_TYPE *data() BSLS_KEYWORD_NOEXCEPT;
        // Return an address providing modifiable access to the null-terminated
        // buffer of 'length() + 1' characters whose contents are identical to
        // the value of this string.  Note that any call to the string
        // destructor or any of its manipulators invalidates the returned
        // pointer.

    void swap(basic_string& other) BSLS_KEYWORD_NOEXCEPT_SPECIFICATION(
                         AllocatorTraits::propagate_on_container_swap::value ||
                         AllocatorTraits::is_always_equal::value);
        // Exchange the value of this object with that of the specified 'other'
        // object; also exchange the allocator of this object with that of
        // 'other' if the (template parameter) type 'ALLOCATOR' has the
        // 'propagate_on_container_swap' trait, and do not modify either
        // allocator otherwise.  This method provides the no-throw
        // exception-safety guarantee.  This operation has 'O[1]' complexity if
        // either this object was created with the same allocator as 'other' or
        // 'ALLOCATOR' has the 'propagate_on_container_swap' trait; otherwise,
        // it has 'O[n + m]' complexity, where 'n' and 'm' are the lengths of
        // this object and 'other', respectively.  Note that this method's
        // support for swapping objects created with different allocators when
        // 'ALLOCATOR' does not have the 'propagate_on_container_swap' trait is
        // a departure from the C++ Standard.

    // ACCESSORS

                     // *** 21.3.3 iterators: ***

    const_iterator  begin() const BSLS_KEYWORD_NOEXCEPT;
    const_iterator cbegin() const BSLS_KEYWORD_NOEXCEPT;
        // Return an iterator providing non-modifiable access to the first
        // character of this string (or the past-the-end iterator if this
        // string is empty).

    const_iterator  end() const BSLS_KEYWORD_NOEXCEPT;
    const_iterator cend() const BSLS_KEYWORD_NOEXCEPT;
        // Return the past-the-end iterator for this string.

    const_reverse_iterator  rbegin() const BSLS_KEYWORD_NOEXCEPT;
    const_reverse_iterator crbegin() const BSLS_KEYWORD_NOEXCEPT;
        // Return a reverse iterator providing non-modifiable access to the
        // last character of this string (or the past-the-end reverse iterator
        // if this string is empty).

    const_reverse_iterator  rend() const BSLS_KEYWORD_NOEXCEPT;
    const_reverse_iterator crend() const BSLS_KEYWORD_NOEXCEPT;
        // Return the past-the-end reverse iterator for this string.

                          // *** 21.3.4 capacity: ***

    size_type length() const BSLS_KEYWORD_NOEXCEPT;
        // Return the length of this string.  Note that this number may differ
        // from 'CHAR_TRAITS::length(c_str())' in case the string contains null
        // characters.  Also note that a null-terminating character added by
        // the 'c_str' method is *not* counted in this length.

    size_type size() const BSLS_KEYWORD_NOEXCEPT;
        // Return the length of this string.  Note that this number may differ
        // from 'CHAR_TRAITS::length(c_str())' in case the string contains null
        // characters.  Also note that a null-terminating character added by
        // the 'c_str' method is *not* counted in this length.

    size_type max_size() const BSLS_KEYWORD_NOEXCEPT;
        // Return the maximal possible length of this string.  Note that
        // requests to create a string longer than this number of characters
        // are guaranteed to raise a 'length_error' exception.

    size_type capacity() const BSLS_KEYWORD_NOEXCEPT;
        // Return the capacity of this string, i.e., the maximum length for
        // which resizing is guaranteed not to trigger a reallocation.

    bool empty() const BSLS_KEYWORD_NOEXCEPT;
        // Return 'true' if this string has length 0, and 'false' otherwise.

                       // *** 21.3.5 element access: ***

    const_reference operator[](size_type position) const;
        // Return a reference providing non-modifiable access to the character
        // at the specified 'position' in this string.  The behavior is
        // undefined unless 'position <= length()'.  Note that if
        // 'position == length()', a reference to the null-terminating
        // character is returned.

    const_reference at(size_type position) const;
        // Return a reference providing non-modifiable access to the character
        // at the specified 'position' in this string.  Throw 'out_of_range' if
        // 'position >= length()'.

    const CHAR_TYPE& front() const;
        // Return a reference providing non-modifiable access to the character
        // at the first position in this string.  The behavior is undefined if
        // this string is empty.

    const CHAR_TYPE& back() const;
        // Return a reference providing non-modifiable access to the character
        // at the last position in this string.  The behavior is undefined if
        // this string is empty.  Note that the last position is
        // 'length() - 1'.

    size_type copy(CHAR_TYPE *characterString,
                   size_type  numChars,
                   size_type  position = 0) const;
        // Copy from this string, starting from the optionally specified
        // 'position', the specified 'numChars' or 'length() - position'
        // characters, whichever is smaller, into the specified
        // 'characterString' buffer, and return the number of characters
        // copied.  If 'position' is not specified, 0 is used.  Throw
        // 'out_of_range' if 'position > length()'.  The behavior is undefined
        // unless 'characterString' is at least 'numChars' long.  Note that the
        // output 'characterString' is *not* null-terminated.

                     // *** 21.3.7 string operations: ***

    const CHAR_TYPE *c_str() const BSLS_KEYWORD_NOEXCEPT;
        // Return an address providing non-modifiable access to the
        // null-terminated buffer of 'length() + 1' characters whose contents
        // are identical to the value of this string.  Note that any call to
        // the string destructor or any of its manipulators invalidates the
        // returned pointer.

    const CHAR_TYPE *data() const BSLS_KEYWORD_NOEXCEPT;
        // Return an address providing non-modifiable access to the
        // null-terminated buffer of 'length() + 1' characters whose contents
        // are identical to the value of this string.  Note that any call to
        // the string destructor or any of its manipulators invalidates the
        // returned pointer.

    allocator_type get_allocator() const BSLS_KEYWORD_NOEXCEPT;
        // Return the allocator used by this string to supply memory.

    size_type find(const basic_string& substring,
                   size_type           position = 0) const
                                                         BSLS_KEYWORD_NOEXCEPT;
        // Return the starting position of the *first* occurrence of the
        // specified 'substring', if such a substring can be found in this
        // string (on or *after* the optionally specified 'position' if such a
        // 'position' is specified) using 'CHAR_TRAITS::eq' to compare
        // characters, and return 'npos' otherwise.

    template <class STRING_VIEW_LIKE_TYPE>
    size_type find(
               const STRING_VIEW_LIKE_TYPE& substring,
               size_type                    position = 0
               BSLSTL_STRING_DECLARE_ONLY_CONVERTIBLE_TO_STRINGVIEW_PARAM_VOID)
                               const BSLS_KEYWORD_NOEXCEPT_SPECIFICATION(true);
        // Return the starting position of the *first* occurrence of the
        // specified 'substring', if such a substring can be found in this
        // string (on or *after* the optionally specified 'position' if such a
        // 'position' is specified) using 'CHAR_TRAITS::eq' to compare
        // characters, and return 'npos' otherwise.  The behavior is undefined
        // unless the conversion from 'STRING_VIEW_LIKE_TYPE' to
        // 'bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS>' does not throw any
        // exception.    Note that this behavior differs from the behavior
        // implemented in the standard container, where the following noexcept
        // specification is used:
        //..
        // noexcept(
        //     std::is_nothrow_convertible_v<const T&,
        //                                   std::basic_string_view<CharT,
        //                                                          Traits> >)
        //..

    size_type find(const CHAR_TYPE *substring,
                   size_type        position,
                   size_type        numChars) const;
    size_type find(const CHAR_TYPE *substring,
                   size_type        position = 0) const;
        // Return the starting position of the *first* occurrence of the
        // specified 'substring' of the optionally specified 'numChars' length,
        // if such a substring can be found in this string (on or *after* the
        // optionally specified 'position' if such a 'position' is specified)
        // using 'CHAR_TRAITS::eq' to compare characters, and return 'npos'
        // otherwise.  If 'numChars' is not specified,
        // 'CHAR_TRAITS::length(substring)' is used.

    size_type find(CHAR_TYPE character, size_type position = 0) const;
        // Return the position of the *first* occurrence of the specified
        // 'character', if such an occurrence can be found in this string (on
        // or *after* the optionally specified 'position' if such a 'position'
        // is specified), and return 'npos' otherwise.

    size_type rfind(const basic_string& substring,
                    size_type           position = npos) const
                                                         BSLS_KEYWORD_NOEXCEPT;
        // Return the starting position of the *last* occurrence of the
        // specified 'substring' within this string, if such a sequence can be
        // found in this string (on or *before* the optionally specified
        // 'position' if such a 'position' is specified) using
        // 'CHAR_TRAITS::eq' to compare characters, and return 'npos'
        // otherwise.

    template <class STRING_VIEW_LIKE_TYPE>
    size_type rfind(
               const STRING_VIEW_LIKE_TYPE& substring,
               size_type                    position = npos
               BSLSTL_STRING_DECLARE_ONLY_CONVERTIBLE_TO_STRINGVIEW_PARAM_VOID)
                               const BSLS_KEYWORD_NOEXCEPT_SPECIFICATION(true);
        // Return the starting position of the *last* occurrence of the
        // specified 'substring' within this string, if such a sequence can be
        // found in this string (on or *before* the optionally specified
        // 'position' if such a 'position' is specified) using
        // 'CHAR_TRAITS::eq' to compare characters, and return 'npos'
        // otherwise.  The behavior is undefined unless the conversion from
        // 'STRING_VIEW_LIKE_TYPE' to
        // 'bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS>' does not throw any
        // exception.    Note that this behavior differs from the behavior
        // implemented in the standard container, where the following noexcept
        // specification is used:
        //..
        // noexcept(
        //     std::is_nothrow_convertible_v<const T&,
        //                                   std::basic_string_view<CharT,
        //                                                          Traits> >)
        //..

    size_type rfind(const CHAR_TYPE *characterString,
                    size_type        position,
                    size_type        numChars) const;
    size_type rfind(const CHAR_TYPE *characterString,
                    size_type        position = npos) const;
        // Return the starting position of the *last* occurrence of a substring
        // whose value equals that of the specified 'characterString' of the
        // optionally specified 'numChars' length, if such a substring can be
        // found in this string (on or *before* the optionally specified
        // 'position' if such a 'position' is specified), and return 'npos'
        // otherwise.  If 'numChars' is not specified,
        // 'CHAR_TRAITS::length(characterString)' is used.

    size_type rfind(CHAR_TYPE character, size_type position = npos) const;
        // Return the position of the *last* occurrence of the specified
        // 'character', if such an occurrence can be found in this string (on
        // or *before* the optionally specified 'position' if such a 'position'
        // is specified), and return 'npos' otherwise.

    size_type find_first_of(const basic_string& characterString,
                            size_type           position = 0) const
                                                         BSLS_KEYWORD_NOEXCEPT;
        // Return the position of the *first* occurrence of a character
        // belonging to the specified 'characterString', if such an occurrence
        // can be found in this string (on or *after* the optionally specified
        // 'position' if such a 'position' is specified), and return 'npos'
        // otherwise.

    template <class STRING_VIEW_LIKE_TYPE>
    size_type find_first_of(
               const STRING_VIEW_LIKE_TYPE& characterString,
               size_type                    position = 0
               BSLSTL_STRING_DECLARE_ONLY_CONVERTIBLE_TO_STRINGVIEW_PARAM_VOID)
                               const BSLS_KEYWORD_NOEXCEPT_SPECIFICATION(true);
        // Return the position of the *first* occurrence of a character
        // belonging to the specified 'characterString', if such an occurrence
        // can be found in this string (on or *after* the optionally specified
        // 'position' if such a 'position' is specified), and return 'npos'
        // otherwise.  The behavior is undefined unless the conversion from
        // 'STRING_VIEW_LIKE_TYPE' to
        // 'bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS>' does not throw any
        // exception.    Note that this behavior differs from the behavior
        // implemented in the standard container, where the following noexcept
        // specification is used:
        //..
        // noexcept(
        //     std::is_nothrow_convertible_v<const T&,
        //                                   std::basic_string_view<CharT,
        //                                                          Traits> >)
        //..

    size_type find_first_of(const CHAR_TYPE *characterString,
                            size_type        position,
                            size_type        numChars) const;
    size_type find_first_of(const CHAR_TYPE *characterString,
                            size_type        position = 0) const;
        // Return the position of the *first* occurrence of a character
        // belonging to the specified 'characterString' of the optionally
        // specified 'numChars' length, if such an occurrence can be found in
        // this string (on or *after* the optionally specified 'position' if
        // such a 'position' is specified), and return 'npos' otherwise.  If
        // 'numChars' is not specified, 'CHAR_TRAITS::length(characterString)'
        // is used.

    size_type find_first_of(CHAR_TYPE character,
                            size_type position = 0) const;
        // Return the position of the *first* occurrence of the specified
        // 'character', if such an occurrence can be found in this string (on
        // or *after* the optionally specified 'position' if such a 'position'
        // is specified), and return 'npos' otherwise.

    size_type find_last_of(const basic_string& characterString,
                           size_type           position = npos) const
                                                         BSLS_KEYWORD_NOEXCEPT;
        // Return the position of the *last* occurrence of a character
        // belonging to the specified 'characterString', if such an occurrence
        // can be found in this string (on or *before* the optionally specified
        // 'position' if such a 'position' is specified), and return 'npos'
        // otherwise.

    template <class STRING_VIEW_LIKE_TYPE>
    size_type find_last_of(
               const STRING_VIEW_LIKE_TYPE& characterString,
               size_type                    position = npos
               BSLSTL_STRING_DECLARE_ONLY_CONVERTIBLE_TO_STRINGVIEW_PARAM_VOID)
                               const BSLS_KEYWORD_NOEXCEPT_SPECIFICATION(true);
        // Return the position of the *last* occurrence of a character
        // belonging to the specified 'characterString', if such an occurrence
        // can be found in this string (on or *before* the optionally specified
        // 'position' if such a 'position' is specified), and return 'npos'
        // otherwise.  The behavior is undefined unless the conversion from
        // 'STRING_VIEW_LIKE_TYPE' to
        // 'bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS>' does not throw any
        // exception.    Note that this behavior differs from the behavior
        // implemented in the standard container, where the following noexcept
        // specification is used:
        //..
        // noexcept(
        //     std::is_nothrow_convertible_v<const T&,
        //                                   std::basic_string_view<CharT,
        //                                                          Traits> >)
        //..

    size_type find_last_of(const CHAR_TYPE *characterString,
                           size_type        position,
                           size_type        numChars) const;
    size_type find_last_of(const CHAR_TYPE *characterString,
                           size_type        position = npos) const;
        // Return the position of the *last* occurrence of a character
        // belonging to the specified 'characterString' of the optionally
        // specified 'numChars' length, if such an occurrence can be found in
        // this string (on or *before* the optionally specified 'position' if
        // such a 'position' is specified), and return 'npos' otherwise.  If
        // 'numChars' is not specified, 'CHAR_TRAITS::length(characterString)'
        // is used.

    size_type find_last_of(CHAR_TYPE character,
                           size_type position = npos) const;
        // Return the position of the *last* occurrence of the specified
        // 'character', if such an occurrence can be found in this string (on
        // or *before* the optionally specified 'position' if such a 'position'
        // is specified), and return 'npos' otherwise.

    size_type find_first_not_of(const basic_string& characterString,
                                size_type           position = 0) const
                                                         BSLS_KEYWORD_NOEXCEPT;
        // Return the position of the *first* occurrence of a character *not*
        // belonging to the specified 'characterString', if such an occurrence
        // can be found in this string (on or *after* the optionally specified
        // 'position' if such a 'position' is specified), and return 'npos'
        // otherwise.

    template <class STRING_VIEW_LIKE_TYPE>
    size_type find_first_not_of(
               const STRING_VIEW_LIKE_TYPE& characterString,
               size_type                    position = 0
               BSLSTL_STRING_DECLARE_ONLY_CONVERTIBLE_TO_STRINGVIEW_PARAM_VOID)
                               const BSLS_KEYWORD_NOEXCEPT_SPECIFICATION(true);
        // Return the position of the *first* occurrence of a character *not*
        // belonging to the specified 'characterString', if such an occurrence
        // can be found in this string (on or *after* the optionally specified
        // 'position' if such a 'position' is specified), and return 'npos'
        // otherwise.  The behavior is undefined unless the conversion from
        // 'STRING_VIEW_LIKE_TYPE' to
        // 'bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS>' does not throw any
        // exception.    Note that this behavior differs from the behavior
        // implemented in the standard container, where the following noexcept
        // specification is used:
        //..
        // noexcept(
        //     std::is_nothrow_convertible_v<const T&,
        //                                   std::basic_string_view<CharT,
        //                                                          Traits> >)
        //..

    size_type find_first_not_of(const CHAR_TYPE *characterString,
                                size_type        position,
                                size_type        numChars) const;
    size_type find_first_not_of(const CHAR_TYPE *characterString,
                                size_type        position = 0) const;
        // Return the position of the *first* occurrence of a character *not*
        // belonging to the specified 'characterString' of the optionally
        // specified 'numChars' length, if such an occurrence can be found in
        // this string (on or *after* the optionally specified 'position' if
        // such a 'position' is specified), and return 'npos' otherwise.  If
        // 'numChars' is not specified, 'CHAR_TRAITS::length(characterString)'
        // is used.

    size_type find_first_not_of(CHAR_TYPE character,
                                size_type position = 0) const;
        // Return the position of the *first* occurrence of a character
        // *different* from the specified 'character', if such an occurrence
        // can be found in this string (on or *after* the optionally specified
        // 'position' if such a 'position' is specified), and return 'npos'
        // otherwise.

    size_type find_last_not_of(const basic_string& characterString,
                               size_type           position = npos) const
                                                         BSLS_KEYWORD_NOEXCEPT;
        // Return the position of the *last* occurrence of a character *not*
        // belonging to the specified 'characterString', if such an occurrence
        // can be found in this string (on or *before* the optionally specified
        // 'position' if such a 'position' is specified), and return 'npos'
        // otherwise.

    template <class STRING_VIEW_LIKE_TYPE>
    size_type find_last_not_of(
               const STRING_VIEW_LIKE_TYPE& characterString,
               size_type                    position = npos
               BSLSTL_STRING_DECLARE_ONLY_CONVERTIBLE_TO_STRINGVIEW_PARAM_VOID)
                               const BSLS_KEYWORD_NOEXCEPT_SPECIFICATION(true);
        // Return the position of the *last* occurrence of a character *not*
        // belonging to the specified 'characterString', if such an occurrence
        // can be found in this string (on or *before* the optionally specified
        // 'position' if such a 'position' is specified), and return 'npos'
        // otherwise.  The behavior is undefined unless the conversion from
        // 'STRING_VIEW_LIKE_TYPE' to
        // 'bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS>' does not throw any
        // exception.    Note that this behavior differs from the behavior
        // implemented in the standard container, where the following noexcept
        // specification is used:
        //..
        // noexcept(
        //     std::is_nothrow_convertible_v<const T&,
        //                                   std::basic_string_view<CharT,
        //                                                          Traits> >)
        //..

    size_type find_last_not_of(const CHAR_TYPE *characterString,
                               size_type        position,
                               size_type        numChars) const;
    size_type find_last_not_of(const CHAR_TYPE *characterString,
                               size_type        position = npos) const;
        // Return the position of the *last* occurrence of a character *not*
        // belonging to the specified 'characterString' of the optionally
        // specified 'numChars' length, if such an occurrence can be found in
        // this string (on or *before* the optionally specified 'position' if
        // such a 'position' is specified), and return 'npos' otherwise.  If
        // 'numChars' is not specified, 'CHAR_TRAITS::length(characterString)'
        // is used.

    size_type find_last_not_of(CHAR_TYPE character,
                               size_type position = npos) const;
        // Return the position of the *last* occurrence of a character
        // *different* from the specified 'character', if such an occurrence
        // can be found in this string (on or *before* the optionally specified
        // 'position' if such a 'position' is specified), and return 'npos'
        // otherwise.

    bool starts_with(basic_string_view<CHAR_TYPE, CHAR_TRAITS> characterString)
                                                   const BSLS_KEYWORD_NOEXCEPT;
        // Return 'true' if the length of this string is equal to or greater
        // than the length of the specified 'characterString' and the first
        // 'characterString.length()' characters of this string are equal to
        // the characters of the 'characterString', and 'false' otherwise.
        // 'CHAR_TRAITS::compare' is used to compare characters.  See
        // {Lexicographical Comparisons}.

    bool starts_with(CHAR_TYPE character) const BSLS_KEYWORD_NOEXCEPT;
        // Return 'true' if this string contains at least one symbol and the
        // last symbol of this string is equal to the specified 'character',
        // and 'false' otherwise.  'CHAR_TRAITS::eq' is used to compare
        // characters.  See {Lexicographical Comparisons}.

    bool starts_with(const CHAR_TYPE *characterString) const;
        // Return 'true' if the length of this string is equal to or greater
        // than the length of the specified 'characterString' and the first
        // 'CHAR_TRAITS::length(characterString)' characters of this string are
        // equal to the characters of the 'characterString', and 'false'
        // otherwise.  'CHAR_TRAITS::compare' is used to compare characters.
        // See {Lexicographical Comparisons}.

    bool ends_with(basic_string_view<CHAR_TYPE, CHAR_TRAITS> characterString)
                                                   const BSLS_KEYWORD_NOEXCEPT;
        // Return 'true' if the length of this string is equal to or greater
        // than the length of the specified 'characterString' and the last
        // 'characterString.length()' characters of this string are equal to
        // the characters of the 'characterString', and 'false' otherwise.
        // 'CHAR_TRAITS::compare' is used to compare characters.  See
        // {Lexicographical Comparisons}.

    bool ends_with(CHAR_TYPE character) const BSLS_KEYWORD_NOEXCEPT;
        // Return 'true' if this string contains at least one symbol and the
        // last symbol of this string is equal to the specified 'character',
        // and 'false' otherwise.  'CHAR_TRAITS::eq' is used to compare
        // characters.  See {Lexicographical Comparisons}.

    bool ends_with(const CHAR_TYPE *characterString) const;
        // Return 'true' if the length of this string is equal to or greater
        // than the length of the specified 'characterString' and the last
        // 'CHAR_TRAITS::length(characterString)' characters of this string are
        // equal to the characters of the 'characterString', and 'false'
        // otherwise.  'CHAR_TRAITS::compare' is used to compare characters.
        // See {Lexicographical Comparisons}.

    basic_string substr(size_type position = 0,
                        size_type numChars = npos) const;
        // Return a string whose value is the substring starting at the
        // optionally specified 'position' in this string, of length the
        // optionally specified 'numChars' or 'length() - position', whichever
        // is smaller.  If 'position' is not specified, 0 is used (i.e., the
        // substring is from the beginning of this string).  If 'numChars' is
        // not specified, 'npos' is used (i.e., the entire suffix from
        // 'position' to the end of the string is returned).

    int compare(const basic_string& other) const BSLS_KEYWORD_NOEXCEPT;
        // Lexicographically compare this string with the specified 'other'
        // string, and return a negative value if this string is less than
        // 'other', a positive value if it is greater than 'other', and 0 in
        // case of equality.  'CHAR_TRAITS::lt' is used to compare characters.
        // See {Lexicographical Comparisons}.

    int compare(size_type           position,
                size_type           numChars,
                const basic_string& other) const;
        // Lexicographically compare the substring of this string of the
        // specified 'numChars' length starting at the specified 'position' (or
        // the suffix of this string starting at 'position' if
        // 'position + numChars > length()') with the specified 'other' string,
        // and return a negative value if the indicated substring of this
        // string is less than 'other', a positive value if it is greater than
        // 'other', and 0 in case of equality.  'CHAR_TRAITS::lt' is used to
        // compare characters.  See {Lexicographical Comparisons}.  Throw
        // 'out_of_range' if 'position > length()'.

    int compare(size_type           lhsPosition,
                size_type           lhsNumChars,
                const basic_string& other,
                size_type           otherPosition,
                size_type           otherNumChars = npos) const;
        // Lexicographically compare the substring of this string of the
        // specified 'lhsNumChars' length starting at the specified
        // 'lhsPosition' (or the suffix of this string starting at
        // 'lhsPosition' if 'lhsPosition + lhsNumChars > length()') with the
        // substring of the specified 'other' string of the optionally
        // specified 'otherNumChars' length starting at the specified
        // 'otherPosition' (or the suffix of 'other' starting at
        // 'otherPosition' if
        // 'otherPosition + otherNumChars > other.length()').  If 'numChars' is
        // not specified, 'npos' is used.  Return a negative value if the
        // indicated substring of this string is less than the indicated
        // substring of 'other', a positive value if it is greater than the
        // indicated substring of 'other', and 0 in case of equality.
        // 'CHAR_TRAITS::lt' is used to compare characters.  Throw
        // 'out_of_range' if 'lhsPosition > length()' or
        // 'otherPosition > other.length()'.  See {Lexicographical
        // Comparisons}.

    int compare(const CHAR_TYPE *other) const;
        // Lexicographically compare this string with the specified
        // null-terminated 'other' string (of length
        // 'CHAR_TRAITS::length(other)'), and return a negative value if this
        // string is less than 'other', a positive value if it is greater than
        // 'other', and 0 in case of equality.  'CHAR_TRAITS::lt' is used to
        // compare characters.  See {Lexicographical Comparisons}.

    int compare(size_type        lhsPosition,
                size_type        lhsNumChars,
                const CHAR_TYPE *other,
                size_type        otherNumChars) const;
        // Lexicographically compare the substring of this string of the
        // specified 'lhsNumChars' length starting at the specified
        // 'lhsPosition' (or the suffix of this string starting at
        // 'lhsPosition' if 'lhsPosition + lhsNumChars > length()') with the
        // specified 'other' string of the specified 'otherNumChars' length,
        // and return a negative value if the indicated substring of this
        // string is less than 'other', a positive value if it is greater than
        // 'other', and 0 in case of equality.  'CHAR_TRAITS::lt' is used to
        // compare characters.  Throw 'out_of_range' if
        // 'lhsPosition > length()'.  See {Lexicographical Comparisons}.

    int compare(size_type        lhsPosition,
                size_type        lhsNumChars,
                const CHAR_TYPE *other) const;
        // Lexicographically compare the substring of this string of the
        // specified 'lhsNumChars' length starting at the specified
        // 'lhsPosition' (or the suffix of this string starting at
        // 'lhsPosition' if 'lhsPosition + lhsNumChars > length()') with the
        // specified null-terminated 'other' string (of length
        // 'CHAR_TRAITS::length(other)'), and return a negative value if the
        // indicated substring of this string is less than 'other', a positive
        // value if it is greater than 'other', and 0 in case of equality.
        // 'CHAR_TRAITS::lt' is used to compare characters.  Throw
        // 'out_of_range' if 'lhsPosition > length()'.  See {Lexicographical
        // Comparisons}.

    template <class STRING_VIEW_LIKE_TYPE>
    int compare(
               const STRING_VIEW_LIKE_TYPE& other
               BSLSTL_STRING_DECLARE_ONLY_CONVERTIBLE_TO_STRINGVIEW_PARAM_VOID)
                               const BSLS_KEYWORD_NOEXCEPT_SPECIFICATION(true);
        // Lexicographically compare this string with the specified 'other',
        // and return a negative value if this string is less than 'other', a
        // positive value if it is greater than 'other', and 0 in case of
        // equality.  'CHAR_TRAITS::lt' is used to compare characters.  See
        // {Lexicographical Comparisons}.  The behavior is undefined unless the
        // conversion from 'STRING_VIEW_LIKE_TYPE' to
        // 'bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS>' does not throw any
        // exception.  Note that this behavior differs from the behavior
        // implemented in the standard container, where the following noexcept
        // specification is used:
        //..
        // noexcept(
        //     std::is_nothrow_convertible_v<const T&,
        //                                   std::basic_string_view<CharT,
        //                                                          Traits> >)
        //..

    template <class STRING_VIEW_LIKE_TYPE>
    int compare(
        size_type                    position,
        size_type                    numChars,
        const STRING_VIEW_LIKE_TYPE& other
        BSLSTL_STRING_DECLARE_ONLY_CONVERTIBLE_TO_STRINGVIEW_PARAM_VOID) const;
        // Lexicographically compare the substring of this string of the
        // specified 'numChars' length starting at the specified 'position' (or
        // the suffix of this string starting at 'position' if
        // 'position + numChars > length()') with the specified 'other', and
        // return a negative value if the indicated substring of this string is
        // less than 'other', a positive value if it is greater than 'other',
        // and 0 in case of equality.  'CHAR_TRAITS::lt' is used to compare
        // characters.  See {Lexicographical Comparisons}.  Throw
        // 'out_of_range' if 'position > length()'.

    template <class STRING_VIEW_LIKE_TYPE>
    int compare(
        size_type                    lhsPosition,
        size_type                    lhsNumChars,
        const STRING_VIEW_LIKE_TYPE& other,
        size_type                    otherPosition,
        size_type                    otherNumChars = npos
        BSLSTL_STRING_DECLARE_ONLY_CONVERTIBLE_TO_STRINGVIEW_PARAM_VOID) const;
        // Lexicographically compare the substring of this string of the
        // specified 'lhsNumChars' length starting at the specified
        // 'lhsPosition' (or the suffix of this string starting at
        // 'lhsPosition' if 'lhsPosition + lhsNumChars > length()') with the
        // substring of the specified 'other' of the optionally specified
        // 'otherNumChars' length starting at the specified 'otherPosition' (or
        // the suffix of 'other' starting at 'otherPosition' if
        // 'otherPosition + otherNumChars > other.length()').  If 'numChars' is
        // not specified, 'npos' is used.  Return a negative value if the
        // indicated substring of this string is less than the indicated
        // substring of 'other', a positive value if it is greater than the
        // indicated substring of 'other', and 0 in case of equality.
        // 'CHAR_TRAITS::lt' is used to compare characters.  See
        // {Lexicographical Comparisons}.  Throw 'out_of_range' if
        // 'lhsPosition > length()' or 'otherPosition > other.length()'.

    // *** BDE compatibility with platform libraries: ***

    template <class ALLOC2>
    operator std::basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOC2>() const
        // Convert this object to a string type native to the compiler's
        // library, instantiated with the same character type and traits type,
        // but not necessarily the same allocator type.  The return string will
        // contain the same sequence of characters as 'orig' and will have a
        // default-constructed allocator.  Note that this conversion operator
        // can be invoked implicitly (e.g., during argument passing).
    {
        // See {DRQS 131792157} for why this is inline.
        std::basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOC2> result;
        result.assign(data(), length());
        return result;
    }

    operator basic_string_view<CHAR_TYPE, CHAR_TRAITS>() const;
        // Convert this object to a 'string_view' type instantiated with the
        // same character type and traits type.  The return view will contain
        // the same sequence of characters as this object.  Note that this
        // conversion operator can be invoked implicitly (e.g., during argument
        // passing).
};

#ifdef BSLS_COMPILERFEATURES_SUPPORT_CTAD
// CLASS TEMPLATE DEDUCTION GUIDES

template <
    class CHAR_TYPE,
    class CHAR_TRAITS,
    class ALLOCATOR,
    class ALLOC,
    class = bsl::enable_if_t<bsl::is_convertible_v<ALLOC, ALLOCATOR>>
    >
basic_string(basic_string<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>, ALLOC)
-> basic_string<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>;
    // Deduce the template parameters 'CHAR_TYPE', 'TRAITS', and 'ALLOCATOR'
    // from the corresponding template parameters of the 'bsl::basic_string'
    // passed to the constructor of 'basic_string'.  This deduction guide does
    // not participate unless the specified 'ALLOC' is convertible to
    // 'ALLOCATOR'.

template <
    class CHAR_TYPE,
    class ALLOC,
    class DEFAULT_ALLOCATOR = bsl::allocator<CHAR_TYPE>,
    class = bsl::enable_if_t<bsl::is_convertible_v<ALLOC *, DEFAULT_ALLOCATOR>>
    >
basic_string(const CHAR_TYPE *, ALLOC *)
-> basic_string<CHAR_TYPE>;
    // Deduce the template parameter 'CHAR_TYPE' from the parameters passed to
    // the constructor of 'basic_string'.  This deduction guide does not
    // participate unless the specified 'ALLOC' is convertible to
    // 'bsl::allocator<CHAR_TYPE>'.

template <
    class CHAR_TYPE,
    class ALLOC,
    class SZ,
    class DEFAULT_ALLOCATOR = bsl::allocator<CHAR_TYPE>,
    class = bsl::enable_if_t<
                            bsl::is_convertible_v<ALLOC *, DEFAULT_ALLOCATOR>>,
    class = bsl::enable_if_t<!bsl::is_pointer_v<SZ>>
         // this last check eliminates an ambiguity for the case
         //  basic_string(const char *, const char *, Allocator *)
    >
basic_string(const CHAR_TYPE *, SZ, ALLOC *)
-> basic_string<CHAR_TYPE>;
    // Deduce the template parameter 'CHAR_TYPE' from the parameters passed to
    // the constructor of 'basic_string'.  This deduction guide does not
    // participate unless the specified 'ALLOC' is convertible to
    // 'bsl::allocator<CHAR_TYPE>'.

template <
    class CHAR_TYPE,
    class ALLOC,
    class DEFAULT_ALLOCATOR = bsl::allocator<CHAR_TYPE>,
    class SZ = typename bsl::allocator_traits<DEFAULT_ALLOCATOR>::size_type,
    class = bsl::enable_if_t<bsl::is_convertible_v<ALLOC *, DEFAULT_ALLOCATOR>>
    >
basic_string(SZ, CHAR_TYPE, ALLOC *)
-> basic_string<CHAR_TYPE>;
    // Deduce the template parameter 'CHAR_TYPE' from the parameters passed to
    // the constructor of 'basic_string'.  This deduction guide does not
    // participate unless the specified 'ALLOC' is convertible to
    // 'bsl::allocator<CHAR_TYPE>'.

template <
    class CHAR_TYPE,
    class CHAR_TRAITS,
    class ALLOCATOR,
    class ALLOC,
    class SZ = typename allocator_traits<ALLOCATOR>::size_type,
    class = bsl::enable_if_t<bsl::is_convertible_v<ALLOC *, ALLOCATOR>>
    >
basic_string(basic_string<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>, SZ, SZ, ALLOC *)
-> basic_string<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>;
    // Deduce the template parameters 'CHAR_TYPE', 'TRAITS', and 'ALLOCATOR'
    // from the corresponding template parameters of the 'bsl::basic_string'
    // passed to the constructor of 'basic_string'.  This deduction guide does
    // not participate unless the specified 'ALLOC' is convertible to
    // 'ALLOCATOR'.

template <
    class INPUT_ITER,
    class CHAR_TYPE =
             typename BloombergLP::bslstl::IteratorUtil::IterVal_t<INPUT_ITER>,
    class ALLOCATOR = bsl::allocator<CHAR_TYPE>,
    class = bsl::enable_if_t<bsl::IsStdAllocator_v<ALLOCATOR>>
    >
basic_string(INPUT_ITER, INPUT_ITER, ALLOCATOR = ALLOCATOR())
  -> basic_string<CHAR_TYPE, char_traits<CHAR_TYPE>, ALLOCATOR>;
    // Deduce the template parameter 'CHAR_TYPE' from the 'value_type' of the
    // iterators passed to passed to the constructor of 'basic_string'.  Deduce
    // the template parameter 'ALLOCATOR' from the optional argument passed to
    // the constructor.  This deduction guide does not participate unless the
    // specified 'ALLOCATOR' meets the requirements of a standard allocator.

template <
    class INPUT_ITER,
    class CHAR_TYPE =
             typename BloombergLP::bslstl::IteratorUtil::IterVal_t<INPUT_ITER>,
    class ALLOC,
    class DEFAULT_ALLOCATOR = bsl::allocator<CHAR_TYPE>,
    class = bsl::enable_if_t<bsl::is_convertible_v<ALLOC *, DEFAULT_ALLOCATOR>>
    >
basic_string(INPUT_ITER, INPUT_ITER, ALLOC *)
  -> basic_string<CHAR_TYPE>;
    // Deduce the template parameter 'CHAR_TYPE' from the 'value_type' of the
    // iterators passed to passed to the constructor of 'basic_string'.  This
    // deduction guide does not participate unless the specified 'ALLOC' is
    // convertible to 'bsl::allocator<CHAR_TYPE>'.

template <
    class CHAR_TYPE,
    class CHAR_TRAITS,
    class ALLOCATOR = allocator<CHAR_TYPE>,
    class = bsl::enable_if_t<bsl::IsStdAllocator_v<ALLOCATOR>>
    >
basic_string(basic_string_view<CHAR_TYPE, CHAR_TRAITS>,
             ALLOCATOR = ALLOCATOR())
  -> basic_string<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>;
    // Deduce the template parameters 'CHAR_TYPE' and 'TRAITS' from the
    // corresponding template parameters of the 'bsl::basic_string_view' passed
    // to the constructor of 'basic_string'.  Deduce the template parameter
    // 'ALLOCATOR' from the optional argument passed to the constructor.  This
    // deduction guide does not participate unless the specified 'ALLOCATOR'
    // meets the requirements of a standard allocator.

template <
    class CHAR_TYPE,
    class CHAR_TRAITS,
    class ALLOC,
    class DEFAULT_ALLOCATOR = bsl::allocator<CHAR_TYPE>,
    class = bsl::enable_if_t<bsl::is_convertible_v<ALLOC *, DEFAULT_ALLOCATOR>>
    >
basic_string(basic_string_view<CHAR_TYPE, CHAR_TRAITS>, ALLOC *)
  -> basic_string<CHAR_TYPE, CHAR_TRAITS>;
    // Deduce the template parameters 'CHAR_TYPE' and 'TRAITS' from the
    // corresponding template parameters of the 'bsl::basic_string_view' passed
    // to the constructor of 'basic_string'.  This deduction guide does not
    // participate unless the specified 'ALLOC' is convertible to
    // 'bsl::allocator<CHAR_TYPE>'.

template<
    class CHAR_TYPE,
    class ALLOC,
    class DEFAULT_ALLOCATOR = bsl::allocator<CHAR_TYPE>,
    class = bsl::enable_if_t<bsl::is_convertible_v<ALLOC *, DEFAULT_ALLOCATOR>>
    >
basic_string(std::initializer_list<CHAR_TYPE>, ALLOC *)
-> basic_string<CHAR_TYPE>;
    // Deduce the template parameter 'CHAR_TYPE' from the 'value_type' of the
    // 'initializer_list' passed to the constructor of 'basic_string'.  This
    // deduction guide does not participate unless the specified 'ALLOC' is
    // convertible to 'bsl::allocator<CHAR_TYPE>'.

#endif

// FREE OPERATORS
template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOC>
bool operator==(const basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOC>&  lhs,
                const basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOC>&  rhs)
                                                         BSLS_KEYWORD_NOEXCEPT;
template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOC1, class ALLOC2>
bool
operator==(const std::basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOC1>& lhs,
           const bsl::basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOC2>& rhs)
                                                         BSLS_KEYWORD_NOEXCEPT;
template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOC1, class ALLOC2>
bool
operator==(const bsl::basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOC1>& lhs,
           const std::basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOC2>& rhs)
                                                         BSLS_KEYWORD_NOEXCEPT;
template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOC>
bool operator==(const CHAR_TYPE                                  *lhs,
                const basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOC>&  rhs);
template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOC>
bool operator==(const basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOC>&  lhs,
                const CHAR_TYPE                                  *rhs);
    // Return 'true' if the specified 'lhs' string has the same value as the
    // specified 'rhs' string, and 'false' otherwise.  Two strings have the
    // same value if they have the same length, and the characters at each
    // respective position have the same value according to 'CHAR_TRAITS::eq'.

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOC>
bool operator!=(const basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOC>&  lhs,
                const basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOC>&  rhs)
                                                         BSLS_KEYWORD_NOEXCEPT;
template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOC1, class ALLOC2>
bool
operator!=(const std::basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOC1>& lhs,
           const bsl::basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOC2>& rhs)
                                                         BSLS_KEYWORD_NOEXCEPT;
template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOC1, class ALLOC2>
bool
operator!=(const bsl::basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOC1>& lhs,
           const std::basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOC2>& rhs)
                                                         BSLS_KEYWORD_NOEXCEPT;

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOC>
bool operator!=(const CHAR_TYPE                                  *lhs,
                const basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOC>&  rhs);
template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOC>
bool operator!=(const basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOC>&  lhs,
                const CHAR_TYPE                                  *rhs);
    // Return 'true' if the specified 'lhs' string has a different value from
    // the specified 'rhs' string, and 'false' otherwise.  Two strings have the
    // same value if they have the same length, and the characters at each
    // respective position have the same value according to 'CHAR_TRAITS::eq'.

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOC>
bool operator<(const basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOC>&  lhs,
               const basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOC>&  rhs)
                                                         BSLS_KEYWORD_NOEXCEPT;
template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOC1, class ALLOC2>
bool
operator<(const std::basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOC1>& lhs,
          const bsl::basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOC2>& rhs)
                                                         BSLS_KEYWORD_NOEXCEPT;
template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOC1, class ALLOC2>
bool
operator<(const bsl::basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOC1>& lhs,
          const std::basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOC2>& rhs)
                                                         BSLS_KEYWORD_NOEXCEPT;
template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOC>

bool operator<(const CHAR_TYPE                                  *lhs,
               const basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOC>&  rhs);
template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOC>
bool operator<(const basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOC>&  lhs,
               const CHAR_TYPE                                  *rhs);
    // Return 'true' if the specified 'lhs' string has a lexicographically
    // smaller value than the specified 'rhs' string, and 'false' otherwise.
    // See {Lexicographical Comparisons}.

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOC>
bool operator>(const basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOC>& lhs,
               const basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOC>& rhs)
                                                         BSLS_KEYWORD_NOEXCEPT;
template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOC1, class ALLOC2>
bool
operator>(const std::basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOC1>& lhs,
          const bsl::basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOC2>& rhs)
                                                         BSLS_KEYWORD_NOEXCEPT;
template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOC1, class ALLOC2>
bool
operator>(const bsl::basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOC1>& lhs,
          const std::basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOC2>& rhs)
                                                         BSLS_KEYWORD_NOEXCEPT;

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOC>
bool operator>(const CHAR_TYPE                                  *lhs,
               const basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOC>&  rhs);
template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOC>
bool operator>(const basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOC>&  lhs,
               const CHAR_TYPE                                  *rhs);
    // Return 'true' if the specified 'lhs' string has a lexicographically
    // larger value than the specified 'rhs' string, and 'false' otherwise.
    // See {Lexicographical Comparisons}.

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOC>
bool operator<=(const basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOC>&  lhs,
                const basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOC>&  rhs)
                                                         BSLS_KEYWORD_NOEXCEPT;
template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOC1, class ALLOC2>
bool
operator<=(const std::basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOC1>& lhs,
           const bsl::basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOC2>& rhs)
                                                         BSLS_KEYWORD_NOEXCEPT;
template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOC1, class ALLOC2>
bool
operator<=(const bsl::basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOC1>& lhs,
           const std::basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOC2>& rhs)
                                                         BSLS_KEYWORD_NOEXCEPT;

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOC>
bool operator<=(const CHAR_TYPE                                  *lhs,
                const basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOC>&  rhs);
template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOC>
bool operator<=(const basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOC>&  lhs,
                const CHAR_TYPE                                  *rhs);
    // Return 'true' if the specified 'lhs' string has a value
    // lexicographically smaller than or or equal to the specified 'rhs'
    // string, and 'false' otherwise.  See {Lexicographical Comparisons}.

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOC>
bool operator>=(const basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOC>&  lhs,
                const basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOC>&  rhs)
                                                         BSLS_KEYWORD_NOEXCEPT;
template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOC1, class ALLOC2>
bool
operator>=(const std::basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOC1>& lhs,
           const bsl::basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOC2>& rhs)
                                                         BSLS_KEYWORD_NOEXCEPT;
template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOC1, class ALLOC2>
bool
operator>=(const bsl::basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOC1>& lhs,
           const std::basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOC2>& rhs)
                                                         BSLS_KEYWORD_NOEXCEPT;

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOC>
bool operator>=(const CHAR_TYPE                                  *lhs,
                const basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOC>&  rhs);
template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOC>
bool operator>=(const basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOC>&  lhs,
                const CHAR_TYPE                                  *rhs);
    // Return 'true' if the specified 'lhs' string has a value
    // lexicographically larger than or equal to the specified 'rhs' string,
    // and 'false' otherwise.  See {Lexicographical Comparisons}.

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>
operator+(const basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>&     lhs,
          const basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>&     rhs);
#ifdef BSLSTL_STRING_SUPPORT_RVALUE_ADDITION_OPERATORS
template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
basic_string<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>
operator+(bsl::basic_string<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR> &&  lhs,
          const basic_string<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>&   rhs);
template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
basic_string<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>
operator+(const basic_string<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>&   lhs,
          bsl::basic_string<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR> &&  rhs);
template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
basic_string<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>
operator+(bsl::basic_string<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR> &&  lhs,
          bsl::basic_string<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR> &&  rhs);
#endif  // BSLSTL_STRING_SUPPORT_RVALUE_ADDITION_OPERATORS
template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOC1, class ALLOC2>
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOC2>
operator+(const std::basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOC1>&   lhs,
          const bsl::basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOC2>&   rhs);
#ifdef BSLSTL_STRING_SUPPORT_RVALUE_ADDITION_OPERATORS
template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOC1, class ALLOC2>
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOC2>
operator+(const std::basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOC1>&   lhs,
          bsl::basic_string<CHAR_TYPE, CHAR_TRAITS, ALLOC2> &&     rhs);
#endif  // BSLSTL_STRING_SUPPORT_RVALUE_ADDITION_OPERATORS
template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOC1, class ALLOC2>
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOC1>
operator+(const bsl::basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOC1>&   lhs,
          const std::basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOC2>&   rhs);
#ifdef BSLSTL_STRING_SUPPORT_RVALUE_ADDITION_OPERATORS
template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOC1, class ALLOC2>
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOC1>
operator+(bsl::basic_string<CHAR_TYPE, CHAR_TRAITS, ALLOC1> &&     lhs,
          const std::basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOC2>&   rhs);
#endif  // BSLSTL_STRING_SUPPORT_RVALUE_ADDITION_OPERATORS
template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>
operator+(const CHAR_TYPE                                         *lhs,
          const basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>&     rhs);
#ifdef BSLSTL_STRING_SUPPORT_RVALUE_ADDITION_OPERATORS
template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
basic_string<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>
operator+(const CHAR_TYPE                                         *lhs,
          bsl::basic_string<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR> &&  rhs);
#endif  // BSLSTL_STRING_SUPPORT_RVALUE_ADDITION_OPERATORS
template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>
operator+(CHAR_TYPE                                                lhs,
          const basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>&     rhs);
#ifdef BSLSTL_STRING_SUPPORT_RVALUE_ADDITION_OPERATORS
template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>
operator+(CHAR_TYPE                                                lhs,
          bsl::basic_string<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR> &&  rhs);
#endif  // BSLSTL_STRING_SUPPORT_RVALUE_ADDITION_OPERATORS
template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>
operator+(const basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>&     lhs,
          const CHAR_TYPE                                         *rhs);
#ifdef BSLSTL_STRING_SUPPORT_RVALUE_ADDITION_OPERATORS
template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>
operator+(bsl::basic_string<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR> &&  lhs,
          const CHAR_TYPE                                         *rhs);
#endif  // BSLSTL_STRING_SUPPORT_RVALUE_ADDITION_OPERATORS
template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>
operator+(const basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>&     lhs,
          CHAR_TYPE                                                rhs);
#ifdef BSLSTL_STRING_SUPPORT_RVALUE_ADDITION_OPERATORS
template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>
operator+(bsl::basic_string<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR> &&  lhs,
          CHAR_TYPE                                                rhs);
#endif  // BSLSTL_STRING_SUPPORT_RVALUE_ADDITION_OPERATORS
    // Return the concatenation of strings constructed from the specified 'lhs'
    // and 'rhs' arguments, i.e., 'basic_string(lhs).append(rhs)'.  The
    // allocator of the returned string is determined per the rules in P1165
    // (https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1165r1.html).
    // Note that overloads that accept rvalue references are implemented for
    // C++11 and later only.

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
std::basic_ostream<CHAR_TYPE, CHAR_TRAITS>&
operator<<(std::basic_ostream<CHAR_TYPE, CHAR_TRAITS>&          os,
           const basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>& str);
    // Write the string specified by 'str' into the output stream specified by
    // 'os', and return 'os'.  If the string is shorter than 'os.width()', then
    // it is padded to 'os.width()' with the current 'os.fill()' character.
    // The padding, if any, is output after the string (on the right) if
    // 'os.flags() | ios::left' is non-zero and before the string otherwise.
    // This function will do nothing unless 'os.good()' is true on entry.

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
std::basic_istream<CHAR_TYPE, CHAR_TRAITS>&
operator>>(std::basic_istream<CHAR_TYPE, CHAR_TRAITS>&     is,
           basic_string<CHAR_TYPE,CHAR_TRAITS, ALLOCATOR>& str);
    // Replace the contents of the specified 'str' string with a word read from
    // the specified 'is' input stream, and return 'is'.  The word begins at
    // the first non-whitespace character on the input stream and ends when
    // another whitespace character (or eof) is found.  The trailing whitespace
    // character is left on the input stream.  If 'is.good()' is not true on
    // entry or if eof is found before any non-whitespace characters, then
    // 'str' is unchanged and 'is.fail()' is becomes true.  If eof is detected
    // after some characters have been read into 'str', then 'is.eof()' becomes
    // true, but 'is.fail()' does not.

#if defined (BSLS_LIBRARYFEATURES_HAS_CPP11_BASELINE_LIBRARY) && \
    defined (BSLS_COMPILERFEATURES_SUPPORT_INLINE_NAMESPACE)
inline namespace literals {
inline namespace string_literals {
 string operator ""_s(const char    *characterString, std::size_t length);
wstring operator ""_s(const wchar_t *characterString, std::size_t length);
    // Convert a character sequence of the specified 'length' excluding the
    // terminating null character starting at the beginning of the specified
    // 'characterString' to a string object of the indicated return type.  Use
    // the 'bslma::Default::defaultAllocator()' to supply memory.  (See the
    // "User-Defined Literals" section in the component-level documentation.)
    //
    // Example:
    //..
    //     using namespace bsl::string_literals;
    //     bsl::string str1 = "123\0abc";
    //     bsl::string str2 = "123\0abc"_s;
    //     assert(3 == str1.size());
    //     assert(7 == str2.size());
    //
    //     bsl::wstring str3 = L"123\0abc"_s;
    //     assert(7 == str3.size());
    //..

#if !defined(BSLS_PLATFORM_OS_SOLARIS) ||                                   \
    (defined(BSLS_PLATFORM_CMP_GNU) && BSLS_PLATFORM_CMP_VERSION >= 800000)
 string operator ""_S(const char    *characterString, std::size_t length);
wstring operator ""_S(const wchar_t *characterString, std::size_t length);
    // Convert a character sequence of the specified 'length' excluding the
    // terminating null character starting at the beginning of the specified
    // 'characterString' to a string object of the indicated return type.  Use
    // the 'bslma::Default::globalAllocator()' to supply memory.  (See the
    // "Memory Allocation For a File-Scope Strings" section in the
    // component-level documentation.)
    //
    // Example:
    //..
    //     using namespace bsl::string_literals;
    //     static const bsl::string  g_str1 =  "123\0abc"_S;
    //     static const bsl::wstring g_str2 = L"123\0abc"_S;
    //..
#endif
}
}

#endif  // BSLS_LIBRARYFEATURES_HAS_CPP11_BASELINE_LIBRARY &&
        // BSLS_COMPILERFEATURES_SUPPORT_INLINE_NAMESPACE

// FREE FUNCTIONS
template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
void swap(basic_string<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>& a,
          basic_string<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>& b)
                           BSLS_KEYWORD_NOEXCEPT_SPECIFICATION(
                               BSLS_KEYWORD_NOEXCEPT_OPERATOR(a.swap(b)));
    // Exchange the value of the specified 'a' object with that of the
    // specified 'b' object; also exchange the allocator of 'a' with that of
    // 'b' if the (template parameter) type 'ALLOCATOR' has the
    // 'propagate_on_container_swap' trait, and do not modify either allocator
    // otherwise.  This function provides the no-throw exception-safety
    // guarantee.  This operation has 'O[1]' complexity if either 'a' was
    // created with the same allocator as 'b' or 'ALLOCATOR' has the
    // 'propagate_on_container_swap' trait; otherwise, it has 'O[n + m]'
    // complexity, where 'n' and 'm' are the lengths of 'a' and 'b',
    // respectively.  Note that this function's support for swapping objects
    // created with different allocators when 'ALLOCATOR' does not have the
    // 'propagate_on_container_swap' trait is a departure from the C++
    // Standard.

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
std::basic_istream<CHAR_TYPE, CHAR_TRAITS>&
getline(std::basic_istream<CHAR_TYPE, CHAR_TRAITS>&     is,
        basic_string<CHAR_TYPE,CHAR_TRAITS, ALLOCATOR>& str,
        CHAR_TYPE                                       delim);
    // Replace the contents of the specified 'str' string by extracting
    // characters from the specified 'is' stream until the specified 'delim'
    // character is extracted, and return 'is'.  The 'delim' character is
    // removed from the input stream but is not appended to 'str'.  If an 'eof'
    // is detected before 'delim', then the characters up to the 'eof' are put
    // into 'str' and 'is.eof()' becomes true.  If 'is.good()' is false on
    // entry, then do nothing, otherwise if no characters are extracted (e.g.,
    // because because the stream is at eof), 'str' will become empty and
    // 'is.fail()' will become true.

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
std::basic_istream<CHAR_TYPE, CHAR_TRAITS>&
getline(std::basic_istream<CHAR_TYPE, CHAR_TRAITS>&     is,
        basic_string<CHAR_TYPE,CHAR_TRAITS, ALLOCATOR>& str);
    // Replace the contents of the specified 'str' string by extracting
    // characters from the specified 'is' stream until a newline character
    // (is.widen('\n') is extracted, and return 'is'.  The newline character is
    // removed from the input stream but is not appended to 'str'.  If an 'eof'
    // is detected before the newline, then the characters up to the 'eof' are
    // put into 'str' and 'is.eof()' becomes true.  If 'is.good()' is false on
    // entry, then do nothing, otherwise if no characters are extracted (e.g.,
    // because because the stream is at eof), 'str' will become empty and
    // 'is.fail()' will become true.

int  stoi(const string&  str, std::size_t *pos = 0, int base = 10);
int  stoi(const wstring& str, std::size_t *pos = 0, int base = 10);
long stol(const string&  str, std::size_t *pos = 0, int base = 10);
long stol(const wstring& str, std::size_t *pos = 0, int base = 10);
unsigned long stoul(const string&  str, std::size_t *pos = 0, int base = 10);
unsigned long stoul(const wstring& str, std::size_t *pos = 0, int base = 10);
long long stoll(const string&  str, std::size_t *pos = 0, int base = 10);
long long stoll(const wstring& str, std::size_t *pos = 0, int base = 10);
unsigned long long stoull(const string&   str,
                          std::size_t    *pos = 0,
                          int             base = 10);
unsigned long long stoull(const wstring&  str,
                          std::size_t    *pos = 0,
                          int             base = 10);
    // Return the value of the specified 'str' by parsing the string and
    // interpreting its content as an integral number.  Optionally specify
    // 'pos' whose value is set to the position of the next character in 'str'
    // after the numerical value.  Optionally specify 'base' used to change the
    // interpretation of 'str' to a integral number written in the given
    // 'base'.  Valid bases are bases in the range of [2,36] and base 0, where
    // base 0 automatically determines the base while parsing the string: the
    // base will be 16 if the number is prefixed with '0x' or '0X', base 8 if
    // the number is prefixed with a '0', and base 10 otherwise.  The function
    // ignores leading white space characters and interprets as many characters
    // possible to form a valid integral number in the chosen base.  If no
    // conversion could be performed, then an 'invalid_argument' exception is
    // thrown.  If the value read is out of range of the return type, then an
    // 'out_of_range' exception is thrown.  The behavior is undefined unless
    // 'base' is valid.  Note that negative numbers are parsed by interpreting
    // the numeric sequence following the '-' character, and then negating the
    // result, so that 'stoul' and 'stoull' have defined results for negative
    // numbers where the absolute value falls in the valid range for the
    // corresponding signed conversion.

float  stof(const string&  str, std::size_t *pos =0);
float  stof(const wstring& str, std::size_t *pos =0);
double stod(const string&  str, std::size_t *pos =0);
double stod(const wstring& str, std::size_t *pos =0);
long double stold(const string&  str, std::size_t *pos =0);
long double stold(const wstring& str, std::size_t *pos =0);
    // Parses 'str' interpreting its contents as a floating point number. In
    // C++11 if the number in 'str' is prefixed with '0x' or '0X' the string
    // will be interpreted as a hex number.  If there is no leading 0x or 0X
    // the string will be interpreted as a decimal number.  Optionally specify
    // 'pos' whose value is set to the position of the next character after the
    // numerical value.  The function ignores leading white space characters
    // and interprets as many characters possible to form a valid floating
    // point number.  If no conversion could be performed, then an
    // 'invalid_argument' exception is thrown.  If the value read is out of
    // range of the return type, then an 'out_of_range' exception is thrown.

string to_string(int value);
    // Constructs a string with contents equal to the specified 'value'.  The
    // contents of the string will be the same as what
    // 'std::sprintf(buf, "%d", value)' would produce with a sufficiently large
    // buffer.
string to_string(long value);
    // Constructs a string with contents equal to the specified 'value'.  The
    // contents of the string will be the same as what
    // 'std::sprintf(buf, "%ld", value)' would produce with a sufficiently
    // large buffer.
string to_string(long long value);
    // Constructs a string with contents equal to the specified 'value'.  The
    // contents of the string will be the same as what
    // 'std::sprintf(buf, "%lld", value)' would produce with a sufficiently
    // large buffer.
string to_string(unsigned value);
    // Constructs a string with contents equal to the specified 'value'.  The
    // contents of the string will be the same as what
    // 'std::sprintf(buf, "%u", value)' would produce with a sufficiently large
    // buffer.
string to_string(unsigned long value);
    // Constructs a string with contents equal to the specified 'value'.  The
    // contents of the string will be the same as what
    // 'std::sprintf(buf, "%lu", value)' would produce with a sufficiently
    // large buffer.
string to_string(unsigned long long value);
    // Constructs a string with contents equal to the specified 'value'.  The
    // contents of the string will be the same as what
    // 'std::sprintf(buf, "%llu", value)' would produce with a sufficiently
    // large buffer.
string to_string(float value);
string to_string(double value);
    // converts a floating point value to a string with the same contents as
    // what 'std::sprintf(buf, "%f", value)' would produce for a sufficiently
    // large buffer.
string to_string(long double value);
    // converts a floating point value to a string with the same contents as
    // what 'std::sprintf(buf, "%Lf", value)' would produce for a sufficiently
    // large buffer.

wstring to_wstring(int value);
    // Constructs a string with contents equal to the specified 'value'.  The
    // contents of the string will be the same as what
    // 'std::swprintf(buf, L"%d", value)' would produce with a sufficiently
    // large buffer.
wstring to_wstring(long value);
    // Constructs a string with contents equal to the specified 'value'.  The
    // contents of the string will be the same as what
    // 'std::swprintf(buf, L"%ld", value)' would produce with a sufficiently
    // large buffer.
wstring to_wstring(long long value);
    // Constructs a string with contents equal to the specified 'value'.  The
    // contents of the string will be the same as what
    // 'std::swprintf(buf, L"%lld", value)' would produce with a sufficiently
    // large buffer.
wstring to_wstring(unsigned value);
    // Constructs a string with contents equal to the specified 'value'.  The
    // contents of the string will be the same as what
    // 'std::swprintf(buf, L"%u", value)' would produce with a sufficiently
    // large buffer.
wstring to_wstring(unsigned long value);
    // Constructs a string with contents equal to the specified 'value'.  The
    // contents of the string will be the same as what
    // 'std::swprintf(buf, L"%lu", value)' would produce with a sufficiently
    // large buffer.
wstring to_wstring(unsigned long long value);
    // Constructs a string with contents equal to the specified 'value'.  The
    // contents of the string will be the same as what
    // 'std::swprintf(buf, L"%llu", value)' would produce with a sufficiently
    // large buffer.
wstring to_wstring(float value);
wstring to_wstring(double value);
    // converts a floating point value to a string with the same contents as
    // what 'std::sprintf(buf, sz, L"%f", value)' would produce for a
    // sufficiently large buffer.
wstring to_wstring(long double value);
    // converts a floating point value to a string with the same contents as
    // 'what std::sprintf(buf, sz, L"%Lf", value)' would produce for a
    // sufficiently large buffer.

enum MaxDecimalStringLengths{
    // This 'enum' give upper bounds on the maximum string lengths storing each
    // scalar numerical type.  It is safe to use stack-allocated buffers of
    // these sizes for generating decimal representations of the corresponding
    // type, including sign and terminating null character, using the default
    // precision of 6 significant digits for floating point types.

    e_MAX_SHORT_STRLEN10      = 2 + sizeof(short) * 3,
    e_MAX_INT_STRLEN10        = 2 + sizeof(int) * 3,
    e_MAX_INT64_STRLEN10      = 26,
    e_MAX_FLOAT_STRLEN10      = 48,
    e_MAX_DOUBLE_STRLEN10     = 318,
    e_MAX_LONGDOUBLE_STRLEN10 = 318,
    e_MAX_SCALAR_STRLEN10     = e_MAX_INT64_STRLEN10
};

// HASH SPECIALIZATIONS
template <class HASHALG, class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
void hashAppend(HASHALG&                                               hashAlg,
                const basic_string<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>& input);
    // Pass the specified 'input' string to the specified 'hashAlg' hashing
    // algorithm of the (template parameter) type 'HASHALG'.

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
std::size_t
hashBasicString(const basic_string<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>& str);
    // Return a hash value for the specified 'str'.

std::size_t hashBasicString(const string& str);
    // Return a hash value for the specified 'str'.

std::size_t hashBasicString(const wstring& str);
    // Return a hash value for the specified 'str'.

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
struct hash<basic_string<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR> >
    : ::BloombergLP::bslh::Hash<>
    // Specialize 'bsl::hash' for strings, including an overload for pointers
    // to allow character arrays to be hashed without converting them first.
{
    // PUBLIC ACCESSORS
    std::size_t operator()(
        const basic_string<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>& input) const;
        // Compute and return the hash value of the specified 'input'.

    std::size_t operator()(const CHAR_TYPE *input) const;
        // Compute and return the hash value of the contents of the specified
        // null-terminated 'input'.  This value will be the same as the hash
        // value of a 'basic_string' constructed from 'input'.
};

#if defined(BSLS_PLATFORM_CMP_SUN) && BSLS_PLATFORM_CMP_VERSION < 0x5130
// {DRQS 132030795}

// Sun CC 12.3 has trouble with the partial specializations above in certain
// circumstances (see {DRQS 132030795}).  Adding these explicit specializations
// for 'string' and 'wstring' makes the problematic cases work.

template <>
struct hash<string> : ::BloombergLP::bslh::Hash<>
{
    // PUBLIC ACCESSORS
    std::size_t operator()(const string& input) const;
        // Compute and return the hash value of the specified 'input'.

    std::size_t operator()(const char *input) const;
        // Compute and return the hash value of the contents of the specified
        // null-terminated 'input'.  This value will be the same as the hash
        // value of a 'basic_string' constructed from 'input'.
};

template <>
struct hash<wstring> : ::BloombergLP::bslh::Hash<>
{
    // PUBLIC ACCESSORS
    std::size_t operator()(const wstring& input) const;
        // Compute and return the hash value of the specified 'input'.

    std::size_t operator()(const wchar_t *input) const;
        // Compute and return the hash value of the contents of the specified
        // null-terminated 'input'.  This value will be the same as the hash
        // value of a 'basic_string' constructed from 'input'.
};

#endif

}  // close namespace bsl

namespace BloombergLP {
namespace bslh {

template <class HASHALG, class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
BSLS_PLATFORM_AGGRESSIVE_INLINE
void hashAppend(
           HASHALG&                                                    hashAlg,
           const std::basic_string<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>& input);
    // Pass the specified 'input' string to the specified 'hashAlg' hashing
    // algorithm of the (template parameter) type 'HASHALG'.  Note that this
    // function violates the BDE coding standard, adding a function for a
    // namespace for a different package, and none of the function parameters
    // are from this package either.  This is necessary in order to provide an
    // implementation of 'bslh::hashAppend' for the (native) standard library
    // 'string' type as we are not allowed to add overloads directly into
    // namespace 'std', and this component essentially provides the interface
    // between 'bsl' and 'std' string types.

}  // close namespace bslh
}  // close enterprise namespace

// ============================================================================
//                       FUNCTION TEMPLATE DEFINITIONS
// ============================================================================
// See IMPLEMENTATION NOTES in the '.cpp' before modifying anything below.

namespace bsl {
                          // ----------------
                          // class String_Imp
                          // ----------------

// CLASS METHODS
template <class CHAR_TYPE, class SIZE_TYPE>
SIZE_TYPE
String_Imp<CHAR_TYPE, SIZE_TYPE>::computeNewCapacity(SIZE_TYPE newLength,
                                                     SIZE_TYPE oldCapacity,
                                                     SIZE_TYPE maxSize)
{
    BSLS_ASSERT_SAFE(newLength >= oldCapacity);

    SIZE_TYPE newCapacity = oldCapacity + (oldCapacity >> 1);
        // We must exercise an exponential growth, otherwise we cannot
        // guarantee amortized time for 'append', 'insert', 'push_back',
        // 'replace', etc.  1.5 growth factor helps to reuse previously
        // allocated and freed memory blocks on frequent re-allocations due to
        // a continuous string growth (for example, when calling 'push_back' in
        // a loop).
        //
        // TBD: consider bounding the exponential growth when 'newCapacity' is
        // about several megabytes.

    if (newLength > newCapacity) {
        newCapacity = newLength;
    }

    if (newCapacity < oldCapacity || newCapacity > maxSize) {  // overflow
        newCapacity = maxSize;
    }

    return newCapacity;
}

// CREATORS
template <class CHAR_TYPE, class SIZE_TYPE>
BSLS_PLATFORM_AGGRESSIVE_INLINE
String_Imp<CHAR_TYPE, SIZE_TYPE>::String_Imp()
: d_start_p(0)
, d_length(0)
, d_capacity(this->SHORT_BUFFER_CAPACITY)  // See {DRQS 131792157} for 'this'.
{
}

template <class CHAR_TYPE, class SIZE_TYPE>
BSLS_PLATFORM_AGGRESSIVE_INLINE
String_Imp<CHAR_TYPE, SIZE_TYPE>::String_Imp(SIZE_TYPE length,
                                             SIZE_TYPE capacity)
: d_start_p(0)
, d_length(length)
, d_capacity(capacity <= static_cast<SIZE_TYPE>(this->SHORT_BUFFER_CAPACITY)
                      ?  static_cast<SIZE_TYPE>(this->SHORT_BUFFER_CAPACITY)
                      :  capacity)         // See {DRQS 131792157} for 'this'.
{
}

// MANIPULATORS
template <class CHAR_TYPE, class SIZE_TYPE>
void String_Imp<CHAR_TYPE, SIZE_TYPE>::swap(String_Imp& other)
{
    if (!isShortString() && !other.isShortString()) {
        // If both strings are long, swap the individual fields.
        BloombergLP::bslalg::ScalarPrimitives::swap(d_length, other.d_length);
        BloombergLP::bslalg::ScalarPrimitives::swap(d_capacity,
                                                    other.d_capacity);
        BloombergLP::bslalg::ScalarPrimitives::swap(d_start_p,
                                                    other.d_start_p);
    }
    else {
        // Otherwise bitwise-swap the whole objects (relies on the
        // BitwiseMoveable type trait).
        BloombergLP::bslalg::ScalarPrimitives::swap(*this, other);
    }
}

// PRIVATE MANIPULATORS
template <class CHAR_TYPE, class SIZE_TYPE>
inline
void String_Imp<CHAR_TYPE, SIZE_TYPE>::resetFields()
{
    d_start_p  = 0;
    d_length   = 0;
    d_capacity = this->SHORT_BUFFER_CAPACITY;
                                           // See {DRQS 131792157} for 'this'.
}

template <class CHAR_TYPE, class SIZE_TYPE>
inline
CHAR_TYPE *String_Imp<CHAR_TYPE, SIZE_TYPE>::dataPtr()
{
    return isShortString()
           ? reinterpret_cast<CHAR_TYPE *>((void *)d_short.buffer())
           : d_start_p;
}

// PRIVATE ACCESSORS
template <class CHAR_TYPE, class SIZE_TYPE>
inline
bool String_Imp<CHAR_TYPE, SIZE_TYPE>::isShortString() const
{
    return d_capacity == this->SHORT_BUFFER_CAPACITY;
                                           // See {DRQS 131792157} for 'this'.
}

template <class CHAR_TYPE, class SIZE_TYPE>
inline
const CHAR_TYPE *String_Imp<CHAR_TYPE, SIZE_TYPE>::dataPtr() const
{
    return isShortString()
          ? reinterpret_cast<const CHAR_TYPE *>((const void *)d_short.buffer())
          : d_start_p;
}

                    // ------------------------------
                    // class bsl::String_ClearProctor
                    // ------------------------------

// CREATORS
template <class FULL_STRING_TYPE>
String_ClearProctor<FULL_STRING_TYPE>::String_ClearProctor(
                                                   FULL_STRING_TYPE *stringPtr)
: d_string_p(stringPtr)
, d_originalLength(stringPtr->d_length)
{
    d_string_p->d_length = 0;
}

template <class FULL_STRING_TYPE>
String_ClearProctor<FULL_STRING_TYPE>::~String_ClearProctor()
{
    if (d_string_p) {
        d_string_p->d_length = d_originalLength;
    }
}

// MANIPULATORS
template <class FULL_STRING_TYPE>
void String_ClearProctor<FULL_STRING_TYPE>::release()
{
    d_string_p = 0;
}

                        // -----------------------
                        // class bsl::basic_string
                        // -----------------------

// CLASS DATA
template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
const typename basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::size_type
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::npos;

// PRIVATE CLASS METHODS
template<class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
inline
void
basic_string<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>::privateThrowLengthError(
                                                 bool        maxLengthExceeded,
                                                 const char *message)
{
    if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(maxLengthExceeded)) {
        BSLS_PERFORMANCEHINT_UNLIKELY_HINT;
        BloombergLP::bslstl::StdExceptUtil::throwLengthError(message);
    }
}

template<class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
inline
void
basic_string<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>::privateThrowOutOfRange(
                                                        bool        outOfRange,
                                                        const char *message)
{
    if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(outOfRange)) {
        BSLS_PERFORMANCEHINT_UNLIKELY_HINT;
        BloombergLP::bslstl::StdExceptUtil::throwOutOfRange(message);
    }
}

// PRIVATE MANIPULATORS
template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
inline
CHAR_TYPE *
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::privateAllocate(
                                                            size_type numChars)
{
    return this->allocateN((CHAR_TYPE *)0, numChars + 1);
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
inline
void basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::privateDeallocate()
{
    if (!this->isShortString()) {
        this->deallocateN(this->d_start_p, this->d_capacity + 1);
    }
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
inline
void
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::privateCopyFromOutOfPlaceBuffer(
                                                  const basic_string& original)
{
    BSLS_ASSERT_SAFE(!this->isShortString());
    BSLS_ASSERT_SAFE(!original.isShortString());

    // Note that it is possible that 'original' is not a short-string, but its
    // length has been updated to fit in the short-string buffer (so 'this'
    // copy should be a short-string).

    static_cast<Imp &>(*this) = Imp(original.length(), original.length());

    if (!this->isShortString()) {
        this->d_start_p = privateAllocate(this->d_capacity);
    }

    CHAR_TRAITS::copy(this->dataPtr(), original.data(), this->d_length + 1);
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>&
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::privateAppend(
                                              const CHAR_TYPE *characterString,
                                              size_type        numChars,
                                              const char      *message)
{
    privateThrowLengthError(numChars > max_size() - length(), message);

    size_type  newLength  = this->d_length + numChars;
    size_type  newStorage = this->d_capacity;
    CHAR_TYPE *newBuffer  = privateReserveRaw(&newStorage,
                                              newLength,
                                              this->d_length);

    if (newBuffer) {
        CHAR_TRAITS::copy(newBuffer + this->d_length,
                          characterString,
                          numChars);
        CHAR_TRAITS::assign(*(newBuffer + newLength), CHAR_TYPE());

        privateDeallocate();

        this->d_start_p  = newBuffer;
        this->d_capacity = newStorage;
    }
    else {
        CHAR_TRAITS::move(this->dataPtr() + length(),
                          characterString,
                          numChars);
        CHAR_TRAITS::assign(*(this->dataPtr() + newLength), CHAR_TYPE());
    }

    this->d_length = newLength;
    return *this;
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>&
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::privateAppend(
                                                         size_type   numChars,
                                                         CHAR_TYPE   character,
                                                         const char *message)
{
    privateThrowLengthError(numChars > max_size() - length(), message);

    size_type newLength = this->d_length + numChars;
    privateReserveRaw(newLength);
    CHAR_TRAITS::assign(this->dataPtr() + this->d_length, numChars, character);
    this->d_length = newLength;
    CHAR_TRAITS::assign(*(this->dataPtr() + newLength), CHAR_TYPE());
    return *this;
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
inline
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>&
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::privateAppend(
                                                     iterator    first,
                                                     iterator    last,
                                                     const char *message,
                                                     std::forward_iterator_tag)
{
    BSLS_ASSERT_SAFE(first <= last);

    return privateAppend(const_iterator(first),
                         const_iterator(last),
                         message,
                         std::forward_iterator_tag());
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
inline
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>&
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::privateAppend(
                                                     const_iterator  first,
                                                     const_iterator  last,
                                                     const char     *message,
                                                     std::forward_iterator_tag)
{
    BSLS_ASSERT_SAFE(first <= last);
    return privateAppend(&*first, last - first, message);
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
template <class INPUT_ITER>
inline
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>&
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::privateAppend(
                                                       INPUT_ITER  first,
                                                       INPUT_ITER  last,
                                                       const char *message,
                                                       std::input_iterator_tag)
{
    basic_string temp(get_allocator());
    for (; first != last; ++first) {
        temp.push_back(*first);
    }
    if (length() == 0 && capacity() <= temp.capacity()) {
        quickSwapRetainAllocators(temp);

        // This object may not have been null-terminated because of
        // String_ClearProctor, so force null termination in the swapped-into
        // temporary.
        CHAR_TRAITS::assign(*(temp.dataPtr()), CHAR_TYPE());
        return *this;                                                 // RETURN
    }
    return privateAppend(temp.data(), temp.length(), message);
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
template <class INPUT_ITER>
inline
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>&
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::privateAppend(
                                                     INPUT_ITER  first,
                                                     INPUT_ITER  last,
                                                     const char *message,
                                                     std::forward_iterator_tag)
{
    size_type numChars = bsl::distance(first, last);
    privateThrowLengthError(numChars > max_size() - length(), message);

    size_type  newLength  = this->d_length + numChars;
    size_type  newStorage = this->d_capacity;
    CHAR_TYPE *newBuffer  = privateReserveRaw(&newStorage,
                                              newLength,
                                              this->d_length);

    if (newBuffer) {
        for (size_type pos = this->d_length; first != last; ++first, ++pos) {
            CHAR_TRAITS::assign(*(newBuffer + pos), *first);
        }

        privateDeallocate();

        this->d_start_p  = newBuffer;
        this->d_capacity = newStorage;
    }
    else {
        for (size_type pos = this->d_length; first != last; ++first, ++pos) {
            CHAR_TRAITS::assign(*(this->dataPtr() + pos), *first);
        }
    }

    CHAR_TRAITS::assign(*(this->dataPtr() + newLength), CHAR_TYPE());
    this->d_length = newLength;
    return *this;
}

template<class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
template<class INPUT_ITER>
inline
basic_string<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>&
basic_string<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>::privateAppend(
                                                           INPUT_ITER  first,
                                                           INPUT_ITER  last,
                                                           const char *message)
{
    return privateAppendDispatch(first,
                                 last,
                                 message,
                                 first,
                                 BloombergLP::bslmf::Nil());
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
template <class INPUT_ITER>
inline
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>&
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::privateAppendDispatch(
                              INPUT_ITER                              first,
                              INPUT_ITER                              last,
                              const char                             *message,
                              BloombergLP::bslmf::MatchArithmeticType,
                              BloombergLP::bslmf::Nil                 )
{
    return privateAppend((size_type)first, (CHAR_TYPE)last, message);
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
template <class INPUT_ITER>
inline
basic_string<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>&
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::privateAppendDispatch(
                                     INPUT_ITER                       first,
                                     INPUT_ITER                       last,
                                     const char                      *message,
                                     BloombergLP::bslmf::MatchAnyType,
                                     BloombergLP::bslmf::MatchAnyType )
{
    typename iterator_traits<INPUT_ITER>::iterator_category tag;
    return privateAppend(first, last, message, tag);
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
template <class FIRST_TYPE, class SECOND_TYPE>
inline
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>&
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::privateAssignDispatch(
                                                          FIRST_TYPE   first,
                                                          SECOND_TYPE  second,
                                                          const char  *message)
{
    {
        String_ClearProctor<basic_string> guard(this);
        privateAppend(first, second, message);
        guard.release();
    }

    return *this;
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
inline
typename basic_string<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>::Imp&
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::privateBase()
{
    return *static_cast<Imp *>(this);
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
void basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::privateClear(
                                                     bool deallocateBufferFlag)
{
    if (deallocateBufferFlag) {
        privateDeallocate();
        this->resetFields();
    }
    else {
        this->d_length = 0;
    }

    CHAR_TRAITS::assign(*begin(), CHAR_TYPE());
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
inline
void basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::privateInsertDispatch(
                                                       const_iterator position,
                                                       iterator       first,
                                                       iterator       last)
{
    BSLS_ASSERT_SAFE(first <= last);

    privateInsertDispatch(position,
                          const_iterator(first),
                          const_iterator(last));
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
void basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::privateInsertDispatch(
                                                       const_iterator position,
                                                       const_iterator first,
                                                       const_iterator last)
{
    BSLS_ASSERT_SAFE(first <= last);

    size_type pos = position - cbegin();
    privateThrowOutOfRange(
                       pos > length(),
                       "string<...>::insert<Iter>(pos,i,j): invalid position");

    size_type numChars = last - first;
    privateThrowLengthError(
                        numChars > max_size() - length(),
                        "string<...>::insert<Iter>(pos,i,j): string too long");

    privateInsertRaw(pos, &*first, numChars);
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
template <class INPUT_ITER>
inline
void basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::privateInsertDispatch(
                                                       const_iterator position,
                                                       INPUT_ITER     first,
                                                       INPUT_ITER     last)
{
    size_type pos = position - cbegin();
    privateReplaceDispatch(pos,
                           size_type(0),
                           first,
                           last,
                           first,
                           BloombergLP::bslmf::Nil());
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>&
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::privateInsertRaw(
                                              size_type        outPosition,
                                              const CHAR_TYPE *characterString,
                                              size_type        numChars)
{
    BSLS_ASSERT_SAFE(outPosition <= length());
    BSLS_ASSERT_SAFE(numChars <= max_size() - length());
    BSLS_ASSERT_SAFE(characterString || 0 == numChars);

    size_type  newLength  = this->d_length + numChars;
    size_type  newStorage = this->d_capacity;
    CHAR_TYPE *newBuffer  = privateReserveRaw(&newStorage,
                                              newLength,
                                              outPosition);

    if (newBuffer) {
        // Source and destination cannot overlap, order of next two copies is
        // arbitrary.  Do it left to right to maintain cache consistency.

        const CHAR_TYPE *tail    = this->dataPtr() + outPosition;
        size_type        tailLen = this->d_length - outPosition;

        CHAR_TRAITS::copy(newBuffer + outPosition, characterString, numChars);
        CHAR_TRAITS::copy(newBuffer + outPosition + numChars, tail, tailLen);
        CHAR_TRAITS::assign(*(newBuffer + newLength), CHAR_TYPE());

        privateDeallocate();

        this->d_start_p  = newBuffer;
        this->d_capacity = newStorage;
    }
    else {
        // Because of possible aliasing, we have to be very careful in which
        // order to move blocks.  If 'characterString' overlaps with tail, or
        // is entirely contained: in the former case, 'characterString' is
        // shifted by 'numChars' (takes 'first' onto 'last'); in the latter,
        // the tail moves in by 'numChars', so cannot overwrite
        // 'characterString'!

        const CHAR_TYPE *first   = characterString;
        const CHAR_TYPE *last    = characterString + numChars;
        CHAR_TYPE       *tail    = this->dataPtr() + outPosition;
        size_type        tailLen = this->d_length - outPosition;
        const CHAR_TYPE *shifted = (tail < first && last <= tail + tailLen)
                                 ? last    // 'first' shifted by 'numChars'
                                 : first;  // 'no shift

        CHAR_TRAITS::move(tail + numChars, tail, tailLen);
        CHAR_TRAITS::move(tail, shifted, numChars);
        CHAR_TRAITS::assign(*(this->dataPtr() + newLength), CHAR_TYPE());
    }

    this->d_length = newLength;
    return *this;
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>&
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::privateReplaceRaw(
                                              size_type        outPosition,
                                              size_type        outNumChars,
                                              const CHAR_TYPE *characterString,
                                              size_type        numChars)
{
    BSLS_ASSERT_SAFE(outPosition <= length());
    BSLS_ASSERT_SAFE(outNumChars <= length());
    BSLS_ASSERT_SAFE(outPosition <= length() - outNumChars);
    BSLS_ASSERT_SAFE(length() - outNumChars <= max_size() - numChars);
    BSLS_ASSERT_SAFE(characterString || 0 == numChars);

    const difference_type displacement =
                          static_cast<difference_type>(numChars - outNumChars);

    size_type  newLength  = this->d_length + displacement;
    size_type  newStorage = this->d_capacity;
    CHAR_TYPE *newBuffer  = privateReserveRaw(&newStorage,
                                              newLength,
                                              outPosition);

    const CHAR_TYPE *tail    = this->dataPtr() + outPosition + outNumChars;
    size_type        tailLen = this->d_length  - outPosition - outNumChars;

    if (newBuffer) {
        // Source and destination cannot overlap, order of next two copies is
        // arbitrary.  Do it left to right to maintain cache consistency.

        CHAR_TRAITS::copy(newBuffer + outPosition, characterString, numChars);
        CHAR_TRAITS::copy(newBuffer + outPosition + numChars, tail, tailLen);
        CHAR_TRAITS::assign(*(newBuffer + newLength), CHAR_TYPE());

        privateDeallocate();

        this->d_start_p  = newBuffer;
        this->d_capacity = newStorage;
        this->d_length = newLength;
        return *this;                                                 // RETURN
    }

    // Because of possible aliasing, we have to be very careful in which order
    // to move blocks.  There are up to three blocks if 'characterString'
    // overlaps with the tail.

    CHAR_TYPE       *dest  = this->dataPtr() + outPosition;
    const CHAR_TYPE *first = characterString;
    const CHAR_TYPE *last  = characterString + numChars;

    if (tail < last && last <= tail + tailLen) {
        // Either 'characterString' overlaps with tail, or is entirely
        // contained.

        if (first < tail) {
            // Not entirely contained: break '[first .. last)' at 'tail', and
            // move it in two steps, the second shifted but not the first.

            size_type prefix = tail - first, suffix = last - tail;
            if (outNumChars < numChars) {
                CHAR_TRAITS::move(dest + numChars, tail, tailLen);
                CHAR_TRAITS::move(dest, first, prefix);
            }
            else {
                CHAR_TRAITS::move(dest, first, prefix);
                CHAR_TRAITS::move(dest + numChars, tail, tailLen);
            }
            CHAR_TRAITS::move(dest + prefix,
                              last - suffix + displacement,
                              suffix);
        }
        else {
            // Entirely contained: copy 'tail' first, and copy
            // '[first .. last)' shifted by 'displacement'.

            CHAR_TRAITS::move(dest + numChars, tail, tailLen);
            CHAR_TRAITS::copy(dest, first + displacement, numChars);
        }
    }
    else {
        // Note: no aliasing in tail.

        if (outNumChars < numChars) {
            CHAR_TRAITS::move(dest + numChars, tail, tailLen);
            CHAR_TRAITS::move(dest, characterString, numChars);
        }
        else {
            CHAR_TRAITS::move(dest, characterString, numChars);
            CHAR_TRAITS::move(dest + numChars, tail, tailLen);
        }
    }
    CHAR_TRAITS::assign(*(this->dataPtr() + newLength), CHAR_TYPE());
    this->d_length = newLength;
    return *this;
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>&
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::privateReplaceRaw(
                                                         size_type outPosition,
                                                         size_type outNumChars,
                                                         size_type numChars,
                                                         CHAR_TYPE character)
{
    BSLS_ASSERT_SAFE(outPosition <= length());
    BSLS_ASSERT_SAFE(outNumChars <= length());
    BSLS_ASSERT_SAFE(outPosition <= length() - outNumChars);
    BSLS_ASSERT_SAFE(length() <= max_size() - numChars);

    size_type  newLength  = this->d_length - outNumChars + numChars;
    size_type  newStorage = this->d_capacity;
    CHAR_TYPE *newBuffer  = privateReserveRaw(&newStorage,
                                              newLength,
                                              outPosition);

    const CHAR_TYPE *tail    = this->dataPtr() + outPosition + outNumChars;
    size_type        tailLen = this->d_length  - outPosition - outNumChars;

    if (newBuffer) {
        CHAR_TYPE *dest = newBuffer + outPosition;

        CHAR_TRAITS::assign(dest, numChars, character);
        CHAR_TRAITS::copy(dest + numChars, tail, tailLen);
        CHAR_TRAITS::assign(*(newBuffer + newLength), CHAR_TYPE());

        privateDeallocate();

        this->d_start_p  = newBuffer;
        this->d_capacity = newStorage;
    }
    else {
        CHAR_TYPE *dest = this->dataPtr() + outPosition;

        CHAR_TRAITS::move(dest + numChars, tail, tailLen);
        CHAR_TRAITS::assign(dest, numChars, character);
        CHAR_TRAITS::assign(*(this->dataPtr() + newLength), CHAR_TYPE());
    }

    this->d_length = newLength;
    return *this;
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
template <class INPUT_ITER>
inline
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>&
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::privateReplaceDispatch(
                              size_type                               position,
                              size_type                               numChars,
                              INPUT_ITER                              first,
                              INPUT_ITER                              last,
                              BloombergLP::bslmf::MatchArithmeticType ,
                              BloombergLP::bslmf::Nil                 )
{
    return replace(position, numChars, (size_type)first, (CHAR_TYPE)last);
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
template <class INPUT_ITER>
inline
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>&
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::privateReplaceDispatch(
                                     size_type                        position,
                                     size_type                        numChars,
                                     INPUT_ITER                       first,
                                     INPUT_ITER                       last,
                                     BloombergLP::bslmf::MatchAnyType ,
                                     BloombergLP::bslmf::MatchAnyType )
{
    typename iterator_traits<INPUT_ITER>::iterator_category tag;
    return privateReplace(position, numChars, first, last, tag);
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
template <class INPUT_ITER>
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>&
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::privateReplace(
                                                       size_type  outPosition,
                                                       size_type  outNumChars,
                                                       INPUT_ITER first,
                                                       INPUT_ITER last,
                                                       std::input_iterator_tag)
{
    privateThrowOutOfRange(
               length() < outPosition,
               "string<...>::replace<InputIter>(pos,n,i,j): invalid position");

    basic_string temp(get_allocator());
    for (; first != last; ++first) {
        temp.push_back(*first);
    }
    if (outPosition == 0 && length() <= outNumChars) {
        // Note: can potentially shrink the capacity, hence the reserve.

        temp.privateReserveRaw(capacity());
        quickSwapRetainAllocators(temp);
        return *this;                                                 // RETURN
    }
    return privateReplaceRaw(outPosition,
                             outNumChars,
                             temp.data(),
                             temp.length());
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
template <class INPUT_ITER>
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>&
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::privateReplace(
                                                     size_type  outPosition,
                                                     size_type  outNumChars,
                                                     INPUT_ITER first,
                                                     INPUT_ITER last,
                                                     std::forward_iterator_tag)
{
    privateThrowOutOfRange(
                    length() < outPosition,
                    "string<...>::replace<Iter>(pos,n,i,j): invalid position");

    size_type numChars = bsl::distance(first, last);
    privateThrowLengthError(
                     max_size() - (length() - outPosition) < numChars,
                     "string<...>::replace<Iter>(pos,n,i,j): string too long");

    // Create a temp string because the 'first'/'last' iterator pair can alias
    // the current string; not using the constructor with two iterators because
    // it recurses back here.
    basic_string temp(numChars, CHAR_TYPE());

    for (size_type pos = 0; pos != numChars; ++first, ++pos) {
        temp[pos] = *first;
    }

    return privateReplaceRaw(outPosition,
                             outNumChars,
                             temp.data(),
                             temp.length());
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>&
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::privateReplace(
                                                     size_type      position,
                                                     size_type      numChars,
                                                     const_iterator first,
                                                     const_iterator last,
                                                     std::forward_iterator_tag)
{
    BSLS_ASSERT_SAFE(first <= last);

    privateThrowOutOfRange(
                    length() < position,
                    "string<...>::replace<Iter>(pos,n,i,j): invalid position");

    size_type numNewChars = bsl::distance(first, last);
    privateThrowLengthError(
                     max_size() - (length() - position) < numNewChars,
                     "string<...>::replace<Iter>(pos,n,i,j): string too long");

    return privateReplaceRaw(position, numChars, &*first, numNewChars);
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
BSLS_PLATFORM_AGGRESSIVE_INLINE
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>&
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::privateReplace(
                                                     size_type      position,
                                                     size_type      numChars,
                                                     iterator       first,
                                                     iterator       last,
                                                     std::forward_iterator_tag)
{
    BSLS_ASSERT_SAFE(first <= last);

    return privateReplace(position,
                          numChars,
                          const_iterator(first),
                          const_iterator(last),
                          std::forward_iterator_tag());
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
void basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::privateReserveRaw(
                                                         size_type newCapacity)
{
    BSLS_ASSERT_SAFE(newCapacity <= max_size());

    if (this->d_capacity < newCapacity) {
        size_type newStorage = this->computeNewCapacity(newCapacity,
                                                        this->d_capacity,
                                                        max_size());
        CHAR_TYPE *newBuffer = privateAllocate(newStorage);

        CHAR_TRAITS::copy(newBuffer, this->dataPtr(), this->d_length + 1);

        privateDeallocate();

        this->d_start_p  = newBuffer;
        this->d_capacity = newStorage;
    }
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
CHAR_TYPE *
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::privateReserveRaw(
                                                        size_type *storage,
                                                        size_type  newCapacity,
                                                        size_type  numChars)
{
    BSLS_ASSERT_SAFE(numChars <= length());
    BSLS_ASSERT_SAFE(newCapacity <= max_size());
    BSLS_ASSERT_SAFE(storage != 0);

    if (*storage >= newCapacity) {
        return 0;                                                     // RETURN
    }

    *storage = this->computeNewCapacity(newCapacity,
                                        *storage,
                                        max_size());

    CHAR_TYPE *newBuffer = privateAllocate(*storage);

    CHAR_TRAITS::copy(newBuffer, this->dataPtr(), numChars);
    return newBuffer;
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>&
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::privateResizeRaw(
                                                           size_type newLength,
                                                           CHAR_TYPE character)
{
    BSLS_ASSERT_SAFE(newLength <= max_size());

    privateReserveRaw(newLength);

    if (newLength > this->d_length) {
        CHAR_TRAITS::assign(this->dataPtr() + this->d_length,
                            newLength - this->d_length,
                            character);
    }
    this->d_length = newLength;
    CHAR_TRAITS::assign(*(this->dataPtr() + this->d_length), CHAR_TYPE());
    return *this;
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
inline
void basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::
                               quickSwapExchangeAllocators(basic_string& other)
{
    privateBase().swap(other.privateBase());
    using std::swap;
    swap(ContainerBase::allocator(), other.ContainerBase::allocator());
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
inline
void basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::
                                 quickSwapRetainAllocators(basic_string& other)
{
    privateBase().swap(other.privateBase());
}

// PRIVATE ACCESSORS
template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
int basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::privateCompareRaw(
                                          size_type        lhsPosition,
                                          size_type        lhsNumChars,
                                          const CHAR_TYPE *other,
                                          size_type        otherNumChars) const
{
    BSLS_ASSERT_SAFE(lhsPosition <= length());
    BSLS_ASSERT_SAFE(lhsNumChars <= length());
    BSLS_ASSERT_SAFE(lhsPosition <= length() - lhsNumChars);
    BSLS_ASSERT_SAFE(other);

    size_type numChars  = lhsNumChars < otherNumChars ? lhsNumChars
                                                      : otherNumChars;
    int       cmpResult = CHAR_TRAITS::compare(this->dataPtr() + lhsPosition,
                                               other,
                                               numChars);
    if (cmpResult) {
        return cmpResult;                                             // RETURN
    }
    if (lhsNumChars < otherNumChars) {
        return -1;                                                    // RETURN
    }
    if (lhsNumChars > otherNumChars) {
        return 1;                                                     // RETURN
    }
    return 0;
}

// CREATORS

                // *** 21.3.2 construct/copy/destroy: ***

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
inline
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::basic_string()
                                                          BSLS_KEYWORD_NOEXCEPT
: Imp()
, BloombergLP::bslalg::ContainerBase<allocator_type>(ALLOCATOR())
{
    CHAR_TRAITS::assign(*begin(), CHAR_TYPE());
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
inline
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::basic_string(
                                               const ALLOCATOR& basicAllocator)
                                                          BSLS_KEYWORD_NOEXCEPT
: Imp()
, ContainerBase(basicAllocator)
{
    CHAR_TRAITS::assign(*begin(), CHAR_TYPE());
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
BSLS_PLATFORM_AGGRESSIVE_INLINE
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::basic_string(
                                                  const basic_string& original)
: Imp(original)
, ContainerBase(AllocatorTraits::select_on_container_copy_construction(
                                                     original.get_allocator()))
{
    if (!this->isShortString()) {
        // Copy out-of-place string into either short buffer or new long
        // buffer, according to size.

        privateCopyFromOutOfPlaceBuffer(original);
    }
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
BSLS_PLATFORM_AGGRESSIVE_INLINE
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::basic_string(
                                            const basic_string& original,
                                            const ALLOCATOR&    basicAllocator)
: Imp(original)
, ContainerBase(basicAllocator)
{
    if (!this->isShortString()) {
        // Copy out-of-place string into either short buffer or new long
        // buffer, according to size.

        privateCopyFromOutOfPlaceBuffer(original);
    }
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
inline
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::basic_string(
                         BloombergLP::bslmf::MovableRef<basic_string> original)
                                                          BSLS_KEYWORD_NOEXCEPT
: Imp(original)
, ContainerBase(MoveUtil::access(original).get_allocator())
{
    if (!this->isShortString()) {   // nothing to fix up if string is short
        basic_string& originalRef = MoveUtil::access(original);
        originalRef.resetFields();
    }
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
inline
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::basic_string(
                   BloombergLP::bslmf::MovableRef<basic_string> original,
                   const ALLOCATOR&                             basicAllocator)
: Imp(original)
, ContainerBase(basicAllocator)
{
    if (!this->isShortString()) {   // nothing to fix up if string is short
        basic_string& originalRef = MoveUtil::access(original);

        if (this->get_allocator() == originalRef.get_allocator()) {
            originalRef.resetFields();
        }
        else {
            privateCopyFromOutOfPlaceBuffer(originalRef);
        }
    }
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
BSLS_PLATFORM_AGGRESSIVE_INLINE
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::basic_string(
                                            const basic_string& original,
                                            size_type           position,
                                            const ALLOCATOR&    basicAllocator)
: Imp()
, ContainerBase(basicAllocator)
{
    assign(original, position, npos);
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
BSLS_PLATFORM_AGGRESSIVE_INLINE
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::basic_string(
                                            const basic_string& original,
                                            size_type           position,
                                            size_type           numChars,
                                            const ALLOCATOR&    basicAllocator)
: Imp()
, ContainerBase(basicAllocator)
{
    assign(original, position, numChars);
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
#ifdef BSLS_COMPILERFEATURES_SUPPORT_CTAD
template <class>
#endif
BSLS_PLATFORM_AGGRESSIVE_INLINE
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::basic_string(
                                             const CHAR_TYPE  *characterString,
                                             const ALLOCATOR&  basicAllocator)
: Imp()
, ContainerBase(basicAllocator)
{
    BSLS_ASSERT_SAFE(characterString);

    assign(characterString);
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
BSLS_PLATFORM_AGGRESSIVE_INLINE
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::basic_string(
                                             const CHAR_TYPE  *characterString,
                                             size_type         numChars,
                                             const ALLOCATOR&  basicAllocator)
: Imp()
, ContainerBase(basicAllocator)
{
    BSLS_ASSERT_SAFE(characterString || 0 == numChars);

    assign(characterString, numChars);
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
#ifdef BSLS_COMPILERFEATURES_SUPPORT_CTAD
template <class>
#endif
BSLS_PLATFORM_AGGRESSIVE_INLINE
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::basic_string(
                                              size_type         numChars,
                                              CHAR_TYPE         character,
                                              const ALLOCATOR&  basicAllocator)
: Imp()
, ContainerBase(basicAllocator)
{
    assign(numChars, character);
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
template <class INPUT_ITER>
inline
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::basic_string(
                                               INPUT_ITER       first,
                                               INPUT_ITER       last,
                                               const ALLOCATOR& basicAllocator)
: Imp()
, ContainerBase(basicAllocator)
{
    append(first, last);
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
template <class ALLOC2>
BSLS_PLATFORM_AGGRESSIVE_INLINE
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::basic_string(
         const std::basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOC2>& original,
         const ALLOCATOR&                                       basicAllocator)
: Imp()
, ContainerBase(basicAllocator)
{
    this->assign(original.data(), original.length());
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
inline
basic_string<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>::basic_string(
           const BloombergLP::bslstl::StringRefData<CHAR_TYPE>& strRef,
           const ALLOCATOR&                                     basicAllocator)
: Imp()
, ContainerBase(basicAllocator)
{
    assign(strRef.data(), strRef.length());
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
template <class STRING_VIEW_LIKE_TYPE>
inline
basic_string<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>::basic_string(
               const STRING_VIEW_LIKE_TYPE& object
               BSLSTL_STRING_DEFINE_ONLY_CONVERTIBLE_TO_STRINGVIEW_PARAM_ALLOC)
: Imp()
, ContainerBase(basicAllocator)
{
    bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS> strView = object;
    assign(strView.data(), strView.length());
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
template <class STRING_VIEW_LIKE_TYPE>
inline
basic_string<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>::basic_string(
                     const STRING_VIEW_LIKE_TYPE& object,
                     size_type                    position,
                     size_type                    numChars,
                     const ALLOCATOR&             basicAllocator
                     BSLSTL_STRING_DEFINE_CONVERTIBLE_TO_STRINGVIEW_PARAM_VOID)
: Imp()
, ContainerBase(basicAllocator)
{
    bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS> strView = object;
    privateThrowOutOfRange(
            position > strView.length(),
            "string<...>::assign(const string_view&,pos,n): invalid position");

    if (numChars > strView.length() - position) {
        numChars = strView.length() - position;
    }

    assign(strView.data() + position, numChars);
}

#if defined(BSLS_COMPILERFEATURES_SUPPORT_GENERALIZED_INITIALIZERS)
template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
inline
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::basic_string(
                               std::initializer_list<CHAR_TYPE> values,
                               const ALLOCATOR&                 basicAllocator)
: Imp()
, ContainerBase(basicAllocator)
{
    append(values.begin(), values.end());
}
#endif

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
BSLS_PLATFORM_AGGRESSIVE_INLINE
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::~basic_string()
{
    // perform a validity check
    BSLS_ASSERT_SAFE((*this)[this->d_length] == CHAR_TYPE());
    BSLS_ASSERT_SAFE(capacity() >= length());

    privateDeallocate();
    this->d_length = npos;  // invalid length
}

// MANIPULATORS

                // *** 21.3.2 construct/copy/destroy: ***

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
BSLS_PLATFORM_AGGRESSIVE_INLINE
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>&
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::operator=(
                                                       const basic_string& rhs)
{
    if (BSLS_PERFORMANCEHINT_PREDICT_LIKELY(this != &rhs)) {
        if (AllocatorTraits::propagate_on_container_copy_assignment::value) {
            basic_string other(rhs, rhs.get_allocator());
            quickSwapExchangeAllocators(other);
        }
        else {
            privateAssignDispatch(
                  rhs.data(),
                  rhs.size(),
                  "string<...>::operator=(const string&...): string too long");
        }
    }
    return *this;
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
inline
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>&
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::operator=(
                              BloombergLP::bslmf::MovableRef<basic_string> rhs)
                                     BSLS_KEYWORD_NOEXCEPT_SPECIFICATION(
              AllocatorTraits::propagate_on_container_move_assignment::value ||
              AllocatorTraits::is_always_equal::value)
{
    basic_string& lvalue = rhs;

    if (BSLS_PERFORMANCEHINT_PREDICT_LIKELY(this != &lvalue)) {
        if (AllocatorTraits::propagate_on_container_move_assignment::value) {
            basic_string other(MoveUtil::move(lvalue));
            quickSwapExchangeAllocators(other);
        }
        else if (get_allocator() == lvalue.get_allocator()) {
            basic_string other(MoveUtil::move(lvalue));
            quickSwapRetainAllocators(other);
        }
        else {
            privateAssignDispatch(
                  lvalue.data(),
                  lvalue.size(),
                  "string<...>::operator=(MovableRef<...>): string too long");
        }
    }
    return *this;
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
template <class STRING_VIEW_LIKE_TYPE>
inline
BSLSTL_STRING_DEFINE_ONLY_CONVERTIBLE_TO_STRINGVIEW_RETURN_TYPE
basic_string<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>::operator=(
                                              const STRING_VIEW_LIKE_TYPE& rhs)
{
    bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS> strView = rhs;
    return privateAssignDispatch(
                  strView.data(),
                  strView.size(),
                  "string<>::operator=(basic_string_view&): string too long");
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
BSLS_PLATFORM_AGGRESSIVE_INLINE
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>&
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::operator=(const CHAR_TYPE *rhs)
{
    BSLS_ASSERT_SAFE(rhs);

    return assign(rhs);
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
BSLS_PLATFORM_AGGRESSIVE_INLINE
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>&
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::operator=(CHAR_TYPE character)
{
    return assign(1, character);
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
template <class ALLOC2>
BSLS_PLATFORM_AGGRESSIVE_INLINE
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>&
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::operator=(
                    const std::basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOC2>& rhs)
{
    return privateAssignDispatch(
            rhs.data(),
            rhs.size(),
            "string<...>::operator=(std::string&...): string too long");
}

#if defined(BSLS_COMPILERFEATURES_SUPPORT_GENERALIZED_INITIALIZERS)
template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
BSLS_PLATFORM_AGGRESSIVE_INLINE
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>&
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::operator=(
                                       std::initializer_list<CHAR_TYPE> values)
{
    return privateAssignDispatch(
                  values.begin(),
                  values.end(),
                  "string<...>::operator=(initializer_list): string too long");
}
#endif

                      // *** 21.3.4 capacity: ***

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
BSLS_PLATFORM_AGGRESSIVE_INLINE
void basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::resize(size_type newLength,
                                                           CHAR_TYPE character)
{
    privateThrowLengthError(newLength > max_size(),
                            "string<...>::resize(n,c): string too long");
    privateResizeRaw(newLength, character);
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
BSLS_PLATFORM_AGGRESSIVE_INLINE
void basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::resize(size_type newLength)
{
    privateThrowLengthError(newLength > max_size(),
                            "string<...>::resize(n): string too long");
    privateResizeRaw(newLength, CHAR_TYPE());
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
BSLS_PLATFORM_AGGRESSIVE_INLINE
void basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::reserve(
                                                         size_type newCapacity)
{
    privateThrowLengthError(newCapacity > max_size(),
                            "string<...>::reserve(n): string too long");
    privateReserveRaw(newCapacity);
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
BSLS_PLATFORM_AGGRESSIVE_INLINE
void basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::shrink_to_fit()
{
    if (this->size() < this->d_capacity) {
        basic_string temp(this->get_allocator());
        temp.privateAppend(this->data(),
                           this->length(),
                           "string<...>::shrink_to_fit(): string too long");
        quickSwapRetainAllocators(temp);
    }
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
BSLS_PLATFORM_AGGRESSIVE_INLINE
void basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::clear()
                                                          BSLS_KEYWORD_NOEXCEPT
{
    // Note: Stlport and Dinkumware do not deallocate the allocated buffer in
    // long string representation, ApacheSTL does.

    privateClear(Imp::BASIC_STRING_DEALLOCATE_IN_CLEAR);
}

                      // *** 21.3.3 iterators: ***

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
inline
typename basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::iterator
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::begin() BSLS_KEYWORD_NOEXCEPT
{
    return this->dataPtr();
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
inline
typename basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::iterator
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::end() BSLS_KEYWORD_NOEXCEPT
{
    return begin() + this->d_length;
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
inline
typename basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::reverse_iterator
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::rbegin() BSLS_KEYWORD_NOEXCEPT
{
    return reverse_iterator(end());
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
inline
typename basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::reverse_iterator
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::rend() BSLS_KEYWORD_NOEXCEPT
{
    return reverse_iterator(begin());
}

                   // *** 21.3.5 element access: ***

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
inline
typename basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::reference
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::operator[](size_type position)
{
    BSLS_ASSERT_SAFE(position <= length());

    return *(begin() + position);
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
typename basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::reference
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::at(size_type position)
{
    // Note: deliberately not inline, because 1) this is not a very widely used
    // function, and 2) it is very convenient to have at least one non-inlined
    // element accessor for debugging.

    privateThrowOutOfRange(position >= length(),
                           "string<...>::at(n): invalid position");

    return *(begin() + position);
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
inline
CHAR_TYPE&
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::front()
{
    BSLS_ASSERT_SAFE(!empty());

    return *begin();
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
inline
CHAR_TYPE&
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::back()
{
    BSLS_ASSERT_SAFE(!empty());

    return *(begin() + length() - 1);
}

                     // *** 21.3.6 modifiers: ***

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
BSLS_PLATFORM_AGGRESSIVE_INLINE
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>&
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::operator+=(
                                                       const basic_string& rhs)
{
    return append(rhs);
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
BSLS_PLATFORM_AGGRESSIVE_INLINE
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>&
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::operator+=(
                                                          const CHAR_TYPE *rhs)
{
    BSLS_ASSERT_SAFE(rhs);

    return append(rhs);
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
BSLS_PLATFORM_AGGRESSIVE_INLINE
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>&
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::operator+=(CHAR_TYPE character)
{
    push_back(character);
    return *this;
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
template <class STRING_VIEW_LIKE_TYPE>
BSLS_PLATFORM_AGGRESSIVE_INLINE
BSLSTL_STRING_DEFINE_ONLY_CONVERTIBLE_TO_STRINGVIEW_RETURN_TYPE
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::operator+=(
                                              const STRING_VIEW_LIKE_TYPE& rhs)
{
    const bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS> strView = rhs;
    return append(strView.data(),strView.length());
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
template <class ALLOC2>
BSLS_PLATFORM_AGGRESSIVE_INLINE
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>&
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::operator+=(
                  const std::basic_string<CHAR_TYPE, CHAR_TRAITS, ALLOC2>& rhs)
{
    return append(rhs.begin(),rhs.end());
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
BSLS_PLATFORM_AGGRESSIVE_INLINE
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>&
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::append(
                                                   const basic_string&  suffix)
{
    return append(suffix, size_type(0), npos);
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>&
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::append(
                                                  const basic_string& suffix,
                                                  size_type           position,
                                                  size_type           numChars)
{
    privateThrowOutOfRange(
                 position > suffix.length(),
                 "string<...>::append(const string&,pos,n): invalid position");

    if (numChars > suffix.length() - position) {
        numChars = suffix.length() - position;
    }
    return privateAppend(
                  suffix.data() + position,
                  numChars,
                  "string<...>::append(const string&,pos,n): string too long");
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
BSLS_PLATFORM_AGGRESSIVE_INLINE
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>&
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::append(
                                              const CHAR_TYPE *characterString,
                                              size_type        numChars)
{
    BSLS_ASSERT_SAFE(characterString || 0 == numChars);

    return privateAppend(characterString,
                         numChars,
                         "string<...>::append(char*...): string too long");
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
BSLS_PLATFORM_AGGRESSIVE_INLINE
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>&
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::append(
                                              const CHAR_TYPE *characterString)
{
    BSLS_ASSERT_SAFE(characterString);

    return append(characterString, CHAR_TRAITS::length(characterString));
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
BSLS_PLATFORM_AGGRESSIVE_INLINE
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>&
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::append(size_type numChars,
                                                      CHAR_TYPE character)
{
    return privateAppend(numChars,
                         character,
                         "string<...>::append(n,c): string too long");
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
template <class STRING_VIEW_LIKE_TYPE>
BSLS_PLATFORM_AGGRESSIVE_INLINE
BSLSTL_STRING_DEFINE_ONLY_CONVERTIBLE_TO_STRINGVIEW_RETURN_TYPE
basic_string<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>::append(
                                           const STRING_VIEW_LIKE_TYPE& suffix)
{
    const bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS> strView = suffix;
    return privateAppend(
                    strView.data(),
                    strView.length(),
                    "string<...>::append(basic_string_view): string too long");
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
template <class STRING_VIEW_LIKE_TYPE>
BSLSTL_STRING_DEFINE_ONLY_CONVERTIBLE_TO_STRINGVIEW_RETURN_TYPE
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::append(
                                         const STRING_VIEW_LIKE_TYPE& suffix,
                                         size_type                    position,
                                         size_type                    numChars)
{
    const bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS> strView = suffix;
    privateThrowOutOfRange(
              position > strView.length(),
             "string<...>::append(basic_string_view,pos,n): invalid position");

    if (numChars > strView.length() - position) {
        numChars = strView.length() - position;
    }
    return privateAppend(
              strView.data() + position,
              numChars,
              "string<...>::append(basic_string_view,pos,n): string too long");
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
template <class INPUT_ITER>
BSLS_PLATFORM_AGGRESSIVE_INLINE
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>&
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::append(INPUT_ITER first,
                                                      INPUT_ITER last)
{
    return privateAppend(first,
                         last,
                         "string<...>::append<Iter>(i,j): string too long");
}

#if defined(BSLS_COMPILERFEATURES_SUPPORT_GENERALIZED_INITIALIZERS)
template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
BSLS_PLATFORM_AGGRESSIVE_INLINE
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>&
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::append(
                                       std::initializer_list<CHAR_TYPE> values)
{
    return privateAppend(
                     values.begin(),
                     values.end(),
                     "string<...>::append(initializer_list): string too long");
}
#endif

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
void basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::push_back(
                                                           CHAR_TYPE character)
{
    privateThrowLengthError(length() >= max_size(),
                            "string<...>::push_back(char): string too long");

    if (length() + 1 > capacity()) {
        privateReserveRaw(length() + 1);
    }
    CHAR_TRAITS::assign(*(begin() + length()), character);
    ++this->d_length;
    CHAR_TRAITS::assign(*(begin() + length()), CHAR_TYPE());
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
BSLS_PLATFORM_AGGRESSIVE_INLINE
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>&
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::assign(
                                               const basic_string& replacement)
{
    return this->operator=(replacement);
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
inline
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>&
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::assign(
                      BloombergLP::bslmf::MovableRef<basic_string> replacement)
                                     BSLS_KEYWORD_NOEXCEPT_SPECIFICATION(false)
{
    basic_string& other = replacement;
    return this->operator=(MoveUtil::move(other));
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>&
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::assign(
                                               const basic_string& replacement,
                                               size_type           position,
                                               size_type           numChars)
{
    privateThrowOutOfRange(
                 position > replacement.length(),
                 "string<...>::assign(const string&,pos,n): invalid position");

    if (numChars > replacement.length() - position) {
        numChars = replacement.length() - position;
    }
    return privateAssignDispatch(
                 replacement.data() + position,
                 numChars,
                 "string<...>::assign(const string&,pos,n): invalid position");
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
BSLS_PLATFORM_AGGRESSIVE_INLINE
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>&
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::assign(
                                              const CHAR_TYPE *characterString)
{
    BSLS_ASSERT_SAFE(characterString);

    return assign(characterString, CHAR_TRAITS::length(characterString));
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
BSLS_PLATFORM_AGGRESSIVE_INLINE
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>&
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::assign(
                                              const CHAR_TYPE *characterString,
                                              size_type        numChars)
{
    BSLS_ASSERT_SAFE(characterString || 0 == numChars);

    return privateAssignDispatch(
                             characterString,
                             numChars,
                             "string<...>::assign(char*...): string too long");
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
template <class STRING_VIEW_LIKE_TYPE>
BSLS_PLATFORM_AGGRESSIVE_INLINE
BSLSTL_STRING_DEFINE_ONLY_CONVERTIBLE_TO_STRINGVIEW_RETURN_TYPE
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::assign(
                                      const STRING_VIEW_LIKE_TYPE& replacement)
{
    const bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS> strView = replacement;

    return this->operator=(strView);
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
template <class STRING_VIEW_LIKE_TYPE>
BSLS_PLATFORM_AGGRESSIVE_INLINE
BSLSTL_STRING_DEFINE_ONLY_CONVERTIBLE_TO_STRINGVIEW_RETURN_TYPE
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::assign(
                                      const STRING_VIEW_LIKE_TYPE& replacement,
                                      size_type                    position,
                                      size_type                    numChars)
{
    const bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS> strView = replacement;

    privateThrowOutOfRange(
            position > strView.length(),
            "string<...>::assign(const StrViewLike&,pos,n): invalid position");

    if (numChars > strView.length() - position) {
        numChars = strView.length() - position;
    }
    return privateAssignDispatch(
            strView.data() + position,
            numChars,
            "string<...>::assign(const StrViewLike&,pos,n): invalid position");
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
template <class ALLOC2>
BSLS_PLATFORM_AGGRESSIVE_INLINE
basic_string<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>&
basic_string<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>::assign(
               const std::basic_string<CHAR_TYPE, CHAR_TRAITS, ALLOC2>& string)
{
    return this->operator=(string);
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
BSLS_PLATFORM_AGGRESSIVE_INLINE
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>&
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::assign(size_type numChars,
                                                      CHAR_TYPE character)
{
    return privateAssignDispatch(
                                  numChars,
                                  character,
                                  "string<...>::assign(n,c): string too long");
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
template <class INPUT_ITER>
BSLS_PLATFORM_AGGRESSIVE_INLINE
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>&
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::assign(INPUT_ITER first,
                                                      INPUT_ITER last)
{
    return privateAssignDispatch(
                            first,
                            last,
                            "string<...>::assign<Iter>(i,j): string too long");
}

#if defined(BSLS_COMPILERFEATURES_SUPPORT_GENERALIZED_INITIALIZERS)
template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
BSLS_PLATFORM_AGGRESSIVE_INLINE
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>&
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::assign(
                                       std::initializer_list<CHAR_TYPE> values)
{
    return privateAssignDispatch(
                     values.begin(),
                     values.end(),
                     "string<...>::assign(initializer_list): string too long");
}
#endif

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
BSLS_PLATFORM_AGGRESSIVE_INLINE
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>&
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::insert(
                                                  size_type           position,
                                                  const basic_string& other)
{
    return insert(position, other, size_type(0), npos);
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>&
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::insert(
                                           size_type            position,
                                           const basic_string&  other,
                                           size_type            sourcePosition,
                                           size_type            numChars)
{
    privateThrowOutOfRange(
                position > length(),
                "string<...>::insert(pos,const string&...): invalid position");
    privateThrowOutOfRange(
        sourcePosition > other.length(),
        "string<...>::insert(pos,const string&...): invalid source  position");

    if (numChars > other.length() - sourcePosition) {
        numChars = other.length() - sourcePosition;
    }
    privateThrowLengthError(
                 numChars > max_size() - length(),
                 "string<...>::insert(pos,const string&...): string too long");
    return privateInsertRaw(position, other.data() + sourcePosition, numChars);
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>&
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::insert(
                                              size_type        position,
                                              const CHAR_TYPE *characterString,
                                              size_type        numChars)
{
    BSLS_ASSERT_SAFE(characterString || 0 == numChars);

    privateThrowOutOfRange(
                        position > length(),
                        "string<...>::insert(pos,char*...): invalid position");

    privateThrowLengthError(
                         numChars > max_size() - length(),
                         "string<...>::insert(pos,char*...): string too long");
    return privateInsertRaw(position, characterString, numChars);
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
BSLS_PLATFORM_AGGRESSIVE_INLINE
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>&
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::insert(
                                              size_type        position,
                                              const CHAR_TYPE *characterString)
{
    BSLS_ASSERT_SAFE(characterString);

    return insert(position,
                  characterString,
                  CHAR_TRAITS::length(characterString));
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>&
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::insert(size_type position,
                                                      size_type numChars,
                                                      CHAR_TYPE character)
{
    privateThrowOutOfRange(position > length(),
                           "string<...>::insert(pos,n,c): invalid position");

    privateThrowLengthError(numChars > max_size() - length(),
                            "string<...>::insert(pos,n,c): string too long");
    return privateReplaceRaw(position, size_type(0), numChars, character);
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
typename basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::iterator
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::insert(const_iterator position,
                                                      CHAR_TYPE      character)
{
    BSLS_ASSERT_SAFE(position >= cbegin());
    BSLS_ASSERT_SAFE(position <= cend());

    size_type pos = position - cbegin();
    insert(pos, size_type(1), character);
    return begin() + pos;
}

#if defined(BSLS_PLATFORM_CMP_SUN) && BSLS_PLATFORM_CMP_VERSION < 0x5130
    // Sun CC compiler doesn't like that 'iterator' return type of 'insert'
    // method with an additional 'INPUT_ITER' template parameter depends on
    // template parameters of the primary template class 'basic_string'.
    // However, it happily accepts 'CHAR_TYPE *', which is how 'iterator' is
    // currently defined.  It will also accept an inline definition of this
    // method (this workaround should be used when 'iterator' becomes a real
    // class and the current workaround stops working).
#   define BSLSTL_INSERT_RETURN_TYPE CHAR_TYPE *
#else
#   define BSLSTL_INSERT_RETURN_TYPE \
    typename basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::iterator
#endif

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
template <class INPUT_ITER>
inline
BSLSTL_INSERT_RETURN_TYPE
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::insert(const_iterator position,
                                                      INPUT_ITER     first,
                                                      INPUT_ITER     last)
{
    BSLS_ASSERT_SAFE(position >= cbegin());
    BSLS_ASSERT_SAFE(position <= cend());

    size_type pos = position - cbegin();
    privateInsertDispatch(position, first, last);
    return begin() + pos;
}

#undef BSLSTL_INSERT_RETURN_TYPE

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
inline
typename basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::iterator
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::insert(const_iterator position,
                                                      size_type      numChars,
                                                      CHAR_TYPE      character)
{
    BSLS_ASSERT_SAFE(position >= cbegin());
    BSLS_ASSERT_SAFE(position <= cend());

    size_type pos = position - cbegin();
    insert(pos, numChars, character);
    return begin() + pos;
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
template <class STRING_VIEW_LIKE_TYPE>
BSLSTL_STRING_DEFINE_ONLY_CONVERTIBLE_TO_STRINGVIEW_RETURN_TYPE
basic_string<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>::insert(
                                         size_type                    position,
                                         const STRING_VIEW_LIKE_TYPE& other)
{
    const bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS> strView = other;
    privateThrowOutOfRange(
              position > length(),
              "string<...>::insert(pos,const string_view&): invalid position");
    privateThrowLengthError(
               strView.length() > max_size() - length(),
               "string<...>::insert(pos,const string_view&): string too long");
    return privateInsertRaw(position, strView.data(), strView.length());
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
template <class STRING_VIEW_LIKE_TYPE>
BSLSTL_STRING_DEFINE_ONLY_CONVERTIBLE_TO_STRINGVIEW_RETURN_TYPE
basic_string<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>::insert(
                                   size_type                    position,
                                   const STRING_VIEW_LIKE_TYPE& other,
                                   size_type                    sourcePosition,
                                   size_type                    numChars)
{
    const bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS> strView = other;
    privateThrowOutOfRange(
           position > length(),
           "string<...>::insert(pos,const string_view&...): invalid position");
    privateThrowOutOfRange(sourcePosition > strView.length(),
                           "string<...>::insert(pos,const string_view&...): "
                           "invalid source position");

    if (numChars > strView.length() - sourcePosition) {
        numChars = strView.length() - sourcePosition;
    }
    privateThrowLengthError(
                 numChars > max_size() - length(),
                 "string<...>::insert(pos,const string&...): string too long");
    return privateInsertRaw(position,
                            strView.data() + sourcePosition,
                            numChars);
}

#if defined(BSLS_COMPILERFEATURES_SUPPORT_GENERALIZED_INITIALIZERS)
template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
inline
typename basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::iterator
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::insert(
                                     const_iterator                   position,
                                     std::initializer_list<CHAR_TYPE> values)
{
    BSLS_ASSERT_SAFE(position >= cbegin());
    BSLS_ASSERT_SAFE(position <= cend());

    size_type pos = position - cbegin();
    privateInsertDispatch(position, values.begin(), values.end());
    return begin() + pos;
}
#endif

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>&
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::erase(size_type position,
                                                     size_type numChars)
{
    privateThrowOutOfRange(position > length(),
                           "string<...>::erase(pos,n): invalid position");

    if (numChars > length() - position) {
        numChars = length() - position;
    }
    if (numChars) {
        this->d_length -= numChars;
        CHAR_TRAITS::move(this->dataPtr() + position,
                          this->dataPtr() + position + numChars,
                          this->d_length - position);
        CHAR_TRAITS::assign(*(begin() + length()), CHAR_TYPE());
    }
    return *this;
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
typename basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::iterator
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::erase(const_iterator position)
{
    BSLS_ASSERT_SAFE(position >= cbegin());
    BSLS_ASSERT_SAFE(position < cend());

    const_iterator postPosition = position;
    iterator       dstPosition  = begin() + (position - cbegin());

    ++postPosition;
    CHAR_TRAITS::move(&*dstPosition, &*postPosition, cend() - postPosition);

    --this->d_length;
    CHAR_TRAITS::assign(*(this->dataPtr() + length()), CHAR_TYPE());

    return dstPosition;
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
typename basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::iterator
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::erase(const_iterator first,
                                                     const_iterator last)
{
    BSLS_ASSERT_SAFE(first >= cbegin());
    BSLS_ASSERT_SAFE(first <= cend());
    BSLS_ASSERT_SAFE(last >= cbegin());
    BSLS_ASSERT_SAFE(last <= cend());
    BSLS_ASSERT_SAFE(last - first >= 0);

    iterator dstFirst = begin() + (first - cbegin());

    if (first != last) {
        CHAR_TRAITS::move(&*dstFirst, &*last, cend() - last);

        this->d_length -= last - first;
        CHAR_TRAITS::assign(*(this->dataPtr() + length()), CHAR_TYPE());
    }

    return dstFirst;
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
inline
void basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::pop_back()
{
    BSLS_ASSERT_SAFE(!empty());

    --this->d_length;
    CHAR_TRAITS::assign(*(begin() + length()), CHAR_TYPE());
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>&
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::replace(
                                               size_type           outPosition,
                                               size_type           outNumChars,
                                               const basic_string& replacement)
{
    privateThrowOutOfRange(
               length() < outPosition,
               "string<...>::replace(pos,const string&...): invalid position");
    if (outNumChars > length() - outPosition) {
        outNumChars = length() - outPosition;
    }
    privateThrowLengthError(
                replacement.length() > outNumChars &&
                    replacement.length() - outNumChars > max_size() - length(),
                "string<...>::replace(pos,const string&...): string too long");
    return privateReplaceRaw(outPosition,
                             outNumChars,
                             replacement.data(),
                             replacement.length());
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>&
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::replace(
                                               size_type           outPosition,
                                               size_type           outNumChars,
                                               const basic_string& replacement,
                                               size_type           position,
                                               size_type           numChars)
{
    privateThrowOutOfRange(
               length() < outPosition,
               "string<...>::replace(pos,const string&...): invalid position");

    if (outNumChars > length() - outPosition) {
        outNumChars = length() - outPosition;
    }
    privateThrowOutOfRange(
               position > replacement.length(),
               "string<...>::replace(pos,const string&...): invalid position");

    if (numChars > replacement.length() - position) {
        numChars = replacement.length() - position;
    }
    privateThrowLengthError(
                numChars > outNumChars &&
                                numChars - outNumChars > max_size() - length(),
                "string<...>::replace(pos,const string&...): string too long");
    return privateReplaceRaw(outPosition,
                             outNumChars,
                             replacement.data() + position,
                             numChars);
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>&
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::replace(
                                              size_type        outPosition,
                                              size_type        outNumChars,
                                              const CHAR_TYPE *characterString,
                                              size_type        numChars)
{
    BSLS_ASSERT_SAFE(characterString || 0 == numChars);

    privateThrowOutOfRange(
                       length() < outPosition,
                       "string<...>::replace(pos,char*...): invalid position");

    if (outNumChars > length() - outPosition) {
        outNumChars = length() - outPosition;
    }

    privateThrowLengthError(
                        numChars > outNumChars &&
                                numChars - outNumChars > max_size() - length(),
                        "string<...>::replace(pos,char*...): string too long");
    return privateReplaceRaw(outPosition,
                             outNumChars,
                             characterString,
                             numChars);
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
BSLS_PLATFORM_AGGRESSIVE_INLINE
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>&
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::replace(
                                              size_type        outPosition,
                                              size_type        outNumChars,
                                              const CHAR_TYPE *characterString)
{
    BSLS_ASSERT_SAFE(characterString);

    return replace(outPosition,
                   outNumChars,
                   characterString,
                   CHAR_TRAITS::length(characterString));
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>&
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::replace(size_type outPosition,
                                                       size_type outNumChars,
                                                       size_type numChars,
                                                       CHAR_TYPE character)
{
    privateThrowOutOfRange(
                            length() < outPosition,
                            "string<...>::replace(pos,n,c): invalid position");
    if (outNumChars > length() - outPosition) {
        outNumChars = length() - outPosition;
    }
    privateThrowLengthError(
                             numChars > outNumChars &&
                                numChars - outNumChars > max_size() - length(),
                             "string<...>::replace(pos,n,c): string too long");
    return privateReplaceRaw(outPosition,
                             outNumChars,
                             numChars,
                             character);
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
template <class STRING_VIEW_LIKE_TYPE>
BSLSTL_STRING_DEFINE_ONLY_CONVERTIBLE_TO_STRINGVIEW_RETURN_TYPE
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::replace(
                                      size_type                    outPosition,
                                      size_type                    outNumChars,
                                      const STRING_VIEW_LIKE_TYPE& replacement)
{
    privateThrowOutOfRange(
              length() < outPosition,
              "string<...>::replace(pos,const strView&...): invalid position");
    if (outNumChars > length() - outPosition) {
        outNumChars = length() - outPosition;
    }

    bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS> strView = replacement;
    privateThrowLengthError(
               strView.length() > outNumChars &&
                   strView.length() - outNumChars > max_size() - length(),
               "string<...>::replace(pos,const strView&...): string too long");
    return privateReplaceRaw(outPosition,
                             outNumChars,
                             strView.data(),
                             strView.length());
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
template <class STRING_VIEW_LIKE_TYPE>
BSLSTL_STRING_DEFINE_ONLY_CONVERTIBLE_TO_STRINGVIEW_RETURN_TYPE
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::replace(
                                      size_type                    outPosition,
                                      size_type                    outNumChars,
                                      const STRING_VIEW_LIKE_TYPE& replacement,
                                      size_type                    position,
                                      size_type                    numChars)
{
    privateThrowOutOfRange(
              length() < outPosition,
              "string<...>::replace(pos,const strView&...): invalid position");

    if (outNumChars > length() - outPosition) {
        outNumChars = length() - outPosition;
    }

    bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS> strView = replacement;
    privateThrowOutOfRange(
              position > strView.length(),
              "string<...>::replace(pos,const strView&...): invalid position");

    if (numChars > strView.length() - position) {
        numChars = strView.length() - position;
    }
    privateThrowLengthError(
               numChars > outNumChars &&
                               numChars - outNumChars > max_size() - length(),
               "string<...>::replace(pos,const strView&...): string too long");
    return privateReplaceRaw(outPosition,
                             outNumChars,
                             strView.data() + position,
                             numChars);
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>&
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::replace(
                                               const_iterator      first,
                                               const_iterator      last,
                                               const basic_string& replacement)
{
    BSLS_ASSERT_SAFE(first >= cbegin());
    BSLS_ASSERT_SAFE(first <= cend());
    BSLS_ASSERT_SAFE(first <= last);
    BSLS_ASSERT_SAFE(last <= cend());

    size_type outPosition = first - cbegin();
    size_type outNumChars = last - first;

    privateThrowLengthError(
                    replacement.length() > outNumChars &&
                    replacement.length() - outNumChars > max_size() - length(),
                    "string<...>::replace(const string&...): string too long");

    return privateReplaceRaw(outPosition,
                             outNumChars,
                             replacement.data(),
                             replacement.length());
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
template <class STRING_VIEW_LIKE_TYPE>
BSLSTL_STRING_DEFINE_ONLY_CONVERTIBLE_TO_STRINGVIEW_RETURN_TYPE
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::replace(
                                      const_iterator               first,
                                      const_iterator               last,
                                      const STRING_VIEW_LIKE_TYPE& replacement)
{
    BSLS_ASSERT_SAFE(first >= cbegin());
    BSLS_ASSERT_SAFE(first <= cend());
    BSLS_ASSERT_SAFE(first <= last);
    BSLS_ASSERT_SAFE(last <= cend());

    size_type outPosition = first - cbegin();
    size_type outNumChars = last - first;

    bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS> strView = replacement;
    privateThrowLengthError(
                   strView.length() > outNumChars &&
                   strView.length() - outNumChars > max_size() - length(),
                   "string<...>::replace(const strView&...): string too long");

    return privateReplaceRaw(outPosition,
                             outNumChars,
                             strView.data(),
                             strView.length());
}


template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>&
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::replace(
                                              const_iterator   first,
                                              const_iterator   last,
                                              const CHAR_TYPE *characterString,
                                              size_type        numChars)
{
    BSLS_ASSERT_SAFE(first >= cbegin());
    BSLS_ASSERT_SAFE(first <= cend());
    BSLS_ASSERT_SAFE(first <= last);
    BSLS_ASSERT_SAFE(last <= cend());
    BSLS_ASSERT_SAFE(characterString || 0 == numChars);

    size_type outPosition = first - cbegin();
    size_type outNumChars = last - first;
    privateThrowLengthError(
                            numChars > outNumChars &&
                            numChars - outNumChars > max_size() - length(),
                            "string<...>::replace(char*...): string too long");
    return privateReplaceRaw(outPosition,
                             outNumChars,
                             characterString,
                             numChars);
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
BSLS_PLATFORM_AGGRESSIVE_INLINE
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>&
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::replace(
                                              const_iterator   first,
                                              const_iterator   last,
                                              const CHAR_TYPE *characterString)
{
    BSLS_ASSERT_SAFE(first >= cbegin());
    BSLS_ASSERT_SAFE(first <= cend());
    BSLS_ASSERT_SAFE(first <= last);
    BSLS_ASSERT_SAFE(last <= cend());
    BSLS_ASSERT_SAFE(characterString);

    return replace(first,
                   last,
                   characterString,
                   CHAR_TRAITS::length(characterString));
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>&
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::replace(
                                                      const_iterator first,
                                                      const_iterator last,
                                                      size_type      numChars,
                                                      CHAR_TYPE      character)
{
    BSLS_ASSERT_SAFE(first >= cbegin());
    BSLS_ASSERT_SAFE(first <= cend());
    BSLS_ASSERT_SAFE(first <= last);
    BSLS_ASSERT_SAFE(last <= cend());

    size_type outPosition = first - cbegin();
    size_type outNumChars = last - first;
    privateThrowLengthError(numChars > outNumChars &&
                                numChars - outNumChars > max_size() - length(),
                            "string<...>::replace(n,c): string too long");
    return privateReplaceRaw(outPosition, outNumChars, numChars, character);
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
template <class INPUT_ITER>
inline
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>&
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::replace(
                                                    const_iterator first,
                                                    const_iterator last,
                                                    INPUT_ITER     stringFirst,
                                                    INPUT_ITER     stringLast)
{
    BSLS_ASSERT_SAFE(first >= cbegin());
    BSLS_ASSERT_SAFE(first <= cend());
    BSLS_ASSERT_SAFE(first <= last);
    BSLS_ASSERT_SAFE(last <= cend());

    size_type outPosition = first - cbegin();
    size_type outNumChars = last - first;
    return privateReplaceDispatch(outPosition,
                                  outNumChars,
                                  stringFirst,
                                  stringLast,
                                  stringFirst,
                                  BloombergLP::bslmf::Nil());
}

                 // *** 21.3.7 string operations: ***

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
inline
CHAR_TYPE *
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::data() BSLS_KEYWORD_NOEXCEPT
{
    return this->dataPtr();
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
void
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::swap(basic_string& other)
                     BSLS_KEYWORD_NOEXCEPT_SPECIFICATION(
                         AllocatorTraits::propagate_on_container_swap::value ||
                         AllocatorTraits::is_always_equal::value)
{
    if (AllocatorTraits::propagate_on_container_swap::value) {
        quickSwapExchangeAllocators(other);
    }
    else if (BSLS_PERFORMANCEHINT_PREDICT_LIKELY(
                                   get_allocator() == other.get_allocator())) {
        quickSwapRetainAllocators(other);
    }
    else {
        BSLS_PERFORMANCEHINT_UNLIKELY_HINT;

        basic_string toThisCopy(MoveUtil::move(other), get_allocator());
        basic_string toOtherCopy(MoveUtil::move(*this),
                                 other.get_allocator());

        this->quickSwapRetainAllocators(toThisCopy);
        other.quickSwapRetainAllocators(toOtherCopy);
    }
}

// ACCESSORS

                     // *** 21.3.3 iterators: ***

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
inline
typename basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::const_iterator
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::begin() const
                                                          BSLS_KEYWORD_NOEXCEPT
{
    return this->dataPtr();
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
inline
typename basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::const_iterator
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::cbegin() const
                                                          BSLS_KEYWORD_NOEXCEPT
{
    return begin();
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
inline
typename basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::const_iterator
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::end() const
                                                          BSLS_KEYWORD_NOEXCEPT
{
    return begin() + this->d_length;
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
inline
typename basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::const_iterator
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::cend() const
                                                          BSLS_KEYWORD_NOEXCEPT
{
    return end();
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
inline
typename basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::const_reverse_iterator
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::rbegin() const
                                                          BSLS_KEYWORD_NOEXCEPT
{
    return const_reverse_iterator(end());
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
inline
typename basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::const_reverse_iterator
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::crbegin() const
                                                          BSLS_KEYWORD_NOEXCEPT
{
    return const_reverse_iterator(end());
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
BSLS_PLATFORM_AGGRESSIVE_INLINE
typename basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::const_reverse_iterator
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::rend() const
                                                          BSLS_KEYWORD_NOEXCEPT
{
    return const_reverse_iterator(begin());
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
BSLS_PLATFORM_AGGRESSIVE_INLINE
typename basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::const_reverse_iterator
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::crend() const
                                                          BSLS_KEYWORD_NOEXCEPT
{
    return const_reverse_iterator(begin());
}

                      // *** 21.3.4 capacity: ***

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
inline
typename basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::size_type
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::size() const
                                                          BSLS_KEYWORD_NOEXCEPT
{
    return this->d_length;
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
inline
typename basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::size_type
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::length() const
                                                          BSLS_KEYWORD_NOEXCEPT
{
    return this->d_length;
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
inline
typename basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::size_type
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::max_size() const
                                                          BSLS_KEYWORD_NOEXCEPT
{
    // Must take into account the null-terminating character.

    size_type stringMaxSize = ~size_type(0) / sizeof(CHAR_TYPE) - 1;
    size_type allocMaxSize  = AllocatorTraits::max_size(get_allocator()) - 1;
    return allocMaxSize < stringMaxSize ? allocMaxSize : stringMaxSize;
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
inline
typename basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::size_type
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::capacity() const
                                                          BSLS_KEYWORD_NOEXCEPT
{
    return this->d_capacity;
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
inline
bool basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::empty() const
                                                          BSLS_KEYWORD_NOEXCEPT
{
    return this->d_length == 0;
}

                   // *** 21.3.5 element access: ***

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
inline
typename basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::const_reference
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::operator[](
                                                      size_type position) const
{
    BSLS_ASSERT_SAFE(position <= length());

    return *(begin() + position);
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
BSLS_PLATFORM_AGGRESSIVE_INLINE
typename basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::const_reference
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::at(size_type position) const
{
    // Note: deliberately not inlined (see comment in non-'const' version).

    privateThrowOutOfRange(position >= length(),
                           "const string<...>::at(n): invalid position");
    return *(begin() + position);
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
inline
const CHAR_TYPE&
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::front() const
{
    BSLS_ASSERT_SAFE(!empty());

    return *begin();
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
inline
const CHAR_TYPE&
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::back() const
{
    BSLS_ASSERT_SAFE(!empty());

    return *(end() - 1);
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
typename basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::size_type
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::copy(CHAR_TYPE *characterString,
                                                    size_type  numChars,
                                                    size_type  position) const
{
    BSLS_ASSERT_SAFE(characterString);

    privateThrowOutOfRange(
                       length() < position,
                       "const string<...>::copy(str,pos,n): invalid position");
    if (numChars > length() - position) {
        numChars = length() - position;
    }
    CHAR_TRAITS::move(characterString, this->dataPtr() + position, numChars);
    return numChars;
}

                 // *** 21.3.7 string operations: ***

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
inline
const CHAR_TYPE *
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::c_str() const
                                                          BSLS_KEYWORD_NOEXCEPT
{
    return this->dataPtr();
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
inline
const CHAR_TYPE *
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::data() const
                                                          BSLS_KEYWORD_NOEXCEPT
{
    return this->dataPtr();
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
inline
typename basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::allocator_type
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::get_allocator() const
                                                          BSLS_KEYWORD_NOEXCEPT
{
    return ContainerBase::allocator();
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
BSLS_PLATFORM_AGGRESSIVE_INLINE
typename basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::size_type
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::find(
                                           const basic_string&  substring,
                                           size_type            position) const
                                                          BSLS_KEYWORD_NOEXCEPT
{
    return find(substring.data(), position, substring.length());
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
template <class STRING_VIEW_LIKE_TYPE>
BSLS_PLATFORM_AGGRESSIVE_INLINE
typename basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::size_type
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::find(
                const STRING_VIEW_LIKE_TYPE& substring,
                size_type                    position
                BSLSTL_STRING_DEFINE_ONLY_CONVERTIBLE_TO_STRINGVIEW_PARAM_VOID)
                                const BSLS_KEYWORD_NOEXCEPT_SPECIFICATION(true)
{
    bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS> strView = substring;
    return find(strView.data(), position, strView.length());
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
typename basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::size_type
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::find(
                                               const CHAR_TYPE *substring,
                                               size_type        position,
                                               size_type        numChars) const
{
    BSLS_ASSERT_SAFE(substring);

    size_type remChars = length() - position;
    if (position > length() || numChars > remChars) {
        return npos;                                                  // RETURN
    }
    if (0 == numChars) {
        return position;                                              // RETURN
    }
    const CHAR_TYPE *thisString = this->dataPtr() + position;
    const CHAR_TYPE *nextString;
    for (remChars -= numChars - 1;
         0 != (nextString = BSLSTL_CHAR_TRAITS::find(thisString,
                                                     remChars,
                                                     *substring));
         remChars -= ++nextString - thisString, thisString = nextString)
    {
        if (0 == CHAR_TRAITS::compare(nextString, substring, numChars)) {
            return nextString - this->dataPtr();                      // RETURN
        }
    }
    return npos;
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
BSLS_PLATFORM_AGGRESSIVE_INLINE
typename basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::size_type
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::find(
                                               const CHAR_TYPE *substring,
                                               size_type        position) const
{
    BSLS_ASSERT_SAFE(substring);

    return find(substring, position, CHAR_TRAITS::length(substring));
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
typename basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::size_type
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::find(CHAR_TYPE character,
                                                    size_type position) const
{
    if (position >= length()) {
        return npos;                                                  // RETURN
    }
    const CHAR_TYPE *result =
        BSLSTL_CHAR_TRAITS::find(this->dataPtr() + position,
                                 length() - position,
                                 character);
    return result ? result - this->dataPtr() : npos;
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
BSLS_PLATFORM_AGGRESSIVE_INLINE
typename basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::size_type
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::rfind(
                                            const basic_string& substring,
                                            size_type           position) const
                                                          BSLS_KEYWORD_NOEXCEPT
{
    return rfind(substring.data(), position, substring.length());
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
template <class STRING_VIEW_LIKE_TYPE>
BSLS_PLATFORM_AGGRESSIVE_INLINE
typename basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::size_type
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::rfind(
                const STRING_VIEW_LIKE_TYPE& substring,
                size_type                    position
                BSLSTL_STRING_DEFINE_ONLY_CONVERTIBLE_TO_STRINGVIEW_PARAM_VOID)
                                const BSLS_KEYWORD_NOEXCEPT_SPECIFICATION(true)
{
    bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS> strView = substring;
    return rfind(strView.data(), position, strView.length());
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
typename basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::size_type
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::rfind(
                                              const CHAR_TYPE *characterString,
                                              size_type        position,
                                              size_type        numChars) const
{
    BSLS_ASSERT_SAFE(characterString || 0 == numChars);

    if (0 == numChars) {
        return position > length() ? length() : position;             // RETURN
    }
    if (numChars <= length()) {
        if (position > length() - numChars) {
            position = length() - numChars;
        }
        const CHAR_TYPE *thisString = this->dataPtr() + position;
        for (; position != npos; --thisString, --position) {
            if (0 == CHAR_TRAITS::compare(thisString,
                                          characterString,
                                          numChars)) {
                return position;                                      // RETURN
            }
        }
    }
    return npos;
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
BSLS_PLATFORM_AGGRESSIVE_INLINE
typename basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::size_type
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::rfind(
                                              const CHAR_TYPE *characterString,
                                              size_type        position) const
{
    BSLS_ASSERT_SAFE(characterString);

    return rfind(characterString,
                 position,
                 CHAR_TRAITS::length(characterString));
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
BSLS_PLATFORM_AGGRESSIVE_INLINE
typename basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::size_type
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::rfind(CHAR_TYPE character,
                                                     size_type position) const
{
    return rfind(&character, position, size_type(1));
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
BSLS_PLATFORM_AGGRESSIVE_INLINE
typename basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::size_type
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::find_first_of(
                                           const basic_string& characterString,
                                           size_type           position) const
                                                          BSLS_KEYWORD_NOEXCEPT
{
    return find_first_of(characterString.data(),
                         position,
                         characterString.length());
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
template <class STRING_VIEW_LIKE_TYPE>
BSLS_PLATFORM_AGGRESSIVE_INLINE
typename basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::size_type
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::find_first_of(
                const STRING_VIEW_LIKE_TYPE& characterString,
                size_type                    position
                BSLSTL_STRING_DEFINE_ONLY_CONVERTIBLE_TO_STRINGVIEW_PARAM_VOID)
                                const BSLS_KEYWORD_NOEXCEPT_SPECIFICATION(true)
{
    bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS> strView = characterString;
    return find_first_of(strView.data(), position, strView.length());
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
typename basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::size_type
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::find_first_of(
                                              const CHAR_TYPE *characterString,
                                              size_type        position,
                                              size_type        numChars) const
{
    BSLS_ASSERT_SAFE(characterString || 0 == numChars);

    if (0 < numChars && position < length()) {
        for (const CHAR_TYPE *current = this->dataPtr() + position;
             current != this->dataPtr() + length();
             ++current)
        {
            if (BSLSTL_CHAR_TRAITS::find(characterString, numChars, *current)
                != 0) {
                return current - this->dataPtr();                     // RETURN
            }
        }
    }
    return npos;
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
BSLS_PLATFORM_AGGRESSIVE_INLINE
typename basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::size_type
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::find_first_of(
                                              const CHAR_TYPE *characterString,
                                              size_type        position) const
{
    BSLS_ASSERT_SAFE(characterString);

    return find_first_of(characterString,
                         position,
                         CHAR_TRAITS::length(characterString));
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
BSLS_PLATFORM_AGGRESSIVE_INLINE
typename basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::size_type
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::find_first_of(
                                                      CHAR_TYPE character,
                                                      size_type position) const
{
    return find_first_of(&character, position, size_type(1));
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
BSLS_PLATFORM_AGGRESSIVE_INLINE
typename basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::size_type
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::find_last_of(
                                           const basic_string& characterString,
                                           size_type           position) const
                                                          BSLS_KEYWORD_NOEXCEPT
{
    return find_last_of(characterString.data(),
                        position,
                        characterString.length());
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
template <class STRING_VIEW_LIKE_TYPE>
BSLS_PLATFORM_AGGRESSIVE_INLINE
typename basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::size_type
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::find_last_of(
                const STRING_VIEW_LIKE_TYPE& characterString,
                size_type                    position
                BSLSTL_STRING_DEFINE_ONLY_CONVERTIBLE_TO_STRINGVIEW_PARAM_VOID)
                                const BSLS_KEYWORD_NOEXCEPT_SPECIFICATION(true)
{
    bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS> strView = characterString;
    return find_last_of(strView.data(), position, strView.length());
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
typename basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::size_type
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::find_last_of(
                                              const CHAR_TYPE *characterString,
                                              size_type        position,
                                              size_type        numChars) const
{
    BSLS_ASSERT_SAFE(characterString || 0 == numChars);

    if (0 < numChars && 0 < length()) {
        size_type remChars = position < length() ? position : length() - 1;
        for (const CHAR_TYPE *current = this->dataPtr() + remChars;
             ;
             --current)
        {
            if (BSLSTL_CHAR_TRAITS::find(
                                        characterString, numChars, *current)) {
                return current - this->dataPtr();                     // RETURN
            }
            if (current == this->dataPtr()) {
                break;
            }
        }
    }
    return npos;
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
BSLS_PLATFORM_AGGRESSIVE_INLINE
typename basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::size_type
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::find_last_of(
                                              const CHAR_TYPE *characterString,
                                              size_type        position) const
{
    BSLS_ASSERT_SAFE(characterString);

    return find_last_of(characterString,
                        position,
                        CHAR_TRAITS::length(characterString));
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
BSLS_PLATFORM_AGGRESSIVE_INLINE
typename basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::size_type
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::find_last_of(
                                                      CHAR_TYPE character,
                                                      size_type position) const
{
    return find_last_of(&character, position, size_type(1));
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
BSLS_PLATFORM_AGGRESSIVE_INLINE
typename basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::size_type
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::find_first_not_of(
                                           const basic_string& characterString,
                                           size_type           position) const
                                                          BSLS_KEYWORD_NOEXCEPT
{
    return find_first_not_of(characterString.data(),
                             position,
                             characterString.length());
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
template <class STRING_VIEW_LIKE_TYPE>
BSLS_PLATFORM_AGGRESSIVE_INLINE
typename basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::size_type
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::find_first_not_of(
                const STRING_VIEW_LIKE_TYPE& characterString,
                size_type                    position
                BSLSTL_STRING_DEFINE_ONLY_CONVERTIBLE_TO_STRINGVIEW_PARAM_VOID)
                                const BSLS_KEYWORD_NOEXCEPT_SPECIFICATION(true)
{
    bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS> strView = characterString;
    return find_first_not_of(strView.data(), position, strView.length());
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
typename basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::size_type
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::find_first_not_of(
                                              const CHAR_TYPE *characterString,
                                              size_type        position,
                                              size_type        numChars) const
{
    BSLS_ASSERT_SAFE(characterString || 0 == numChars);

    if (position < length()) {
        const CHAR_TYPE *last = this->dataPtr() + length();
        for (const CHAR_TYPE *current = this->dataPtr() + position;
             current != last;
             ++current)
        {
            if (!BSLSTL_CHAR_TRAITS::find(
                                        characterString, numChars, *current)) {
                return current - this->dataPtr();                     // RETURN
            }
        }
    }
    return npos;
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
BSLS_PLATFORM_AGGRESSIVE_INLINE
typename basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::size_type
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::find_first_not_of(
                                              const CHAR_TYPE *characterString,
                                              size_type        position) const
{
    BSLS_ASSERT_SAFE(characterString);

    return find_first_not_of(characterString,
                             position,
                             CHAR_TRAITS::length(characterString));
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
BSLS_PLATFORM_AGGRESSIVE_INLINE
typename basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::size_type
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::find_first_not_of(
                                                      CHAR_TYPE character,
                                                      size_type position) const
{
    return find_first_not_of(&character, position, size_type(1));
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
BSLS_PLATFORM_AGGRESSIVE_INLINE
typename basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::size_type
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::find_last_not_of (
                                           const basic_string& characterString,
                                           size_type           position) const
                                                          BSLS_KEYWORD_NOEXCEPT
{
    return find_last_not_of(characterString.data(),
                            position,
                            characterString.length());
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
template <class STRING_VIEW_LIKE_TYPE>
BSLS_PLATFORM_AGGRESSIVE_INLINE
typename basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::size_type
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::find_last_not_of(
                const STRING_VIEW_LIKE_TYPE& characterString,
                size_type                    position
                BSLSTL_STRING_DEFINE_ONLY_CONVERTIBLE_TO_STRINGVIEW_PARAM_VOID)
                                const BSLS_KEYWORD_NOEXCEPT_SPECIFICATION(true)
{
    bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS> strView = characterString;
    return find_last_not_of(strView.data(), position, strView.length());
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
typename basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::size_type
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::find_last_not_of (
                                              const CHAR_TYPE *characterString,
                                              size_type        position,
                                              size_type        numChars) const
{
    BSLS_ASSERT_SAFE(characterString || 0 == numChars);

    if (0 < length()) {
        size_type remChars = position < length() ? position : length() - 1;
        for (const CHAR_TYPE *current = this->dataPtr() + remChars;
             remChars != npos;
             --current, --remChars)
        {
            if (!BSLSTL_CHAR_TRAITS::find(
                                        characterString, numChars, *current)) {
                return current - this->dataPtr();                     // RETURN
            }
        }
    }
    return npos;
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
BSLS_PLATFORM_AGGRESSIVE_INLINE
typename basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::size_type
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::find_last_not_of (
                                              const CHAR_TYPE *characterString,
                                              size_type        position) const
{
    BSLS_ASSERT_SAFE(characterString);

    return find_last_not_of(characterString,
                            position,
                            CHAR_TRAITS::length(characterString));
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
BSLS_PLATFORM_AGGRESSIVE_INLINE
typename basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::size_type
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::find_last_not_of (
                                                      CHAR_TYPE character,
                                                      size_type position) const
{
    return find_last_not_of(&character, position, size_type(1));
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
BSLS_PLATFORM_AGGRESSIVE_INLINE bool
basic_string<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>::starts_with(
                     basic_string_view<CHAR_TYPE, CHAR_TRAITS> characterString)
                                                    const BSLS_KEYWORD_NOEXCEPT
{
    return (length() >= characterString.length() &&
            0 == CHAR_TRAITS::compare(data(),
                                      characterString.data(),
                                      characterString.size()));
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
BSLS_PLATFORM_AGGRESSIVE_INLINE
bool basic_string<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>::starts_with(
                               CHAR_TYPE character) const BSLS_KEYWORD_NOEXCEPT
{
    return (0 < length() &&  CHAR_TRAITS::eq(*data(), character));
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
BSLS_PLATFORM_AGGRESSIVE_INLINE
bool basic_string<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>::starts_with(
                                        const CHAR_TYPE *characterString) const
{
    BSLS_ASSERT_SAFE(characterString);

    std::size_t strLength = CHAR_TRAITS::length(characterString);
    return (length() >= strLength &&
            0 == CHAR_TRAITS::compare(data(),
                                      characterString,
                                      strLength));
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
BSLS_PLATFORM_AGGRESSIVE_INLINE bool
basic_string<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>::ends_with(
                     basic_string_view<CHAR_TYPE, CHAR_TRAITS> characterString)
                                                    const BSLS_KEYWORD_NOEXCEPT
{
    return (length() >= characterString.length() &&
            0 == CHAR_TRAITS::compare(
                                  data() + length() - characterString.length(),
                                  characterString.data(),
                                  characterString.size()));
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
BSLS_PLATFORM_AGGRESSIVE_INLINE
bool basic_string<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>::ends_with(
                               CHAR_TYPE character) const BSLS_KEYWORD_NOEXCEPT
{
    return (0 < length() &&
            CHAR_TRAITS::eq(*(data()+ length() - 1), character));
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
BSLS_PLATFORM_AGGRESSIVE_INLINE
bool basic_string<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>::ends_with(
                                        const CHAR_TYPE *characterString) const
{
    BSLS_ASSERT_SAFE(characterString);

    std::size_t strLength = CHAR_TRAITS::length(characterString);
    return (length() >= strLength &&
            0 == CHAR_TRAITS::compare(data() + length() - strLength,
                                      characterString,
                                      strLength));
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
BSLS_PLATFORM_AGGRESSIVE_INLINE
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>
basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::substr(size_type position,
                                                      size_type numChars) const
{
    return basic_string<CHAR_TYPE,
                        CHAR_TRAITS,
                        ALLOCATOR>(*this, position, numChars);
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
BSLS_PLATFORM_AGGRESSIVE_INLINE
int basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::compare(
                                               const basic_string& other) const
                                                          BSLS_KEYWORD_NOEXCEPT
{
    return privateCompareRaw(size_type(0),
                             length(),
                             other.data(),
                             other.length());
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
int basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::compare(
                                              size_type            position,
                                              size_type            numChars,
                                              const basic_string&  other) const
{
    privateThrowOutOfRange(
                    length() < position,
                    "const string<...>::compare(pos,n,...): invalid position");
    if (numChars > length() - position) {
        numChars = length() - position;
    }
    return privateCompareRaw(position, numChars, other.data(), other.length());
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
int basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::compare(
                                       size_type           lhsPosition,
                                       size_type           lhsNumChars,
                                       const basic_string& other,
                                       size_type           otherPosition,
                                       size_type           otherNumChars) const
{
    privateThrowOutOfRange(
                    length() < lhsPosition,
                    "const string<...>::compare(pos,n,...): invalid position");
    if (lhsNumChars > length() - lhsPosition) {
        lhsNumChars = length() - lhsPosition;
    }
    privateThrowOutOfRange(
                    other.length() < otherPosition,
                    "const string<...>::compare(pos,n,...): invalid position");
    if (otherNumChars > other.length() - otherPosition) {
        otherNumChars = other.length() - otherPosition;
    }
    return privateCompareRaw(lhsPosition,
                             lhsNumChars,
                             other.dataPtr() + otherPosition,
                             otherNumChars);
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
BSLS_PLATFORM_AGGRESSIVE_INLINE
int basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::compare(
                                                  const CHAR_TYPE *other) const
{
    BSLS_ASSERT_SAFE(other);

    return privateCompareRaw(size_type(0),
                             length(),
                             other,
                             CHAR_TRAITS::length(other));
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
int basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::compare(
                                          size_type        lhsPosition,
                                          size_type        lhsNumChars,
                                          const CHAR_TYPE *other,
                                          size_type        otherNumChars) const
{
    BSLS_ASSERT_SAFE(other);

    privateThrowOutOfRange(
                    length() < lhsPosition,
                    "const string<...>::compare(pos,n,...): invalid position");
    if (lhsNumChars > length() - lhsPosition) {
        lhsNumChars = length() - lhsPosition;
    }
    return privateCompareRaw(lhsPosition,
                             lhsNumChars,
                             other,
                             otherNumChars);
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
BSLS_PLATFORM_AGGRESSIVE_INLINE
int basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::compare(
                                                  size_type        lhsPosition,
                                                  size_type        lhsNumChars,
                                                  const CHAR_TYPE *other) const
{
    BSLS_ASSERT_SAFE(other);

    return compare(lhsPosition,
                   lhsNumChars,
                   other,
                   CHAR_TRAITS::length(other));
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
template <class STRING_VIEW_LIKE_TYPE>
BSLS_PLATFORM_AGGRESSIVE_INLINE
int basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::compare(
                const STRING_VIEW_LIKE_TYPE& other
                BSLSTL_STRING_DEFINE_ONLY_CONVERTIBLE_TO_STRINGVIEW_PARAM_VOID)
                                const BSLS_KEYWORD_NOEXCEPT_SPECIFICATION(true)
{
    bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS> strView = other;

    return privateCompareRaw(size_type(0),
                             length(),
                             strView.data(),
                             strView.length());
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
template <class STRING_VIEW_LIKE_TYPE>
int basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::compare(
          size_type                    position,
          size_type                    numChars,
          const STRING_VIEW_LIKE_TYPE& other
          BSLSTL_STRING_DEFINE_ONLY_CONVERTIBLE_TO_STRINGVIEW_PARAM_VOID) const
{
    privateThrowOutOfRange(
                  length() < position,
                  "string<...>::compare(pos,n,StrViewLike): invalid position");

    bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS> strView = other;

    if (numChars > length() - position) {
        numChars = length() - position;
    }
    return privateCompareRaw(position,
                             numChars,
                             strView.data(),
                             strView.length());
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
template <class STRING_VIEW_LIKE_TYPE>
int basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::compare(
          size_type                    lhsPosition,
          size_type                    lhsNumChars,
          const STRING_VIEW_LIKE_TYPE& other,
          size_type                    otherPosition,
          size_type                    otherNumChars
          BSLSTL_STRING_DEFINE_ONLY_CONVERTIBLE_TO_STRINGVIEW_PARAM_VOID) const
{
    privateThrowOutOfRange(
        length() < lhsPosition,
        "string<...>::compare(pos,n, StrViewLike,...): invalid lhs position");

    bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS> strView = other;

    privateThrowOutOfRange(
        strView.length() < otherPosition,
        "string<...>::compare(pos,n, StrViewLike,...): invalid rhs position");

    if (lhsNumChars > length() - lhsPosition) {
        lhsNumChars = length() - lhsPosition;
    }
    if (otherNumChars > other.length() - otherPosition) {
        otherNumChars = other.length() - otherPosition;
    }
    return privateCompareRaw(lhsPosition,
                             lhsNumChars,
                             strView.data() + otherPosition,
                             otherNumChars);
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
BSLS_PLATFORM_AGGRESSIVE_INLINE
basic_string<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>::
operator basic_string_view<CHAR_TYPE, CHAR_TRAITS>() const
{
    return basic_string_view<CHAR_TYPE, CHAR_TRAITS>(data(), size());
}

// PUBLIC ACCESSORS
template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
BSLS_PLATFORM_AGGRESSIVE_INLINE
std::size_t hash<basic_string<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR> >::
operator()(const basic_string<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>& input) const
{
    using ::BloombergLP::bslh::hashAppend;
    ::BloombergLP::bslh::Hash<>::HashAlgorithm hashAlg;
    hashAlg(input.data(), sizeof(CHAR_TYPE) * input.size());
    hashAppend(hashAlg, input.size());
    return static_cast<std::size_t>(hashAlg.computeHash());
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
BSLS_PLATFORM_AGGRESSIVE_INLINE
std::size_t hash<basic_string<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR> >::
operator()(const CHAR_TYPE *input) const
{
    BSLS_ASSERT_SAFE(input);
    using ::BloombergLP::bslh::hashAppend;
    std::size_t length = CHAR_TRAITS::length(input);
    ::BloombergLP::bslh::Hash<>::HashAlgorithm hashAlg;
    hashAlg(input, sizeof(CHAR_TYPE) * length);
    hashAppend(hashAlg, length);
    return static_cast<std::size_t>(hashAlg.computeHash());
}

#if defined(BSLS_PLATFORM_CMP_SUN) && BSLS_PLATFORM_CMP_VERSION < 0x5130
// {DRQS 132030795}
inline
std::size_t hash<string>::operator()(const string& input) const
{
    using ::BloombergLP::bslh::hashAppend;
    ::BloombergLP::bslh::Hash<>::HashAlgorithm hashAlg;
    hashAlg(input.data(), input.size());
    hashAppend(hashAlg, input.size());
    return static_cast<std::size_t>(hashAlg.computeHash());
}

inline
std::size_t hash<string>::operator()(const char *input) const
{
    BSLS_ASSERT_SAFE(input);
    using ::BloombergLP::bslh::hashAppend;
    std::size_t length = char_traits<char>::length(input);
    ::BloombergLP::bslh::Hash<>::HashAlgorithm hashAlg;
    hashAlg(input, length);
    hashAppend(hashAlg, length);
    return static_cast<std::size_t>(hashAlg.computeHash());
}

inline
std::size_t hash<wstring>::operator()(const wstring& input) const
{
    using ::BloombergLP::bslh::hashAppend;
    ::BloombergLP::bslh::Hash<>::HashAlgorithm hashAlg;
    hashAlg(input.data(), sizeof(wchar_t) * input.size());
    hashAppend(hashAlg, input.size());
    return static_cast<std::size_t>(hashAlg.computeHash());
}

inline
std::size_t hash<wstring>::operator()(const wchar_t *input) const
{
    BSLS_ASSERT_SAFE(input);
    using ::BloombergLP::bslh::hashAppend;
    std::size_t length = char_traits<wchar_t>::length(input);
    ::BloombergLP::bslh::Hash<>::HashAlgorithm hashAlg;
    hashAlg(input, sizeof(wchar_t) * length);
    hashAppend(hashAlg, length);
    return static_cast<std::size_t>(hashAlg.computeHash());
}

#endif

}  // close namespace bsl

// FREE FUNCTIONS
template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
inline
void bsl::swap(basic_string<CHAR_TYPE,CHAR_TRAITS, ALLOCATOR>& a,
               basic_string<CHAR_TYPE,CHAR_TRAITS, ALLOCATOR>& b)
                            BSLS_KEYWORD_NOEXCEPT_SPECIFICATION(
                                BSLS_KEYWORD_NOEXCEPT_OPERATOR(a.swap(b)))
{
    a.swap(b);
}

// FREE OPERATORS
template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOC>
inline
bool bsl::operator==(const basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOC>& lhs,
                     const basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOC>& rhs)
                                                          BSLS_KEYWORD_NOEXCEPT
{
    return lhs.size() == rhs.size()
        && 0 == CHAR_TRAITS::compare(lhs.data(), rhs.data(), lhs.size());
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOC1, class ALLOC2>
inline
bool
bsl::operator==(const std::basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOC1>& lhs,
                const bsl::basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOC2>& rhs)
                                                          BSLS_KEYWORD_NOEXCEPT
{
    return lhs.size() == rhs.size()
        && 0 == CHAR_TRAITS::compare(lhs.data(), rhs.data(), lhs.size());
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOC1, class ALLOC2>
inline
bool
bsl::operator==(const bsl::basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOC1>& lhs,
                const std::basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOC2>& rhs)
                                                          BSLS_KEYWORD_NOEXCEPT
{
    return lhs.size() == rhs.size()
        && 0 == CHAR_TRAITS::compare(lhs.data(), rhs.data(), lhs.size());
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOC>
inline
bool bsl::operator==(const CHAR_TYPE                                  *lhs,
                     const basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOC>&  rhs)
{
    BSLS_ASSERT_SAFE(lhs);

    std::size_t len = CHAR_TRAITS::length(lhs);
    return len == rhs.size()
        && 0 == CHAR_TRAITS::compare(lhs, rhs.data(), len);
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOC>
inline
bool bsl::operator==(const basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOC>&  lhs,
                     const CHAR_TYPE                                  *rhs)
{
    BSLS_ASSERT_SAFE(rhs);

    std::size_t len = CHAR_TRAITS::length(rhs);
    return lhs.size() == len
        && 0 == CHAR_TRAITS::compare(lhs.data(), rhs, len);
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOC>
inline
bool bsl::operator!=(const basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOC>& lhs,
                     const basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOC>& rhs)
                                                          BSLS_KEYWORD_NOEXCEPT
{
    return !(lhs == rhs);
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOC1, class ALLOC2>
inline
bool
bsl::operator!=(const std::basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOC1>& lhs,
                const bsl::basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOC2>& rhs)
                                                          BSLS_KEYWORD_NOEXCEPT
{
    return !(lhs == rhs);
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOC1, class ALLOC2>
inline
bool
bsl::operator!=(const bsl::basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOC1>& lhs,
                const std::basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOC2>& rhs)
                                                          BSLS_KEYWORD_NOEXCEPT
{
    return !(lhs == rhs);
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOC>
inline
bool bsl::operator!=(const CHAR_TYPE                                  *lhs,
                     const basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOC>&  rhs)
{
    BSLS_ASSERT_SAFE(lhs);

    return !(lhs == rhs);
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOC>
inline
bool bsl::operator!=(const basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOC>&  lhs,
                     const CHAR_TYPE                                  *rhs)
{
    BSLS_ASSERT_SAFE(rhs);

    return !(lhs == rhs);
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOC>
bool bsl::operator<(const basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOC>& lhs,
                    const basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOC>& rhs)
                                                          BSLS_KEYWORD_NOEXCEPT
{
    const std::size_t minLen = lhs.length() < rhs.length()
                             ? lhs.length() : rhs.length();

    int ret = CHAR_TRAITS::compare(lhs.data(), rhs.data(), minLen);
    if (0 == ret) {
        return lhs.length() < rhs.length();                           // RETURN
    }
    return ret < 0;
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOC1, class ALLOC2>
bool
bsl::operator<(const std::basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOC1>& lhs,
               const bsl::basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOC2>& rhs)
                                                          BSLS_KEYWORD_NOEXCEPT
{
    const std::size_t minLen = lhs.length() < rhs.length()
                             ? lhs.length() : rhs.length();

    int ret = CHAR_TRAITS::compare(lhs.data(), rhs.data(), minLen);
    if (0 == ret) {
        return lhs.length() < rhs.length();                           // RETURN
    }
    return ret < 0;
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOC1, class ALLOC2>
bool
bsl::operator<(const bsl::basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOC1>& lhs,
               const std::basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOC2>& rhs)
                                                          BSLS_KEYWORD_NOEXCEPT
{
    const std::size_t minLen = lhs.length() < rhs.length()
                             ? lhs.length() : rhs.length();

    int ret = CHAR_TRAITS::compare(lhs.data(), rhs.data(), minLen);
    if (0 == ret) {
        return lhs.length() < rhs.length();                           // RETURN
    }
    return ret < 0;
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOC>
bool bsl::operator<(const CHAR_TYPE                                  *lhs,
                    const basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOC>&  rhs)
{
    BSLS_ASSERT_SAFE(lhs);

    const std::size_t lhsLen = CHAR_TRAITS::length(lhs);
    const std::size_t minLen = lhsLen < rhs.length() ? lhsLen : rhs.length();

    int ret = CHAR_TRAITS::compare(lhs, rhs.data(), minLen);
    if (0 == ret) {
        return lhsLen < rhs.length();                                 // RETURN
    }
    return ret < 0;
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOC>
bool bsl::operator<(const basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOC>&  lhs,
                    const CHAR_TYPE                                  *rhs)
{
    BSLS_ASSERT_SAFE(rhs);

    const std::size_t rhsLen = CHAR_TRAITS::length(rhs);
    const std::size_t minLen = rhsLen < lhs.length() ? rhsLen : lhs.length();

    int ret = CHAR_TRAITS::compare(lhs.data(), rhs, minLen);
    if (0 == ret) {
        return lhs.length() < rhsLen;                                 // RETURN
    }
    return ret < 0;
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOC>
inline
bool bsl::operator>(const basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOC>& lhs,
                    const basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOC>& rhs)
                                                          BSLS_KEYWORD_NOEXCEPT
{
    return rhs < lhs;
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOC1, class ALLOC2>
inline
bool
bsl::operator>(const std::basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOC1>& lhs,
               const bsl::basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOC2>& rhs)
                                                          BSLS_KEYWORD_NOEXCEPT
{
    return rhs < lhs;
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOC1, class ALLOC2>
inline
bool
bsl::operator>(const bsl::basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOC1>& lhs,
               const std::basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOC2>& rhs)
                                                          BSLS_KEYWORD_NOEXCEPT
{
    return rhs < lhs;
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOC>
inline
bool bsl::operator>(const CHAR_TYPE                                  *lhs,
                    const basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOC>&  rhs)
{
    BSLS_ASSERT_SAFE(lhs);

    return rhs < lhs;
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOC>
inline
bool bsl::operator>(const basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOC>&  lhs,
                    const CHAR_TYPE                                  *rhs)
{
    BSLS_ASSERT_SAFE(rhs);

    return rhs < lhs;
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOC>
inline
bool bsl::operator<=(const basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOC>& lhs,
                     const basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOC>& rhs)
                                                          BSLS_KEYWORD_NOEXCEPT
{
    return !(rhs < lhs);
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOC1, class ALLOC2>
inline
bool
bsl::operator<=(const std::basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOC1>& lhs,
                const bsl::basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOC2>& rhs)
                                                          BSLS_KEYWORD_NOEXCEPT
{
    return !(rhs < lhs);
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOC1, class ALLOC2>
inline
bool
bsl::operator<=(const bsl::basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOC1>& lhs,
                const std::basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOC2>& rhs)
                                                          BSLS_KEYWORD_NOEXCEPT
{
    return !(rhs < lhs);
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOC>
inline
bool bsl::operator<=(const CHAR_TYPE                                  *lhs,
                     const basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOC>&  rhs)
{
    BSLS_ASSERT_SAFE(lhs);

    return !(rhs < lhs);
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOC>
inline
bool bsl::operator<=(const basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOC>&  lhs,
                     const CHAR_TYPE                                  *rhs)
{
    BSLS_ASSERT_SAFE(rhs);

    return !(rhs < lhs);
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOC>
inline
bool bsl::operator>=(const basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOC>& lhs,
                     const basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOC>& rhs)
                                                          BSLS_KEYWORD_NOEXCEPT
{
    return !(lhs < rhs);
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOC1, class ALLOC2>
inline
bool
bsl::operator>=(const std::basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOC1>& lhs,
                const bsl::basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOC2>& rhs)
                                                          BSLS_KEYWORD_NOEXCEPT
{
    return !(lhs < rhs);
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOC1, class ALLOC2>
inline
bool
bsl::operator>=(const bsl::basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOC1>& lhs,
                const std::basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOC2>& rhs)
                                                          BSLS_KEYWORD_NOEXCEPT
{
    return !(lhs < rhs);
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOC>
inline
bool bsl::operator>=(const CHAR_TYPE                                  *lhs,
                     const basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOC>&  rhs)
{
    BSLS_ASSERT_SAFE(lhs);

    return !(lhs < rhs);
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOC>
inline
bool bsl::operator>=(const basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOC>&  lhs,
                     const CHAR_TYPE                                  *rhs)
{
    BSLS_ASSERT_SAFE(rhs);

    return !(lhs < rhs);
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
bsl::basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>
bsl::operator+(const basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>& lhs,
               const basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>& rhs)
{
    basic_string<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR> result(
        bsl::allocator_traits<ALLOCATOR>::
            select_on_container_copy_construction(lhs.get_allocator()));
    result.reserve(lhs.length() + rhs.length());
    result += lhs;
    result += rhs;
    return result;
}

#ifdef BSLSTL_STRING_SUPPORT_RVALUE_ADDITION_OPERATORS
template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
bsl::basic_string<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>
bsl::operator+(bsl::basic_string<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR> && lhs,
               const basic_string<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>&  rhs)
{
    basic_string<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>& lvalue = lhs;
    lvalue.append(rhs);
    return basic_string<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>(
        BloombergLP::bslmf::MovableRefUtil::move(lvalue));
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
bsl::basic_string<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>
bsl::operator+(const basic_string<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>&  lhs,
               bsl::basic_string<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR> && rhs)
{
    basic_string<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>& lvalue = rhs;
    lvalue.insert(0, lhs);
    return basic_string<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>(
        BloombergLP::bslmf::MovableRefUtil::move(lvalue));
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
bsl::basic_string<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>
bsl::operator+(bsl::basic_string<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>&& lhs,
               bsl::basic_string<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>&& rhs)
{
    basic_string<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>& lvalue = lhs;
    lvalue.append(rhs);
    return basic_string<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>(
        BloombergLP::bslmf::MovableRefUtil::move(lvalue));
}
#endif

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOC1, class ALLOC2>
bsl::basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOC2>
bsl::operator+(const std::basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOC1>& lhs,
               const bsl::basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOC2>& rhs)
{
    bsl::basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOC2> result(
        bsl::allocator_traits<ALLOC2>::
            select_on_container_copy_construction(rhs.get_allocator()));
    result.reserve(lhs.length() + rhs.length());
    result.append(lhs.c_str(), lhs.length());
    result += rhs;
    return result;
}

#ifdef BSLSTL_STRING_SUPPORT_RVALUE_ADDITION_OPERATORS
template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOC1, class ALLOC2>
bsl::basic_string<CHAR_TYPE, CHAR_TRAITS, ALLOC2>
bsl::operator+(const std::basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOC1>& lhs,
               bsl::basic_string<CHAR_TYPE, CHAR_TRAITS, ALLOC2> &&   rhs)
{
    basic_string<CHAR_TYPE, CHAR_TRAITS, ALLOC2>& lvalue = rhs;
    lvalue.insert(0, lhs.c_str(), lhs.size());
    return basic_string<CHAR_TYPE, CHAR_TRAITS, ALLOC2>(
        BloombergLP::bslmf::MovableRefUtil::move(lvalue));
}
#endif

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOC1, class ALLOC2>
bsl::basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOC1>
bsl::operator+(const bsl::basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOC1>& lhs,
               const std::basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOC2>& rhs)
{
    bsl::basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOC1> result(
        bsl::allocator_traits<ALLOC1>::
            select_on_container_copy_construction(lhs.get_allocator()));
    result.reserve(lhs.length() + rhs.length());
    result += lhs;
    result.append(rhs.c_str(), rhs.length());
    return result;
}

#ifdef BSLSTL_STRING_SUPPORT_RVALUE_ADDITION_OPERATORS
template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOC1, class ALLOC2>
bsl::basic_string<CHAR_TYPE, CHAR_TRAITS, ALLOC1>
bsl::operator+(bsl::basic_string<CHAR_TYPE, CHAR_TRAITS, ALLOC1> &&   lhs,
               const std::basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOC2>& rhs)
{
    basic_string<CHAR_TYPE, CHAR_TRAITS, ALLOC1>& lvalue = lhs;
    lvalue.append(rhs.c_str(), rhs.length());
    return basic_string<CHAR_TYPE, CHAR_TRAITS, ALLOC1>(
        BloombergLP::bslmf::MovableRefUtil::move(lvalue));
}
#endif

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
bsl::basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>
bsl::operator+(const CHAR_TYPE                                      *lhs,
               const basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>&  rhs)
{
    BSLS_ASSERT_SAFE(lhs);

    typename basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::size_type
                                          lhsLength = CHAR_TRAITS::length(lhs);

    basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR> result(
        bsl::allocator_traits<ALLOCATOR>::
            select_on_container_copy_construction(rhs.get_allocator()));
    result.reserve(lhsLength + rhs.length());
    result.append(lhs, lhsLength);
    result += rhs;
    return result;
}

#ifdef BSLSTL_STRING_SUPPORT_RVALUE_ADDITION_OPERATORS
template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
bsl::basic_string<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>
bsl::operator+(const CHAR_TYPE                                        *lhs,
               bsl::basic_string<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>&&  rhs)
{
    BSLS_ASSERT_SAFE(lhs);

    basic_string<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>& lvalue = rhs;
    lvalue.insert(0, lhs);
    return basic_string<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>(
        BloombergLP::bslmf::MovableRefUtil::move(lvalue));
}
#endif

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
bsl::basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>
bsl::operator+(CHAR_TYPE                                            lhs,
               const basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>& rhs)
{
    basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR> result(
        bsl::allocator_traits<ALLOCATOR>::
            select_on_container_copy_construction(rhs.get_allocator()));
    result.reserve(1 + rhs.length());
    result.push_back(lhs);
    result += rhs;
    return result;
}

#ifdef BSLSTL_STRING_SUPPORT_RVALUE_ADDITION_OPERATORS
template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
bsl::basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>
bsl::operator+(CHAR_TYPE                                               lhs,
               bsl::basic_string<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR> && rhs)
{
    basic_string<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>& lvalue = rhs;
    lvalue.insert(lvalue.begin(), lhs);
    return basic_string<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>(
        BloombergLP::bslmf::MovableRefUtil::move(lvalue));
}
#endif


template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
bsl::basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>
bsl::operator+(const basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>&  lhs,
               const CHAR_TYPE                                      *rhs)
{
    BSLS_ASSERT_SAFE(rhs);
    typename basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::size_type
                                          rhsLength = CHAR_TRAITS::length(rhs);

    basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR> result(
        bsl::allocator_traits<ALLOCATOR>::
            select_on_container_copy_construction(lhs.get_allocator()));
    result.reserve(lhs.length() + rhsLength);
    result += lhs;
    result.append(rhs, rhsLength);
    return result;
}

#ifdef BSLSTL_STRING_SUPPORT_RVALUE_ADDITION_OPERATORS
template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
bsl::basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>
bsl::operator+(bsl::basic_string<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR> &&  lhs,
               const CHAR_TYPE                                         *rhs)
{
    BSLS_ASSERT_SAFE(rhs);

    basic_string<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>& lvalue = lhs;
    lvalue.append(rhs);
    return basic_string<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>(
        BloombergLP::bslmf::MovableRefUtil::move(lvalue));
}
#endif

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
bsl::basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>
bsl::operator+(const basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>& lhs,
               CHAR_TYPE                                            rhs)
{
    basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR> result(
        bsl::allocator_traits<ALLOCATOR>::
            select_on_container_copy_construction(lhs.get_allocator()));
    result.reserve(lhs.length() + 1);
    result += lhs;
    result.push_back(rhs);
    return result;
}

#ifdef BSLSTL_STRING_SUPPORT_RVALUE_ADDITION_OPERATORS
template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
bsl::basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>
bsl::operator+(bsl::basic_string<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR> && lhs,
               CHAR_TYPE                                               rhs)
{
    basic_string<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>& lvalue = lhs;
    lvalue.push_back(rhs);
    return basic_string<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>(
        BloombergLP::bslmf::MovableRefUtil::move(lvalue));
}
#endif

template <class CHAR_TYPE, class CHAR_TRAITS>
bool bslstl_string_fill(std::basic_ostream<CHAR_TYPE, CHAR_TRAITS>&   os,
                        std::basic_streambuf<CHAR_TYPE, CHAR_TRAITS> *buf,
                        std::size_t                                   n)
    // Do not use, for internal use by 'operator<<' only.
{
    BSLS_ASSERT_SAFE(buf);

    CHAR_TYPE fillChar = os.fill();

    for (std::size_t i = 0; i < n; ++i) {
        if (CHAR_TRAITS::eq_int_type(buf->sputc(fillChar), CHAR_TRAITS::eof()))
        {
            return false;                                             // RETURN
        }
    }

    return true;
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
std::basic_ostream<CHAR_TYPE, CHAR_TRAITS>&
bsl::operator<<(std::basic_ostream<CHAR_TYPE, CHAR_TRAITS>&          os,
                const basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>& str)
{
    typedef std::basic_ostream<CHAR_TYPE, CHAR_TRAITS> Ostrm;
    typename Ostrm::sentry sentry(os);
    bool ok = false;

    if (sentry) {
        ok = true;
        std::size_t     n      = str.size();
        std::size_t     padLen = 0;
        bool            left   = (os.flags() & Ostrm::left) != 0;
        std::streamsize w      = os.width(0);

        std::basic_streambuf<CHAR_TYPE, CHAR_TRAITS> *buf = os.rdbuf();

        if (w > 0 && std::size_t(w) > n) {
            padLen = std::size_t(w) - n;
        }

        if (!left) {
            ok = bslstl_string_fill(os, buf, padLen);
        }

        ok = ok && (buf->sputn(str.data(), std::streamsize(n)) ==
                        std::streamsize(n));

        if (left) {
            ok = ok && bslstl_string_fill(os, buf, padLen);
        }
    }

    if (!ok) {
        os.setstate(Ostrm::failbit);
    }

    return os;
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
std::basic_istream<CHAR_TYPE, CHAR_TRAITS>&
bsl::operator>>(std::basic_istream<CHAR_TYPE, CHAR_TRAITS>&     is,
                basic_string<CHAR_TYPE,CHAR_TRAITS, ALLOCATOR>& str)
{
    typedef std::basic_istream<CHAR_TYPE, CHAR_TRAITS> Istrm;
    typename Istrm::sentry sentry(is);

    if (sentry) {
        std::basic_streambuf<CHAR_TYPE, CHAR_TRAITS> *buf = is.rdbuf();
        typedef std::ctype<CHAR_TYPE> CType;

        const std::locale& loc   = is.getloc();
        const CType&       ctype = std::use_facet<CType>(loc);

        str.clear();
        std::streamsize n = is.width(0);
        if (n <= 0) {
            n = std::numeric_limits<std::streamsize>::max();
        }
        else {
            str.reserve(n);
        }

        while (n-- > 0) {
            typename CHAR_TRAITS::int_type c1 = buf->sbumpc();
            if (CHAR_TRAITS::eq_int_type(c1, CHAR_TRAITS::eof())) {
                is.setstate(Istrm::eofbit);
                break;
            }
            else {
                CHAR_TYPE c = CHAR_TRAITS::to_char_type(c1);

                if (ctype.is(CType::space, c)) {
                    if (CHAR_TRAITS::eq_int_type(buf->sputbackc(c),
                                                 CHAR_TRAITS::eof())) {
                        is.setstate(Istrm::failbit);
                    }
                    break;
                }
                else {
                    str.push_back(c);
                }
            }
        }

        // If we have read no characters, then set failbit.

        if (str.size() == 0) {
            is.setstate(Istrm::failbit);
        }
    }
    else {
        is.setstate(Istrm::failbit);
    }

    return is;
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
std::basic_istream<CHAR_TYPE, CHAR_TRAITS>&
bsl::getline(std::basic_istream<CHAR_TYPE, CHAR_TRAITS>&    is,
             basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>& str,
             CHAR_TYPE                                      delim)
{
    typedef std::basic_istream<CHAR_TYPE, CHAR_TRAITS> Istrm;
    std::size_t nread = 0;
    typename Istrm::sentry sentry(is, true);
    if (sentry) {
        std::basic_streambuf<CHAR_TYPE, CHAR_TRAITS> *buf = is.rdbuf();
        str.clear();

        while (nread < str.max_size()) {
            int c1 = buf->sbumpc();
            if (CHAR_TRAITS::eq_int_type(c1, CHAR_TRAITS::eof())) {
                is.setstate(Istrm::eofbit);
                break;
            }

            ++nread;
            CHAR_TYPE c = CHAR_TRAITS::to_char_type(c1);
            if (!CHAR_TRAITS::eq(c, delim)) {
                str.push_back(c);
            }
            else {
                break;  // character is extracted but not appended
            }
        }
    }
    if (nread == 0 || nread >= str.max_size()) {
        is.setstate(Istrm::failbit);
    }

    return is;
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
inline
std::basic_istream<CHAR_TYPE, CHAR_TRAITS>&
bsl::getline(std::basic_istream<CHAR_TYPE, CHAR_TRAITS>&    is,
             basic_string<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>& str)
{
    return getline(is, str, is.widen('\n'));
}

// HASH SPECIALIZATIONS
template <class HASHALG, class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
inline
void bsl::hashAppend(
                HASHALG&                                               hashAlg,
                const basic_string<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>& input)
{
    using ::BloombergLP::bslh::hashAppend;
    hashAlg(input.data(), sizeof(CHAR_TYPE)*input.size());
    hashAppend(hashAlg, input.size());
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
BSLS_PLATFORM_AGGRESSIVE_INLINE
std::size_t bsl::hashBasicString(
                    const basic_string<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>& str)
{
    return ::BloombergLP::bslh::Hash<>()(str);
}

namespace BloombergLP {

template <class HASHALG, class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
BSLS_PLATFORM_AGGRESSIVE_INLINE
void bslh::hashAppend(
           HASHALG&                                                    hashAlg,
           const std::basic_string<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>& input)
{
    hashAlg(input.data(), sizeof(CHAR_TYPE)*input.size());
    hashAppend(hashAlg, input.size());
}

}  // close enterprise namespace

// ============================================================================
//                                TYPE TRAITS
// ============================================================================

// Type traits for STL *sequence* containers:
// o A sequence container defines STL iterators.
// o A sequence container is bitwise movable if the allocator is bitwise
//   movable.
// o A sequence container uses 'bslma' allocators if the (template parameter)
//   type 'ALLOCATOR' is convertible from 'bslma::Allocator *'.

namespace BloombergLP {

namespace bslalg {

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOC>
struct HasStlIterators<bsl::basic_string<CHAR_TYPE, CHAR_TRAITS, ALLOC> >
    : bsl::true_type
{};

}  // close namespace bslalg

namespace bslma {

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOC>
struct UsesBslmaAllocator<bsl::basic_string<CHAR_TYPE, CHAR_TRAITS, ALLOC> >
    : bsl::is_convertible<Allocator *, ALLOC>
{};

}  // close namespace bslma

}  // close enterprise namespace

#undef BSLSTL_CHAR_TRAITS

#ifdef BSLS_COMPILERFEATURES_SUPPORT_EXTERN_TEMPLATE
extern template class bsl::String_Imp<char, bsl::string::size_type>;
extern template class bsl::String_Imp<wchar_t, bsl::wstring::size_type>;
extern template class bsl::basic_string<char>;
extern template class bsl::basic_string<wchar_t>;

# if defined(BSLS_COMPILERFEATURES_SUPPORT_UTF8_CHAR_TYPE)
extern template class bsl::String_Imp<char8_t, bsl::u8string::size_type>;
extern template class bsl::basic_string<char8_t>;
# endif

# if defined(BSLS_COMPILERFEATURES_SUPPORT_UNICODE_CHAR_TYPES)
extern template class bsl::String_Imp<char16_t, bsl::u16string::size_type>;
extern template class bsl::String_Imp<char32_t, bsl::u32string::size_type>;
extern template class bsl::basic_string<char16_t>;
extern template class bsl::basic_string<char32_t>;
# endif

#endif

#undef BSLSTL_STRING_SUPPORT_RVALUE_ADDITION_OPERATORS

#undef BSLSTL_STRING_DEFINE_STRINGVIEW_LIKE_TYPE_IF_COMPLETE
#undef BSLSTL_STRING_DEFINE_ONLY_CONVERTIBLE_TO_STRINGVIEW_RETURN_TYPE
#undef BSLSTL_STRING_DECLARE_CONVERTIBLE_TO_STRINGVIEW_PARAM_VOID
#undef BSLSTL_STRING_DEFINE_CONVERTIBLE_TO_STRINGVIEW_PARAM_VOID
#undef BSLSTL_STRING_DECLARE_ONLY_CONVERTIBLE_TO_STRINGVIEW_PARAM_VOID
#undef BSLSTL_STRING_DEFINE_ONLY_CONVERTIBLE_TO_STRINGVIEW_PARAM_VOID
#undef BSLSTL_STRING_DECLARE_ONLY_CONVERTIBLE_TO_STRINGVIEW_PARAM_ALLOC
#undef BSLSTL_STRING_DEFINE_ONLY_CONVERTIBLE_TO_STRINGVIEW_PARAM_ALLOC

#undef BSLSTL_STRING_DEDUCE_RVREF
#undef BSLSTL_STRING_DEDUCE_RVREF_1
#undef BSLSTL_STRING_DEDUCE_RVREF_2

#endif

// ----------------------------------------------------------------------------
// Copyright 2013 Bloomberg Finance L.P.
//
// Licensed 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.
// ----------------------------- END-OF-FILE ----------------------------------