// bslstl_stringview.h                                                -*-C++-*-
#ifndef INCLUDED_BSLSTL_STRINGVIEW
#define INCLUDED_BSLSTL_STRINGVIEW

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

//@PURPOSE: Provide a standard-compliant 'basic_string_view' class template.
//
//@CLASSES:
//  bsl::basic_string_view: C++ compliant 'basic_string_view' implementation
//  bsl::string_view: 'typedef' for 'bsl::basic_string_view<char>'
//  bsl::wstring_view: 'typedef' for 'bsl::basic_string_view<wchar_t>'
//
//@CANONICAL_HEADER: bsl_string_view.h
//
//@SEE_ALSO: ISO C++ Standard, bdlb_stringviewutil
//
//@DESCRIPTION: This component defines a single class template
// 'bsl::basic_string_view' and aliases for ordinary and wide character
// specializations 'bsl::string_view' and 'bsl::wstring_view' implementing
// standard containers, 'std::string_view' and 'std::wstring_view', that can
// refer to a constant contiguous sequence of char-like objects with the first
// element of the sequence at position zero.
//
// An instantiation of 'basic_string_view' is a value-semantic type whose
// salient attribute is the sequence of characters it represents.  The
// 'basic_string_view' 'class' is parameterized by the character type,
// 'CHAR_TYPE' and that character type's traits, 'CHAR_TRAITS'.  The traits for
// each character type provide functions that assign, compare, and copy a
// sequence of those characters.
//
// A 'basic_string_view' meets the requirements of a sequential container with
// random access iterators as specified in the [basic.string_view] section of
// the C++ standard [24.4].  The 'basic_string_view' implemented here adheres
// to the C++17 standard, except that it does not have template specializations
// 'std::u16string_view' and 'std::u32string_view'.  Note that if compiler
// supports C++17 standard, then 'stl' implementation of 'basic_string_view' is
// used.
//
///Lexicographical Comparisons
///---------------------------
// Two 'basic_string_view'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::compare' in lexicographical fashion.  If
// 'CHAR_TRAITS::compare' determines that string_views are non-equal (smaller
// or larger), then this is the result.  Otherwise, the lengths of the
// string_views are compared and the shorter string_view is declared the
// smaller.  Lexicographical comparison returns equality only when both
// string_views 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_view':
//..
//  Legend
//  ------
//  'V'              - the 'CHAR_TYPE' template parameter type of the
//                     'basic_string_view'
//  'a', 'b'         - two distinct objects of type 'basic_string_view<V>'
//  'k'              - an integral number
//  'p'              - a pointer defining a sequence of 'CHAR_TYPE' characters
//
//  +----------------------------------------------+--------------------------+
//  | Operation                                    | Complexity               |
//  |==============================================+==========================|
//  | basic_string_view<V> a (default construction)| O[1]                     |
//  |----------------------------------------------+--------------------------|
//  | basic_string_view<V> a(b) (copy construction)| O[1]                     |
//  |----------------------------------------------+--------------------------|
//  | basic_string_view<V> a(p)                    | O[n]                     |
//  |----------------------------------------------+--------------------------|
//  | basic_string_view<V> a(p, k)                 | O[1]                     |
//  |----------------------------------------------+--------------------------|
//  | a.~basic_string_view<V>() (destruction)      | 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.remove_prefix(k)                           | O[1]                     |
//  | a.remove_suffix(k)                           |                          |
//  |----------------------------------------------+--------------------------|
//  | a[k]                                         | O[1]                     |
//  |----------------------------------------------+--------------------------|
//  | a.at(k)                                      | O[1]                     |
//  |----------------------------------------------+--------------------------|
//  | a.front()                                    | O[1]                     |
//  |----------------------------------------------+--------------------------|
//  | a.back()                                     | O[1]                     |
//  |----------------------------------------------+--------------------------|
//  | a.swap(b), swap(a, b)                        | O[1]                     |
//  |----------------------------------------------+--------------------------|
//  | a = b; (assignment)                          | O[1]                     |
//  |----------------------------------------------+--------------------------|
//  | 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_view'
// and 'bsl::wstring_view' types.  The ud-suffix '_sv' is chosen to distinguish
// between the 'bsl'-string_view's user-defined literal operators and the
// 'std'-string_view's user-defined literal 'operator ""sv' introduced in the
// C++14 standard and implemented in the standard library provided by the
// compiler vendor.  Note that the 'bsl'-string_view's 'operator "" _sv',
// unlike the 'std'-string_view's 'operator ""sv', 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++17 standard then the 'std'-string_view's
// 'operator ""sv' can be used to initialize a 'bsl'-string_view as follows:
//..
//  using namespace std::string_view_literals;
//  bsl::string_view sv = "test"sv;
//..
//
// Also note that 'bsl'-string_view's user-defined literal operators are
// declared in the 'bsl::literals::string_view_literals' namespace, where
// 'literals' and 'string_view_literals' are inline namespaces.  Access to
// these operators can be gained with either 'using namespace bsl::literals',
// 'using namespace bsl::string_view_literals' or
// 'using namespace bsl::literals::string_view_literals'.  But we recommend
// 'using namespace bsl::string_view_literals' to minimize the scope of the
// using declaration:
//..
//  using namespace bsl::string_view_literals;
//  bsl::string_view svr = "test"_sv;
//..
//
///Usage
///-----
// In this section we show intended use of this component.
//
///Example 1: Basic Syntax
///- - - - - - - - - - - -
// The 'bsl::string_view' can be used as a lightweight replacement of the
// 'bsl::string', unless you need to modify the content.  It takes up no more
// space and doesn't allocate memory:
//..
//      bslma::TestAllocator         da("Default", veryVeryVeryVerbose);
//      bslma::DefaultAllocatorGuard dag(&da);
//
//      bslma::TestAllocator sfa ("StringFootprint",     veryVeryVeryVerbose);
//      bslma::TestAllocator svfa("StringViewFootprint", veryVeryVeryVerbose);
//      bslma::TestAllocator ssa ("StringSupplied",      veryVeryVeryVerbose);
//
//      const char *LONG_STRING = "0123456789012345678901234567890123456789"
//                                "0123456789012345678901234567890123456789";
//
//      bsl::string      *sPtr  = new (sfa ) bsl::string(LONG_STRING, &ssa);
//      bsl::string_view *svPtr = new (svfa) bsl::string_view(LONG_STRING);
//
//      assert(sfa.numBytesInUse() >= svfa.numBytesInUse());
//      assert(0                   <   ssa.numBytesInUse());
//      assert(0                   ==   da.numBytesInUse());
//..
// At the same time it supports all most used 'access' operations of the
// 'bsl::string', using the same interfaces:
//..
//      const bsl::string&      STR = *sPtr;
//      const bsl::string_view& SV  = *svPtr;
//
//      assert(STR.length()                == SV.length());
//      assert(STR.empty()                 == SV.empty());
//      assert(STR.front()                 == SV.front());
//      assert(STR.at(15)                  == SV.at(15));
//      assert(STR.find("345")             == SV.find("345"));
//      assert(STR.find_last_not_of("578") == SV.find_last_not_of("578"));
//      assert(STR.compare(0, 3, "012")    == SV.compare(0, 3, "012"));
//..
// However, using the 'bsl::string_view', you need to be especially attentive
// to the lifetime of the source character string, since the component
// explicitly refers to it:
//..
//      assert(LONG_STRING != STR.data());
//      assert(LONG_STRING == SV.data());
//
//      sfa.deleteObject(sPtr);
//      svfa.deleteObject(svPtr);
//..

#include <bslscm_version.h>

#include <bslstl_hash.h>
#include <bslstl_iterator.h>
#include <bslstl_stdexceptutil.h>

#include <bslalg_scalarprimitives.h>

#include <bslh_hash.h>

#include <bslmf_enableif.h>
#include <bslmf_isconvertible.h>
#include <bslmf_istriviallycopyable.h>
#include <bslmf_nestedtraitdeclaration.h>

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

#include <string>      // for 'std::char_traits'
#include <functional>  // for 'std::less', 'std::greater_equal'

#ifndef BDE_DONT_ALLOW_TRANSITIVE_INCLUDES
# include <bsls_nativestd.h>
#endif // BDE_DONT_ALLOW_TRANSITIVE_INCLUDES

// 'BDE_DISABLE_CPP17_ABI' is intended for CI builds only, to allow simulation
// of Sun/AIX builds on Linux hosts.  It is an error to define this symbol in
// Bloomberg production builds.
#ifndef BDE_DISABLE_CPP17_ABI
# ifdef BSLS_LIBRARYFEATURES_HAS_CPP17_BASELINE_LIBRARY

#   include <string_view>

namespace bsl {

using std::basic_string_view;
using std::string_view;
using std::wstring_view;

#   if defined(BSLS_COMPILERFEATURES_SUPPORT_UTF8_CHAR_TYPE)
using std::u8string_view;
#   endif

using std::u16string_view;
using std::u32string_view;

using std::swap;

using std::operator==;
using std::operator!=;
using std::operator<;
using std::operator<=;
using std::operator>;
using std::operator>=;

}
# define BSLSTL_STRING_VIEW_IS_ALIASED
# endif  // BSLS_LIBRARYFEATURES_HAS_CPP17_BASELINE_LIBRARY
#endif  // BDE_DISABLE_CPP17_ABI

#ifndef BSLSTL_STRING_VIEW_IS_ALIASED

#if defined(BSLS_PLATFORM_OS_WINDOWS) ||                                      \
   (defined(BSLS_PLATFORM_CMP_SUN) && BSLS_PLATFORM_CMP_VERSION <  0x5130) || \
   (defined(BSLS_PLATFORM_CMP_SUN) && BSLS_PLATFORM_CMP_VERSION == 0x5150)
  // Windows or Sun CC before version 5.12.4 or Sun CC version 5.12.6

# define BSLSTL_STRINGVIEW_IDENTITY_USE_WRAPPER    1
#else
# define BSLSTL_STRINGVIEW_IDENTITY_USE_WRAPPER    0
#endif

namespace BloombergLP {
namespace bslstl {

                         // ===========================
                         // struct 'StringView_Identity
                         // ===========================

template <class TYPE>
struct StringView_Identity {
#if BSLSTL_STRINGVIEW_IDENTITY_USE_WRAPPER
    // See 'Implementation Notes' in the implementation .cpp file.

    struct type {
        // DATA
        TYPE d_value;

        // CREATOR
        template <class ARG_TYPE>
        type(const ARG_TYPE& argument,
                     typename
                     bsl::enable_if<bsl::is_convertible<ARG_TYPE, TYPE>::value,
                                    int>::type = 0);
            // Initialize 'd_value' from the specified 'argument', of the
            // specified 'ARG_TYPE', where 'ARG_TYPE' can be any type that is
            // convertible to the specified 'TYPE'.

        // type(const type&) = default;

        // MANIPULATORS
        // type& operator=(const type&) = default;

        TYPE& operator=(const TYPE& rhs);
            // Assign the specified 'rhs' of type 'TYPE' to this object, and
            // return a reference providing modifiable access to the 'TYPE'
            // object held by this object.

        operator TYPE&();
            // Return a reference providing modifiable access to the 'TYPE'
            // object held by this object.

        // ACCESSOR
        operator const TYPE&() const;
            // Return a const reference to the 'TYPE' object held by this
            // object.
    };
#else
    typedef TYPE type;
#endif
};

}  // close package namespace
}  // close enterprise namespace

namespace bsl {
// Import 'char_traits' into the 'bsl' namespace so that 'basic_string_view'
// and 'char_traits' are always in the same namespace.

using std::char_traits;

                        // =======================
                        // class basic_string_view
                        // =======================

template <class CHAR_TYPE, class CHAR_TRAITS = char_traits<CHAR_TYPE> >
class basic_string_view {
    // This class template provides an STL-compliant 'string_view'.  This
    // implementation offers strong exception guarantees (see below), with the
    // general rule that any method that attempts to access a position outside
    // the valid range of a string_view throws 'std::out_of_range'.
    //
    // Note that the search methods, such as 'find', 'rfind', etc, do *not*
    // actually access invalid positions, so they do *not* throw exceptions.
    //
    // 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.

  public:
    // TYPES
    typedef CHAR_TRAITS                            traits_type;
    typedef CHAR_TYPE                              value_type;
    typedef value_type                            *pointer;
    typedef const value_type                      *const_pointer;
    typedef value_type&                            reference;
    typedef const value_type&                      const_reference;
    typedef const value_type                      *const_iterator;
    typedef const_iterator                         iterator;

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

    typedef std::size_t                            size_type;
    typedef std::ptrdiff_t                         difference_type;

    // 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()]'.

  private:
    // DATA
    const CHAR_TYPE *d_start_p;  // pointer to the data
    size_type        d_length;   // length of the view

    // 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'.

  public:
    // TRAITS
    BSLMF_NESTED_TRAIT_DECLARATION(basic_string_view,
                                   bsl::is_trivially_copyable);

    // CREATORS
    BSLS_KEYWORD_CONSTEXPR
    basic_string_view() BSLS_KEYWORD_NOEXCEPT;
        // Create an empty view.

    //! basic_string_view(const basic_string_view& original) = default;
        // Create a view that has the same value as the specified 'original'
        // object.

    BSLS_KEYWORD_CONSTEXPR_CPP14
    basic_string_view(const CHAR_TYPE *characterString);  // IMPLICIT
        // Create a view of the specified null-terminated 'characterString' (of
        // length 'CHAR_TRAITS::length(characterString)').

    BSLS_KEYWORD_CONSTEXPR_CPP14
    basic_string_view(const CHAR_TYPE *characterString,
                      size_type        numChars);
        // Create a view that has the same value as the subview of the
        // optionally specified 'numChars' length starting at the beginning of
        // the specified 'characterString'.  The behavior is undefined unless
        // 'characterString || (numChars == 0)' and 'numChars <= max_size()'.

    template <class ALLOCATOR>
    BSLS_KEYWORD_CONSTEXPR_CPP14
    basic_string_view(
              const std::basic_string<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>& str);
        // Create a view of the specified 'string'.

    //! ~basic_string_view() = default;
        // Destroy this object.

    // MANIPULATORS
    //! basic_string_view& operator=(const basic_string_view& rhs) = default;
        // Assign to this view the value of the specified 'rhs' object, and
        // return a reference providing modifiable access to this view.

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

    BSLS_KEYWORD_CONSTEXPR_CPP14
    void remove_prefix(size_type numChars);
        // Move the start of this view forward by the specified 'numChars'.
        // The behavior is undefined unless 'numChars <= length()'.

    BSLS_KEYWORD_CONSTEXPR_CPP14
    void remove_suffix(size_type numChars);
        // Move the end of this view back by the specified 'numChars'.  The
        // behavior is undefined unless 'numChars <= length()'.

    BSLS_KEYWORD_CONSTEXPR_CPP14
    void swap(basic_string_view& other) BSLS_KEYWORD_NOEXCEPT;
        // Exchange the value of this view with the value of the specified
        // 'other' object.

    // ACCESSORS

                      // *** iterator support ***

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

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

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

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

                      // *** capacity ***

    BSLS_KEYWORD_CONSTEXPR
    size_type size() const BSLS_KEYWORD_NOEXCEPT;
        // Return the length of this view.

    BSLS_KEYWORD_CONSTEXPR
    size_type length() const BSLS_KEYWORD_NOEXCEPT;
        // Return the length of this view.

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

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

                      // *** element access ***

    BSLS_KEYWORD_CONSTEXPR_CPP14
    const_reference operator[](size_type position) const;
        // Return a reference providing non-modifiable access to the character
        // at the specified 'position' in this view.  The behavior is undefined
        // unless 'position < length()'.

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

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

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

    BSLS_KEYWORD_CONSTEXPR
    const_pointer data() const BSLS_KEYWORD_NOEXCEPT;
        // Return an address providing non-modifiable access to the underlying
        // character array.  Note that this array may be not null-terminated.

                      // *** string operations ***

    size_type copy(CHAR_TYPE *characterString,
                   size_type  numChars,
                   size_type  position = 0) const;
        // Copy from this view, 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
        // 'std::out_of_range' if 'position > length()'.  Note that the output
        // 'characterString' is *not* null-terminated.  The behavior is
        // undefined unless 'characterString' has enough room to hold at least
        // 'numChars' or 'length() - position', whichever is smaller, and the
        // 'characterString' does not lie within the source range to be copied.

    BSLS_KEYWORD_CONSTEXPR_CPP14
    basic_string_view substr(size_type position = 0,
                             size_type numChars = npos) const;
        // Return a view whose value is the subview starting at the optionally
        // specified 'position' in this view, of length the optionally
        // specified 'numChars' or 'length() - position', whichever is smaller.
        // If 'position' is not specified, 0 is used (i.e., the subview is from
        // the beginning of this view).  If 'numChars' is not specified, 'npos'
        // is used (i.e., the entire suffix from 'position' to the end of the
        // view is returned).  Throw 'std::out_of_range' if
        // 'position > length()'.

    BSLS_KEYWORD_CONSTEXPR
    int compare(basic_string_view other) const BSLS_KEYWORD_NOEXCEPT;
        // Lexicographically compare this view with the specified 'other' view,
        // and return a negative value if this view is less than 'other', a
        // positive value if it is greater than 'other', and 0 in case of
        // equality.  See {Lexicographical Comparisons}.

    BSLS_KEYWORD_CONSTEXPR_CPP14
    int compare(size_type         position,
                size_type         numChars,
                basic_string_view other) const;
        // Lexicographically compare the subview of this view of the specified
        // 'numChars' length starting at the specified 'position' (or the
        // suffix of this view starting at 'position' if
        // 'position + numChars > length()') with the specified 'other' view,
        // and return a negative value if the indicated subview of this view is
        // less than 'other', a positive value if it is greater than 'other',
        // and 0 in case of equality.  Throw 'std::out_of_range' if
        // 'position > length()'.  See {Lexicographical Comparisons}.

    BSLS_KEYWORD_CONSTEXPR_CPP14
    int compare(size_type         lhsPosition,
                size_type         lhsNumChars,
                basic_string_view other,
                size_type         otherPosition,
                size_type         otherNumChars) const;
        // Lexicographically compare the subview of this view of the specified
        // 'lhsNumChars' length starting at the specified 'lhsPosition' (or the
        // suffix of this view starting at 'lhsPosition' if
        // 'lhsPosition + lhsNumChars > length()') with the subview of the
        // specified 'other' view of the specified 'otherNumChars' length
        // starting at the specified 'otherPosition' (or the suffix of 'other'
        // starting at 'otherPosition' if
        // 'otherPosition + otherNumChars > other.length()').  Return a
        // negative value if the indicated subview of this view is less than
        // the indicated subview of 'other', a positive value if it is greater
        // than the indicated subview of 'other', and 0 in case of equality.
        // Throw 'std::out_of_range' if 'lhsPosition > length()' or
        // 'otherPosition > other.length()'.  See
        // {Lexicographical Comparisons}.

    BSLS_KEYWORD_CONSTEXPR_CPP14
    int compare(const CHAR_TYPE *other) const;
        // Lexicographically compare this view with the specified
        // null-terminated 'other' string (of length
        // 'CHAR_TRAITS::length(other)'), and return a negative value if this
        // view is less than 'other', a positive value if it is greater than
        // 'other', and 0 in case of equality.  The behavior is undefined
        // unless 'other' is a null-terminated string.

    BSLS_KEYWORD_CONSTEXPR_CPP14
    int compare(size_type        lhsPosition,
                size_type        lhsNumChars,
                const CHAR_TYPE *other) const;
        // Lexicographically compare the subview of this view of the specified
        // 'lhsNumChars' length starting at the specified 'lhsPosition' (or the
        // suffix of this view 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 subview of this view is less than 'other', a positive
        // value if it is greater than 'other', and 0 in case of equality.
        // Throw 'std::out_of_range' if 'lhsPosition > length()'.

    BSLS_KEYWORD_CONSTEXPR_CPP14
    int compare(size_type        lhsPosition,
                size_type        lhsNumChars,
                const CHAR_TYPE *other,
                size_type        otherNumChars) const;
        // Lexicographically compare the subview of this view of the specified
        // 'lhsNumChars' length starting at the specified 'lhsPosition' (or the
        // suffix of this view 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 subview of this view 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 'std::out_of_range' if 'lhsPosition > length()'.  The behavior
        // is undefined unless 'other || 0 == otherNumChars'.

#if defined(BSLSTL_STRINGVIEW_ENABLE_CPP20_METHODS)
    BSLS_KEYWORD_CONSTEXPR_CPP14
    bool starts_with(basic_string_view subview) const BSLS_KEYWORD_NOEXCEPT;
        // Return 'true' if this view starts with the specified 'subview', and
        // 'false' otherwise.

    BSLS_KEYWORD_CONSTEXPR
    bool starts_with(CHAR_TYPE character) const BSLS_KEYWORD_NOEXCEPT;
        // Return 'true' if this view starts with the specified 'character',
        // and 'false' otherwise.

    BSLS_KEYWORD_CONSTEXPR_CPP14
    bool starts_with(const CHAR_TYPE* characterString) const;
        // Return 'true' if this view starts with the specified
        // 'characterString', and 'false' otherwise.

    BSLS_KEYWORD_CONSTEXPR_CPP14
    bool ends_with(basic_string_view subview) const BSLS_KEYWORD_NOEXCEPT;
        // Return 'true' if this view ends with the specified 'subview', and
        // 'false' otherwise.

    BSLS_KEYWORD_CONSTEXPR
    bool ends_with(CHAR_TYPE character) const BSLS_KEYWORD_NOEXCEPT;
        // Return 'true' if this view ends with the specified 'character', and
        // 'false' otherwise.

    BSLS_KEYWORD_CONSTEXPR_CPP14
    bool ends_with(const CHAR_TYPE* characterString) const;
        // Return 'true' if this view ends with the specified
        // 'characterString', and 'false' otherwise.
#endif

    BSLS_KEYWORD_CONSTEXPR_CPP14
    size_type find(basic_string_view subview,
                   size_type         position = 0) const BSLS_KEYWORD_NOEXCEPT;
        // Return the starting position of the *first* occurrence of the
        // specified 'subview', if it can be found in this view (on or *after*
        // the optionally specified 'position') using 'CHAR_TRAITS::eq' to
        // compare characters, and return 'npos' otherwise.

    BSLS_KEYWORD_CONSTEXPR_CPP14
    size_type find(const CHAR_TYPE *characterString,
                   size_type        position,
                   size_type        numChars) const;
        // Return the starting position of the *first* occurrence of the
        // specified 'characterString' of the specified 'numChars' length, if
        // such a string can be found in this view (on or *after* the specified
        // 'position') using 'CHAR_TRAITS::eq' to compare characters, and
        // return 'npos' otherwise.  The behavior is undefined unless
        // 'characterString || (numChars == 0)'.

    BSLS_KEYWORD_CONSTEXPR_CPP14
    size_type find(const CHAR_TYPE *characterString,
                   size_type        position = 0) const;
        // Return the starting position of the *first* occurrence of the
        // specified null-terminated 'characterString', if such a string can be
        // found in this view (on or *after* the optionally specified
        // 'position') using 'CHAR_TRAITS::eq' to compare characters, and
        // return 'npos' otherwise.

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

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

    BSLS_KEYWORD_CONSTEXPR_CPP14
    size_type rfind(const CHAR_TYPE *characterString,
                    size_type        position,
                    size_type        numChars) const;
        // Return the starting position of the *last* occurrence of the
        // specified 'characterString' of the specified 'numChars' length, if
        // such a string can be found in this view (on or *after* the specified
        // 'position') using 'CHAR_TRAITS::eq' to compare characters, and
        // return 'npos' otherwise.  The behavior is undefined unless
        // 'characterString || (numChars == 0)'.

    BSLS_KEYWORD_CONSTEXPR_CPP14
    size_type rfind(const CHAR_TYPE *characterString,
                    size_type        position = npos) const;
        // Return the starting position of the *last* occurrence of the
        // specified null-terminated 'characterString', if such a string can be
        // found in this view (on or *after* the optionally specified
        // 'position') using 'CHAR_TRAITS::eq' to compare characters, and
        // return 'npos' otherwise.

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

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

    BSLS_KEYWORD_CONSTEXPR_CPP14
    size_type find_first_of(const CHAR_TYPE *characterString,
                            size_type        position,
                            size_type        numChars) const;
        // Return the position of the *first* occurrence of a character
        // belonging to the specified 'characterString' of the specified
        // 'numChars' length, if such a string can be found in this view (on or
        // *after* the specified 'position') using 'CHAR_TRAITS::eq' to compare
        // characters, and return 'npos' otherwise.  The behavior is undefined
        // unless 'characterString || (numChars == 0)'.

    BSLS_KEYWORD_CONSTEXPR_CPP14
    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', if such an occurrence
        // can be found in this view (on or *after* the optionally specified
        // 'position'), and return 'npos' otherwise.

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

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

    BSLS_KEYWORD_CONSTEXPR_CPP14
    size_type find_last_of(const CHAR_TYPE *characterString,
                           size_type        position,
                           size_type        numChars) const;
        // Return the position of the *last* occurrence of a character
        // belonging to the specified 'characterString' of the specified
        // 'numChars' length, if such a string can be found in this view (on or
        // *after* the specified 'position') using 'CHAR_TRAITS::eq' to compare
        // characters, and return 'npos' otherwise.  The behavior is undefined
        // unless 'characterString || (numChars == 0)'.

    BSLS_KEYWORD_CONSTEXPR_CPP14
    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', if such an occurrence
        // can be found in this view (on or *after* the optionally specified
        // 'position'), and return 'npos' otherwise.

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

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

    BSLS_KEYWORD_CONSTEXPR_CPP14
    size_type find_first_not_of(const CHAR_TYPE *characterString,
                                size_type        position,
                                size_type        numChars) const;
        // Return the position of the *first* occurrence of a character *not*
        // belonging to the specified 'characterString' of the specified
        // 'numChars' length, if such an occurrence can be found in this view
        // (on or *after* the specified 'position') using 'CHAR_TRAITS::eq' to
        // compare characters, and return 'npos' otherwise.  The behavior is
        // undefined unless 'characterString || (numChars == 0)'.

    BSLS_KEYWORD_CONSTEXPR_CPP14
    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', if such an occurrence
        // can be found in this view (on or *after* the optionally specified
        // 'position'), and return 'npos' otherwise.

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

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

    BSLS_KEYWORD_CONSTEXPR_CPP14
    size_type find_last_not_of(const CHAR_TYPE *characterString,
                               size_type        position,
                               size_type        numChars) const;
        // Return the position of the *last* occurrence of a character *not*
        // belonging to the specified 'characterString' of the specified
        // 'numChars' length, if such an occurrence can be found in this view
        // (on or *after* the specified 'position') using 'CHAR_TRAITS::eq' to
        // compare characters, and return 'npos' otherwise.  The behavior is
        // undefined unless 'characterString || (numChars == 0)'.

    BSLS_KEYWORD_CONSTEXPR_CPP14
    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', if such an occurrence
        // can be found in this view (on or *after* the optionally specified
        // 'position'), and return 'npos' otherwise.

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

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

    template <class ALLOCATOR>
    BSLS_KEYWORD_EXPLICIT
    operator std::basic_string<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>()
    const
        // Convert this object to a string type native to the compiler's
        // library, instantiated with the same character type and traits type.
        // The return string will contain the same sequence of characters as
        // this object and will have a default-constructed allocator.
    {
        // See {DRQS 131792157} for why this is inline.
        return std::basic_string<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>(
            d_start_p, d_length);
    }
};

// TYPEDEFS
typedef basic_string_view<char>         string_view;
typedef basic_string_view<wchar_t>     wstring_view;

#if defined(BSLS_COMPILERFEATURES_SUPPORT_UTF8_CHAR_TYPE)
typedef basic_string_view<char8_t>    u8string_view;
#endif

#if defined(BSLS_COMPILERFEATURES_SUPPORT_UNICODE_CHAR_TYPES)
typedef basic_string_view<char16_t>  u16string_view;
typedef basic_string_view<char32_t>  u32string_view;
#endif

// FREE FUNCTIONS
template <class CHAR_TYPE, class CHAR_TRAITS>
BSLS_KEYWORD_CONSTEXPR_CPP14
void swap(basic_string_view<CHAR_TYPE, CHAR_TRAITS>& a,
          basic_string_view<CHAR_TYPE, CHAR_TRAITS>& b) BSLS_KEYWORD_NOEXCEPT;
    // Exchange the value of the specified 'a' object with the value of the
    // specified 'b' object.

}  // close namespace bsl

namespace BloombergLP {
namespace bslstl_stringview_relops {

                    // =============================
                    // struct StringView_CompareUtil
                    // =============================

template <class CHAR_TYPE, class CHAR_TRAITS>
struct StringView_CompareUtil {
    // This component-private utility 'struct' contains functions for comparing
    // two 'string_view' objects.  This functionality is needed to implement
    // the comparison operators operating on string_view objects without
    // resorting to code duplication or delegating directly between different
    // overloads of the same operator.  The need to avoid delegation to
    // overloads stems from a bug in xlC 12 on AIX leading to incorrect
    // overload resolution and infinite recursion.

    typedef bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS> StringView;

    static
    BSLS_KEYWORD_CONSTEXPR
    bool equals(StringView lhs, StringView rhs) BSLS_KEYWORD_NOEXCEPT;
        // Return 'true' if 'lhs == rhs' and 'false' otherwise.

    static
    BSLS_KEYWORD_CONSTEXPR_CPP14
    bool lessThan(StringView lhs, StringView rhs) BSLS_KEYWORD_NOEXCEPT;
        // Return 'true' if 'lhs < rhs' and 'false' otherwise.
};

// FREE OPERATORS
template <class CHAR_TYPE, class CHAR_TRAITS>
BSLS_KEYWORD_CONSTEXPR
bool operator==(bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS>             lhs,
                bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS>             rhs)
BSLS_KEYWORD_NOEXCEPT;
template <class CHAR_TYPE, class CHAR_TRAITS>
BSLS_KEYWORD_CONSTEXPR
bool operator==(
           typename BloombergLP::bslstl::StringView_Identity<
                    bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS> >::type lhs,
           const bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS>            rhs)
BSLS_KEYWORD_NOEXCEPT;
template <class CHAR_TYPE, class CHAR_TRAITS>
BSLS_KEYWORD_CONSTEXPR
bool operator==(
           const bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS>            lhs,
           typename BloombergLP::bslstl::StringView_Identity<
                    bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS> >::type rhs)
BSLS_KEYWORD_NOEXCEPT;
    // Return 'true' if the specified 'lhs' view has the same value as the
    // specified 'rhs' view, and 'false' otherwise.  Two views 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>
BSLS_KEYWORD_CONSTEXPR
bool operator!=(bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS>             lhs,
                bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS>             rhs)
BSLS_KEYWORD_NOEXCEPT;
template <class CHAR_TYPE, class CHAR_TRAITS>
BSLS_KEYWORD_CONSTEXPR
bool operator!=(
           typename BloombergLP::bslstl::StringView_Identity<
                    bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS> >::type lhs,
           const bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS>            rhs)
BSLS_KEYWORD_NOEXCEPT;
template <class CHAR_TYPE, class CHAR_TRAITS>
BSLS_KEYWORD_CONSTEXPR
bool operator!=(
           const bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS>            lhs,
           typename BloombergLP::bslstl::StringView_Identity<
                    bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS> >::type rhs)
BSLS_KEYWORD_NOEXCEPT;
    // Return 'true' if the specified 'lhs' view has a different value from the
    // specified 'rhs' view, and 'false' otherwise.  Two views 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>
BSLS_KEYWORD_CONSTEXPR_CPP14
bool operator<(bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS>              lhs,
               bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS>              rhs)
BSLS_KEYWORD_NOEXCEPT;
template <class CHAR_TYPE, class CHAR_TRAITS>
BSLS_KEYWORD_CONSTEXPR
bool operator<(
           typename BloombergLP::bslstl::StringView_Identity<
                    bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS> >::type lhs,
           const bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS>            rhs)
BSLS_KEYWORD_NOEXCEPT;
template <class CHAR_TYPE, class CHAR_TRAITS>
BSLS_KEYWORD_CONSTEXPR
bool operator<(
           const bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS>            lhs,
           typename BloombergLP::bslstl::StringView_Identity<
                    bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS> >::type rhs)
BSLS_KEYWORD_NOEXCEPT;
    // Return 'true' if the specified 'lhs' view has a lexicographically
    // smaller value than the specified 'rhs' view, and 'false' otherwise.  See
    // {Lexicographical Comparisons}.

template <class CHAR_TYPE, class CHAR_TRAITS>
BSLS_KEYWORD_CONSTEXPR
bool operator>(bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS>              lhs,
               bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS>              rhs)
BSLS_KEYWORD_NOEXCEPT;
template <class CHAR_TYPE, class CHAR_TRAITS>
BSLS_KEYWORD_CONSTEXPR
bool operator>(
           typename BloombergLP::bslstl::StringView_Identity<
                    bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS> >::type lhs,
           const bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS>            rhs)
BSLS_KEYWORD_NOEXCEPT;
template <class CHAR_TYPE, class CHAR_TRAITS>
BSLS_KEYWORD_CONSTEXPR
bool operator>(
           const bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS>            lhs,
           typename BloombergLP::bslstl::StringView_Identity<
                    bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS> >::type rhs)
BSLS_KEYWORD_NOEXCEPT;
    // Return 'true' if the specified 'lhs' view has a lexicographically larger
    // value than the specified 'rhs' view, and 'false' otherwise.  See
    // {Lexicographical Comparisons}.

template <class CHAR_TYPE, class CHAR_TRAITS>
BSLS_KEYWORD_CONSTEXPR
bool operator<=(bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS>             lhs,
                bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS>             rhs)
BSLS_KEYWORD_NOEXCEPT;
template <class CHAR_TYPE, class CHAR_TRAITS>
BSLS_KEYWORD_CONSTEXPR
bool operator<=(
           typename BloombergLP::bslstl::StringView_Identity<
                    bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS> >::type lhs,
           const bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS>            rhs)
BSLS_KEYWORD_NOEXCEPT;
template <class CHAR_TYPE, class CHAR_TRAITS>
BSLS_KEYWORD_CONSTEXPR
bool operator<=(
           const bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS>            lhs,
           typename BloombergLP::bslstl::StringView_Identity<
                    bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS> >::type rhs)
BSLS_KEYWORD_NOEXCEPT;
    // Return 'true' if the specified 'lhs' view has a value lexicographically
    // smaller than or or equal to the specified 'rhs' view, and 'false'
    // otherwise.  See {Lexicographical Comparisons}.

template <class CHAR_TYPE, class CHAR_TRAITS>
BSLS_KEYWORD_CONSTEXPR
bool operator>=(bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS>             lhs,
                bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS>             rhs)
BSLS_KEYWORD_NOEXCEPT;
template <class CHAR_TYPE, class CHAR_TRAITS>
BSLS_KEYWORD_CONSTEXPR
bool operator>=(
           typename BloombergLP::bslstl::StringView_Identity<
                    bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS> >::type lhs,
           const bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS>            rhs)
BSLS_KEYWORD_NOEXCEPT;
template <class CHAR_TYPE, class CHAR_TRAITS>
BSLS_KEYWORD_CONSTEXPR
bool operator>=(
           const bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS>            lhs,
           typename BloombergLP::bslstl::StringView_Identity<
                    bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS> >::type rhs)
BSLS_KEYWORD_NOEXCEPT;
    // Return 'true' if the specified 'lhs' view has a value lexicographically
    // larger than or equal to the specified 'rhs' view, and 'false' otherwise.
    // See {Lexicographical Comparisons}.

}  // close namespace bslstl_stringview_relops
}  // close namespace BloombergLP

namespace bsl {

template <class CHAR_TYPE, class CHAR_TRAITS>
std::basic_ostream<CHAR_TYPE>&
operator<<(std::basic_ostream<CHAR_TYPE>&            stream,
           basic_string_view<CHAR_TYPE, CHAR_TRAITS> stringView);
    // Write the value of the string bound to the specified 'stringView' to the
    // specified output 'stream' and return a reference to the modifiable
    // 'stream'.

// HASH SPECIALIZATIONS
template <class HASHALG, class CHAR_TYPE, class CHAR_TRAITS>
void hashAppend(HASHALG&                                         hashAlg,
                const basic_string_view<CHAR_TYPE, CHAR_TRAITS>& 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>
struct hash<basic_string_view<CHAR_TYPE, CHAR_TRAITS> >
    : ::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_view<CHAR_TYPE, CHAR_TRAITS>& 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_view' constructed from 'input'.
};

#if defined(BSLS_PLATFORM_CMP_SUN)  // {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_view' and 'wstring_view' makes the problematic cases work.

template <>
struct hash<string_view> : ::BloombergLP::bslh::Hash<>
{
    // PUBLIC ACCESSORS
    std::size_t operator()(const string_view& 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_view' constructed from 'input'.
};

template <>
struct hash<wstring_view> : ::BloombergLP::bslh::Hash<>
{
    // PUBLIC ACCESSORS
    std::size_t operator()(const wstring_view& 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_view' constructed from 'input'.
};

#endif  // defined(BSLS_PLATFORM_CMP_SUN)

}  // close namespace bsl

#endif  // BSLSTL_STRING_VIEW_IS_ALIASED


#if defined (BSLS_LIBRARYFEATURES_HAS_CPP11_BASELINE_LIBRARY) && \
    defined (BSLS_COMPILERFEATURES_SUPPORT_INLINE_NAMESPACE)
namespace bsl {
inline namespace literals {
inline namespace string_view_literals {
 string_view operator ""_sv(const char    *characterString,
                            std::size_t    length);
wstring_view operator ""_sv(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_view object of the indicated return type.
    // (See the "User-Defined Literals" section in the component-level
    // documentation.)
    //
    // Example:
    //..
    //     using namespace bsl::string_view_literals;
    //     bsl::string_view sv1 = "123\0abc";
    //     bsl::string_view sv2 = "123\0abc"_sv;
    //     assert(3 == sv1.size());
    //     assert(7 == sv2.size());
    //
    //     bsl::wstring_view sv3 = L"123\0abc"_sv;
    //     assert(7 == sv3.size());
    //..

}  // close namespace string_view_literals
}  // close namespace literals
}  // close namespace bsl
#endif  // BSLS_LIBRARYFEATURES_HAS_CPP11_BASELINE_LIBRARY &&
        // BSLS_COMPILERFEATURES_SUPPORT_INLINE_NAMESPACE

#ifdef BSLSTL_STRING_VIEW_IS_ALIASED
namespace BloombergLP {
namespace bslh {

template <class HASHALG, class CHAR_TYPE, class CHAR_TRAITS>
BSLS_PLATFORM_AGGRESSIVE_INLINE
void hashAppend(HASHALG&                                              hashAlg,
                const std::basic_string_view<CHAR_TYPE, CHAR_TRAITS>& 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_view' 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
#endif  // BSLSTL_STRING_VIEW_IS_ALIASED

// ============================================================================
//                      INLINE FUNCTION DEFINITIONS
// ============================================================================



#ifndef BSLSTL_STRING_VIEW_IS_ALIASED

#if BSLSTL_STRINGVIEW_IDENTITY_USE_WRAPPER

namespace BloombergLP {
namespace bslstl {

template <class TYPE>
template <class ARG_TYPE>
inline
StringView_Identity<TYPE>::type::type(
            const ARG_TYPE& argument,
            typename bsl::enable_if<bsl::is_convertible<ARG_TYPE, TYPE>::value,
                                    int>::type)
: d_value(argument)
{}

// MANIPULATORS
template <class TYPE>
inline
TYPE& StringView_Identity<TYPE>::type::operator=(const TYPE& rhs)
{
    d_value = rhs;

    return d_value;
}

template <class TYPE>
inline
StringView_Identity<TYPE>::type::operator TYPE&()
{
    return d_value;
}

// ACCESSOR
template <class TYPE>
inline
StringView_Identity<TYPE>::type::operator const TYPE&() const
{
    return d_value;
}

}  // close package namespace
}  // close enterprise namespace

#endif

namespace bsl {

                          // -----------------------
                          // class basic_string_view
                          // -----------------------

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

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

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

// CREATORS
template <class CHAR_TYPE, class CHAR_TRAITS>
inline
BSLS_KEYWORD_CONSTEXPR
basic_string_view<CHAR_TYPE,CHAR_TRAITS>::basic_string_view()
                                                          BSLS_KEYWORD_NOEXCEPT
: d_start_p(0)
, d_length(0)
{}

template <class CHAR_TYPE, class CHAR_TRAITS>
BSLS_PLATFORM_AGGRESSIVE_INLINE
BSLS_KEYWORD_CONSTEXPR_CPP14
basic_string_view<CHAR_TYPE, CHAR_TRAITS>::basic_string_view(
                                              const CHAR_TYPE *characterString)
{
    BSLS_ASSERT_SAFE(characterString);

    d_start_p = characterString;
    d_length  = CHAR_TRAITS::length(characterString);

    BSLS_ASSERT_SAFE(d_length <= max_size());
}

template <class CHAR_TYPE, class CHAR_TRAITS>
BSLS_PLATFORM_AGGRESSIVE_INLINE
BSLS_KEYWORD_CONSTEXPR_CPP14
basic_string_view<CHAR_TYPE, CHAR_TRAITS>::basic_string_view(
                                             const CHAR_TYPE  *characterString,
                                             size_type         numChars)
{
    BSLS_ASSERT_SAFE(characterString || (numChars == 0));
    BSLS_ASSERT_SAFE(numChars <= max_size());

    d_start_p = characterString;
    d_length  = numChars;
}

template <class CHAR_TYPE, class CHAR_TRAITS>
template <class ALLOCATOR>
BSLS_PLATFORM_AGGRESSIVE_INLINE
BSLS_KEYWORD_CONSTEXPR_CPP14
basic_string_view<CHAR_TYPE, CHAR_TRAITS>::basic_string_view(
               const std::basic_string<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>& str)
{
    d_start_p = str.data();
    d_length  = str.size();
}

// MANIPULATORS
template <class CHAR_TYPE, class CHAR_TRAITS>
template <class ALLOCATOR>
BSLS_PLATFORM_AGGRESSIVE_INLINE
BSLS_KEYWORD_CONSTEXPR_CPP14
basic_string_view<CHAR_TYPE, CHAR_TRAITS>&
basic_string_view<CHAR_TYPE, CHAR_TRAITS>::operator=(
               const std::basic_string<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>& rhs)
BSLS_KEYWORD_NOEXCEPT
{
    d_start_p = rhs.data();
    d_length  = rhs.size();
    return *this;
}

template <class CHAR_TYPE, class CHAR_TRAITS>
BSLS_KEYWORD_CONSTEXPR_CPP14
void
basic_string_view<CHAR_TYPE, CHAR_TRAITS>::remove_prefix(size_type numChars)
{
    BSLS_ASSERT_SAFE(d_length >= numChars);
    d_start_p += numChars;
    d_length  -= numChars;
}

template <class CHAR_TYPE, class CHAR_TRAITS>
BSLS_KEYWORD_CONSTEXPR_CPP14
void
basic_string_view<CHAR_TYPE, CHAR_TRAITS>::remove_suffix(size_type numChars)
{
    BSLS_ASSERT_SAFE(d_length >= numChars);
    d_length -= numChars;
}

template <class CHAR_TYPE, class CHAR_TRAITS>
BSLS_KEYWORD_CONSTEXPR_CPP14
void
basic_string_view<CHAR_TYPE, CHAR_TRAITS>::swap(
                                basic_string_view& other) BSLS_KEYWORD_NOEXCEPT
{
    BloombergLP::bslalg::ScalarPrimitives::swap(d_length,  other.d_length);
    BloombergLP::bslalg::ScalarPrimitives::swap(d_start_p, other.d_start_p);
}

// ACCESSORS
template <class CHAR_TYPE, class CHAR_TRAITS>
inline
BSLS_KEYWORD_CONSTEXPR
typename basic_string_view<CHAR_TYPE, CHAR_TRAITS>::const_iterator
basic_string_view<CHAR_TYPE, CHAR_TRAITS>::begin() const BSLS_KEYWORD_NOEXCEPT
{
    return d_start_p;
}

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

template <class CHAR_TYPE, class CHAR_TRAITS>
inline
BSLS_KEYWORD_CONSTEXPR
typename basic_string_view<CHAR_TYPE, CHAR_TRAITS>::const_iterator
basic_string_view<CHAR_TYPE, CHAR_TRAITS>::end() const
                                                          BSLS_KEYWORD_NOEXCEPT
{
    return begin() + d_length;
}

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

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

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

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

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

template <class CHAR_TYPE, class CHAR_TRAITS>
inline
BSLS_KEYWORD_CONSTEXPR
typename basic_string_view<CHAR_TYPE, CHAR_TRAITS>::size_type
basic_string_view<CHAR_TYPE, CHAR_TRAITS>::size() const BSLS_KEYWORD_NOEXCEPT
{
    return d_length;
}

template <class CHAR_TYPE, class CHAR_TRAITS>
inline
BSLS_KEYWORD_CONSTEXPR
typename basic_string_view<CHAR_TYPE, CHAR_TRAITS>::size_type
basic_string_view<CHAR_TYPE, CHAR_TRAITS>::length() const BSLS_KEYWORD_NOEXCEPT
{
    return d_length;
}

template <class CHAR_TYPE, class CHAR_TRAITS>
inline
BSLS_KEYWORD_CONSTEXPR
typename basic_string_view<CHAR_TYPE, CHAR_TRAITS>::size_type
basic_string_view<CHAR_TYPE, CHAR_TRAITS>::max_size() const
                                                          BSLS_KEYWORD_NOEXCEPT
{
    return (npos - 1) / sizeof(CHAR_TYPE);
}

template <class CHAR_TYPE, class CHAR_TRAITS>
inline
BSLS_KEYWORD_CONSTEXPR
bool basic_string_view<CHAR_TYPE, CHAR_TRAITS>::empty() const
                                                          BSLS_KEYWORD_NOEXCEPT
{
    return (0 == d_length);
}

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

    return *(begin() + position);
}

template <class CHAR_TYPE, class CHAR_TRAITS>
BSLS_PLATFORM_AGGRESSIVE_INLINE
BSLS_KEYWORD_CONSTEXPR_CPP14
typename basic_string_view<CHAR_TYPE, CHAR_TRAITS>::const_reference
basic_string_view<CHAR_TYPE, CHAR_TRAITS>::at(size_type position) const
{
    if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(position >= length())) {
        BSLS_PERFORMANCEHINT_UNLIKELY_HINT;
        BloombergLP::bslstl::StdExceptUtil::throwOutOfRange(
                                       "string_view::at(n): invalid position");
    }
    return *(begin() + position);
}

template <class CHAR_TYPE, class CHAR_TRAITS>
inline
BSLS_KEYWORD_CONSTEXPR_CPP14
typename basic_string_view<CHAR_TYPE, CHAR_TRAITS>::const_reference
basic_string_view<CHAR_TYPE, CHAR_TRAITS>::front() const
{
    BSLS_ASSERT_SAFE(!empty());

    return *begin();
}

template <class CHAR_TYPE, class CHAR_TRAITS>
inline
BSLS_KEYWORD_CONSTEXPR_CPP14
typename basic_string_view<CHAR_TYPE, CHAR_TRAITS>::const_reference
basic_string_view<CHAR_TYPE, CHAR_TRAITS>::back() const
{
    BSLS_ASSERT_SAFE(!empty());

    return *(end() - 1);
}

template <class CHAR_TYPE, class CHAR_TRAITS>
inline
BSLS_KEYWORD_CONSTEXPR
typename basic_string_view<CHAR_TYPE, CHAR_TRAITS>::const_pointer
basic_string_view<CHAR_TYPE, CHAR_TRAITS>::data() const BSLS_KEYWORD_NOEXCEPT
{
    return d_start_p;
}

template <class CHAR_TYPE, class CHAR_TRAITS>
typename basic_string_view<CHAR_TYPE, CHAR_TRAITS>::size_type
basic_string_view<CHAR_TYPE, CHAR_TRAITS>::copy(CHAR_TYPE *characterString,
                                                size_type  numChars,
                                                size_type  position) const
{

    if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(position > length())) {
        BSLS_PERFORMANCEHINT_UNLIKELY_HINT;
        BloombergLP::bslstl::StdExceptUtil::throwOutOfRange(
                             "string_view::copy(str,pos,n): invalid position");
    }

    BSLS_ASSERT_SAFE(characterString);

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

    // Check that the destination buffer start is not within the source.
    BSLS_ASSERT_SAFE(std::less<const CHAR_TYPE *>()(
                         characterString, d_start_p + position) ||
                     std::greater_equal<const CHAR_TYPE *>()(
                         characterString, d_start_p + position + numChars));

    CHAR_TRAITS::move(characterString, d_start_p + position, numChars);

    return numChars;
}

template <class CHAR_TYPE, class CHAR_TRAITS>
BSLS_PLATFORM_AGGRESSIVE_INLINE
BSLS_KEYWORD_CONSTEXPR_CPP14
basic_string_view<CHAR_TYPE, CHAR_TRAITS>
basic_string_view<CHAR_TYPE, CHAR_TRAITS>::substr(size_type position,
                                                  size_type numChars) const
{
    if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(position > length())) {
        BSLS_PERFORMANCEHINT_UNLIKELY_HINT;
        BloombergLP::bslstl::StdExceptUtil::throwOutOfRange(
                               "string_view::substr(pos,n): invalid position");
    }

    const size_type maxLen = length() - position;

    return basic_string_view<CHAR_TYPE, CHAR_TRAITS>(
                                        data() + position,
                                        numChars < maxLen ? numChars : maxLen);
}

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

template <class CHAR_TYPE, class CHAR_TRAITS>
BSLS_PLATFORM_AGGRESSIVE_INLINE
BSLS_KEYWORD_CONSTEXPR_CPP14
int basic_string_view<CHAR_TYPE, CHAR_TRAITS>::compare(
                                                 size_type         position,
                                                 size_type         numChars,
                                                 basic_string_view other) const
{
    if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(length() < position)) {
        BSLS_PERFORMANCEHINT_UNLIKELY_HINT;
        BloombergLP::bslstl::StdExceptUtil::throwOutOfRange(
            "const string_view<...>::compare(pos,n, other): invalid position");
    }

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

template <class CHAR_TYPE, class CHAR_TRAITS>
BSLS_PLATFORM_AGGRESSIVE_INLINE
BSLS_KEYWORD_CONSTEXPR_CPP14
int basic_string_view<CHAR_TYPE, CHAR_TRAITS>::compare(
                                         size_type         lhsPosition,
                                         size_type         lhsNumChars,
                                         basic_string_view other,
                                         size_type         otherPosition,
                                         size_type         otherNumChars) const
{
    if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(length() < lhsPosition)) {
        BSLS_PERFORMANCEHINT_UNLIKELY_HINT;
        BloombergLP::bslstl::StdExceptUtil::throwOutOfRange(
               "const string_view<...>::compare(pos,n,other,other_pos,other_n)"
               ": invalid lhs position");
    }

    if (lhsNumChars > length() - lhsPosition) {
        lhsNumChars = length() - lhsPosition;
    }

    if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(
                                             other.length() < otherPosition)) {
        BSLS_PERFORMANCEHINT_UNLIKELY_HINT;
        BloombergLP::bslstl::StdExceptUtil::throwOutOfRange(
               "const string_view<...>::compare(pos,n,other,other_pos,other_n)"
               ": invalid rhs position");
    }

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

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

    size_type otherLength = CHAR_TRAITS::length(other);

    return privateCompareRaw(size_type(0),
                             length(),
                             other,
                             otherLength);
}

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

    if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(length() < lhsPosition)) {
        BSLS_PERFORMANCEHINT_UNLIKELY_HINT;
        BloombergLP::bslstl::StdExceptUtil::throwOutOfRange(
             "const string_view<...>::compare(pos,n,other): invalid position");
    }

    size_type otherLength = CHAR_TRAITS::length(other);

    if (lhsNumChars > length() - lhsPosition) {
        lhsNumChars = length() - lhsPosition;
    }

    return compare(lhsPosition,
                   lhsNumChars,
                   other,
                   otherLength);
}

template <class CHAR_TYPE, class CHAR_TRAITS>
BSLS_PLATFORM_AGGRESSIVE_INLINE
BSLS_KEYWORD_CONSTEXPR_CPP14
int basic_string_view<CHAR_TYPE, CHAR_TRAITS>::compare(
                                          size_type        lhsPosition,
                                          size_type        lhsNumChars,
                                          const CHAR_TYPE *other,
                                          size_type        otherNumChars) const
{
    BSLS_ASSERT_SAFE(other || 0 == otherNumChars);

    if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(length() < lhsPosition)) {
        BSLS_PERFORMANCEHINT_UNLIKELY_HINT;
        BloombergLP::bslstl::StdExceptUtil::throwOutOfRange(
                       "const string_view<...>::compare(pos,n,other,other_pos)"
                      ": invalid position");
    }

    if (lhsNumChars > length() - lhsPosition) {
        lhsNumChars = length() - lhsPosition;
    }
    return privateCompareRaw(lhsPosition,
                             lhsNumChars,
                             other,
                             otherNumChars);
}

#if defined(BSLSTL_STRINGVIEW_ENABLE_CPP20_METHODS)
template <class CHAR_TYPE, class CHAR_TRAITS>
BSLS_PLATFORM_AGGRESSIVE_INLINE
BSLS_KEYWORD_CONSTEXPR_CPP14
bool basic_string_view<CHAR_TYPE, CHAR_TRAITS>::starts_with(
                         basic_string_view subview) const BSLS_KEYWORD_NOEXCEPT
{
    return (size() >= subview.size() &&
            0 == compare(0, subview.size(), subview));
}

template <class CHAR_TYPE, class CHAR_TRAITS>
BSLS_PLATFORM_AGGRESSIVE_INLINE
BSLS_KEYWORD_CONSTEXPR
bool basic_string_view<CHAR_TYPE, CHAR_TRAITS>::starts_with(
                               CHAR_TYPE character) const BSLS_KEYWORD_NOEXCEPT
{
    return (!empty() && CHAR_TRAITS::eq(front(), character));
}


template <class CHAR_TYPE, class CHAR_TRAITS>
BSLS_PLATFORM_AGGRESSIVE_INLINE
BSLS_KEYWORD_CONSTEXPR_CPP14
bool basic_string_view<CHAR_TYPE, CHAR_TRAITS>::starts_with(
                                        const CHAR_TYPE* characterString) const
{
    BSLS_ASSERT_SAFE(characterString);
    for (size_type i = 0; i < d_length; ++i) {
        if (characterString[i] == 0) {
            // Ran out of characterString, so is prefix.
            return true;                                              // RETURN
        }
        if (d_start_p[i] != characterString[i]) {
            // Mismatch.
            return false;                                             // RETURN
        }
    }
    // Ran out of string_view, so check characterString is not longer.
    return characterString[d_length] == 0;
}

template <class CHAR_TYPE, class CHAR_TRAITS>
BSLS_PLATFORM_AGGRESSIVE_INLINE
BSLS_KEYWORD_CONSTEXPR_CPP14
bool basic_string_view<CHAR_TYPE, CHAR_TRAITS>::ends_with(
                         basic_string_view subview) const BSLS_KEYWORD_NOEXCEPT
{
    return (size() >= subview.size() &&
            0 == compare(size() - subview.size(), npos, subview));
}

template <class CHAR_TYPE, class CHAR_TRAITS>
BSLS_PLATFORM_AGGRESSIVE_INLINE
BSLS_KEYWORD_CONSTEXPR
bool basic_string_view<CHAR_TYPE, CHAR_TRAITS>::ends_with(
                               CHAR_TYPE character) const BSLS_KEYWORD_NOEXCEPT
{
    return (!empty() && CHAR_TRAITS::eq(back(), character));
}


template <class CHAR_TYPE, class CHAR_TRAITS>
BSLS_PLATFORM_AGGRESSIVE_INLINE
BSLS_KEYWORD_CONSTEXPR_CPP14
bool basic_string_view<CHAR_TYPE, CHAR_TRAITS>::ends_with(
                                        const CHAR_TYPE* characterString) const
{
    return ends_with(basic_string_view(characterString));
}
#endif

template <class CHAR_TYPE, class CHAR_TRAITS>
BSLS_PLATFORM_AGGRESSIVE_INLINE
 BSLS_KEYWORD_CONSTEXPR_CPP14
typename basic_string_view<CHAR_TYPE, CHAR_TRAITS>::size_type
basic_string_view<CHAR_TYPE, CHAR_TRAITS>::find(
                        basic_string_view subview,
                        size_type         position) const BSLS_KEYWORD_NOEXCEPT
{
    return find(subview.data(), position, subview.length());
}

template <class CHAR_TYPE, class CHAR_TRAITS>
BSLS_PLATFORM_AGGRESSIVE_INLINE
BSLS_KEYWORD_CONSTEXPR_CPP14
typename basic_string_view<CHAR_TYPE, CHAR_TRAITS>::size_type
basic_string_view<CHAR_TYPE, CHAR_TRAITS>::find(
                                               const CHAR_TYPE *substring,
                                               size_type        position,
                                               size_type        numChars) const
{
    BSLS_ASSERT_SAFE(substring || (numChars == 0));

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

    return npos;
}

template <class CHAR_TYPE, class CHAR_TRAITS>
BSLS_PLATFORM_AGGRESSIVE_INLINE
BSLS_KEYWORD_CONSTEXPR_CPP14
typename basic_string_view<CHAR_TYPE, CHAR_TRAITS>::size_type
basic_string_view<CHAR_TYPE, CHAR_TRAITS>::find(
                                              const CHAR_TYPE *characterString,
                                              size_type        position) const
{
    BSLS_ASSERT_SAFE(characterString);

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

template <class CHAR_TYPE, class CHAR_TRAITS>
BSLS_PLATFORM_AGGRESSIVE_INLINE
BSLS_KEYWORD_CONSTEXPR_CPP14
typename basic_string_view<CHAR_TYPE, CHAR_TRAITS>::size_type
basic_string_view<CHAR_TYPE, CHAR_TRAITS>::find(
                                CHAR_TYPE character,
                                size_type position) const BSLS_KEYWORD_NOEXCEPT
{
    if (position >= length()) {
        return npos;                                                  // RETURN
    }
    const CHAR_TYPE *result = CHAR_TRAITS::find(data() + position,
                                                length() - position,
                                                character);
    return result ? result - data() : npos;
}

template <class CHAR_TYPE, class CHAR_TRAITS>
BSLS_PLATFORM_AGGRESSIVE_INLINE
BSLS_KEYWORD_CONSTEXPR_CPP14
typename basic_string_view<CHAR_TYPE, CHAR_TRAITS>::size_type
basic_string_view<CHAR_TYPE, CHAR_TRAITS>::rfind(
                        basic_string_view subview,
                        size_type         position) const BSLS_KEYWORD_NOEXCEPT
{
    return rfind(subview.data(), position, subview.length());
}

template <class CHAR_TYPE, class CHAR_TRAITS>
BSLS_PLATFORM_AGGRESSIVE_INLINE
BSLS_KEYWORD_CONSTEXPR_CPP14
typename basic_string_view<CHAR_TYPE, CHAR_TRAITS>::size_type
basic_string_view<CHAR_TYPE, CHAR_TRAITS>::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 = data() + 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>
BSLS_PLATFORM_AGGRESSIVE_INLINE
BSLS_KEYWORD_CONSTEXPR_CPP14
typename basic_string_view<CHAR_TYPE, CHAR_TRAITS>::size_type
basic_string_view<CHAR_TYPE, CHAR_TRAITS>::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>
BSLS_PLATFORM_AGGRESSIVE_INLINE
BSLS_KEYWORD_CONSTEXPR_CPP14
typename basic_string_view<CHAR_TYPE, CHAR_TRAITS>::size_type
basic_string_view<CHAR_TYPE, CHAR_TRAITS>::rfind(
                                CHAR_TYPE character,
                                size_type position) const BSLS_KEYWORD_NOEXCEPT
{
    return rfind(&character, position, size_type(1));
}

template <class CHAR_TYPE, class CHAR_TRAITS>
BSLS_PLATFORM_AGGRESSIVE_INLINE
BSLS_KEYWORD_CONSTEXPR_CPP14
typename basic_string_view<CHAR_TYPE, CHAR_TRAITS>::size_type
basic_string_view<CHAR_TYPE, CHAR_TRAITS>::find_first_of(
                        basic_string_view subview,
                        size_type         position) const BSLS_KEYWORD_NOEXCEPT
{
    return find_first_of(subview.data(), position, subview.length());
}

template <class CHAR_TYPE, class CHAR_TRAITS>
BSLS_PLATFORM_AGGRESSIVE_INLINE
BSLS_KEYWORD_CONSTEXPR_CPP14
typename basic_string_view<CHAR_TYPE, CHAR_TRAITS>::size_type
basic_string_view<CHAR_TYPE, CHAR_TRAITS>::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>
BSLS_PLATFORM_AGGRESSIVE_INLINE
BSLS_KEYWORD_CONSTEXPR_CPP14
typename basic_string_view<CHAR_TYPE, CHAR_TRAITS>::size_type
basic_string_view<CHAR_TYPE, CHAR_TRAITS>::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 = data() + position;
             current != end();
             ++current)
        {
            if (CHAR_TRAITS::find(characterString, numChars, *current) != 0) {
                return current - data();                              // RETURN
            }
        }
    }
    return npos;
}

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

template <class CHAR_TYPE, class CHAR_TRAITS>
BSLS_PLATFORM_AGGRESSIVE_INLINE
BSLS_KEYWORD_CONSTEXPR_CPP14
typename basic_string_view<CHAR_TYPE, CHAR_TRAITS>::size_type
basic_string_view<CHAR_TYPE, CHAR_TRAITS>::find_last_of(
                        basic_string_view subview,
                        size_type         position) const BSLS_KEYWORD_NOEXCEPT
{
    return find_last_of(subview.data(), position, subview.length());
}

template <class CHAR_TYPE, class CHAR_TRAITS>
BSLS_PLATFORM_AGGRESSIVE_INLINE
BSLS_KEYWORD_CONSTEXPR_CPP14
typename basic_string_view<CHAR_TYPE, CHAR_TRAITS>::size_type
basic_string_view<CHAR_TYPE, CHAR_TRAITS>::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>
BSLS_PLATFORM_AGGRESSIVE_INLINE
BSLS_KEYWORD_CONSTEXPR_CPP14
typename basic_string_view<CHAR_TYPE, CHAR_TRAITS>::size_type
basic_string_view<CHAR_TYPE, CHAR_TRAITS>::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 = data() + remChars;
             current >= data();
             --current)
        {
            if (CHAR_TRAITS::find(characterString, numChars, *current)) {
                return current - data();                              // RETURN
            }
        }
    }
    return npos;
}

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

template <class CHAR_TYPE, class CHAR_TRAITS>
BSLS_PLATFORM_AGGRESSIVE_INLINE
 BSLS_KEYWORD_CONSTEXPR_CPP14
typename basic_string_view<CHAR_TYPE, CHAR_TRAITS>::size_type
basic_string_view<CHAR_TYPE, CHAR_TRAITS>::find_first_not_of(
                        basic_string_view subview,
                        size_type         position) const BSLS_KEYWORD_NOEXCEPT
{
    return find_first_not_of(subview.data(), position, subview.length());
}

template <class CHAR_TYPE, class CHAR_TRAITS>
BSLS_PLATFORM_AGGRESSIVE_INLINE
BSLS_KEYWORD_CONSTEXPR_CPP14
typename basic_string_view<CHAR_TYPE, CHAR_TRAITS>::size_type
basic_string_view<CHAR_TYPE, CHAR_TRAITS>::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>
BSLS_PLATFORM_AGGRESSIVE_INLINE
BSLS_KEYWORD_CONSTEXPR_CPP14
typename basic_string_view<CHAR_TYPE, CHAR_TRAITS>::size_type
basic_string_view<CHAR_TYPE, CHAR_TRAITS>::find_first_not_of(
                                              const CHAR_TYPE *characterString,
                                              size_type        position,
                                              size_type        numChars) const
{
    BSLS_ASSERT_SAFE(characterString || 0 == numChars);

    if (position < length()) {
        for (const CHAR_TYPE *current = data() + position;
             current != end();
             ++current)
        {
            if (!CHAR_TRAITS::find(characterString, numChars, *current)) {
                return current - data();                              // RETURN
            }
        }
    }
    return npos;
}

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

template <class CHAR_TYPE, class CHAR_TRAITS>
BSLS_PLATFORM_AGGRESSIVE_INLINE
BSLS_KEYWORD_CONSTEXPR_CPP14
typename basic_string_view<CHAR_TYPE, CHAR_TRAITS>::size_type
basic_string_view<CHAR_TYPE, CHAR_TRAITS>::find_last_not_of(
                        basic_string_view subview,
                        size_type         position) const BSLS_KEYWORD_NOEXCEPT
{
    return find_last_not_of(subview.data(), position, subview.length());
}

template <class CHAR_TYPE, class CHAR_TRAITS>
BSLS_PLATFORM_AGGRESSIVE_INLINE
BSLS_KEYWORD_CONSTEXPR_CPP14
typename basic_string_view<CHAR_TYPE, CHAR_TRAITS>::size_type
basic_string_view<CHAR_TYPE, CHAR_TRAITS>::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>
BSLS_PLATFORM_AGGRESSIVE_INLINE
BSLS_KEYWORD_CONSTEXPR_CPP14
typename basic_string_view<CHAR_TYPE, CHAR_TRAITS>::size_type
basic_string_view<CHAR_TYPE, CHAR_TRAITS>::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 = data() + remChars;
             current >= data();
             --current)
        {
            if (!CHAR_TRAITS::find(characterString, numChars, *current)) {
                return current - data();                              // RETURN
            }
        }
    }
    return npos;
}

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

// PUBLIC ACCESSORS
template <class CHAR_TYPE, class CHAR_TRAITS>
BSLS_PLATFORM_AGGRESSIVE_INLINE
std::size_t hash<basic_string_view<CHAR_TYPE, CHAR_TRAITS> >::
operator()(const basic_string_view<CHAR_TYPE, CHAR_TRAITS>& 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>
BSLS_PLATFORM_AGGRESSIVE_INLINE
std::size_t hash<basic_string_view<CHAR_TYPE, CHAR_TRAITS> >::
operator()(const CHAR_TYPE *input) const
{
    BSLS_ASSERT_SAFE(input);
    using ::BloombergLP::bslh::hashAppend;
    ::BloombergLP::bslh::Hash<>::HashAlgorithm hashAlg;

    std::size_t length = CHAR_TRAITS::length(input);

    hashAlg(input, sizeof(CHAR_TYPE) * length);
    hashAppend(hashAlg, length);
    return static_cast<std::size_t>(hashAlg.computeHash());
}

#if defined(BSLS_PLATFORM_CMP_SUN)  // {DRQS 132030795}

inline
std::size_t hash<string_view>::operator()(const string_view& 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_view>::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_view>::operator()(const wstring_view& 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_view>::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

namespace BloombergLP {
namespace bslstl_stringview_relops {

                            // ----------------------
                            // StringView_CompareUtil
                            // ----------------------

template <class CHAR_TYPE, class CHAR_TRAITS>
inline
BSLS_KEYWORD_CONSTEXPR
bool StringView_CompareUtil<CHAR_TYPE, CHAR_TRAITS>::equals(
                          StringView lhs, StringView 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>
inline
BSLS_KEYWORD_CONSTEXPR_CPP14
bool StringView_CompareUtil<CHAR_TYPE, CHAR_TRAITS>::lessThan(
                          StringView lhs, StringView 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);
}

}  // close namespace bslstl_stringview_relops
}  // close enterprise namespace

// FREE FUNCTIONS
template <class CHAR_TYPE, class CHAR_TRAITS>
inline
BSLS_KEYWORD_CONSTEXPR_CPP14
void bsl::swap(
            basic_string_view<CHAR_TYPE, CHAR_TRAITS>& a,
            basic_string_view<CHAR_TYPE, CHAR_TRAITS>& b) BSLS_KEYWORD_NOEXCEPT
{
    a.swap(b);
}

// FREE OPERATORS
template <class CHAR_TYPE, class CHAR_TRAITS>
inline
BSLS_KEYWORD_CONSTEXPR
bool BloombergLP::bslstl_stringview_relops::
operator==(bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS>        lhs,
           bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS>        rhs)
                                                          BSLS_KEYWORD_NOEXCEPT
{
    return StringView_CompareUtil<CHAR_TYPE, CHAR_TRAITS>::equals(lhs, rhs);
}

template <class CHAR_TYPE, class CHAR_TRAITS>
inline
BSLS_KEYWORD_CONSTEXPR
bool BloombergLP::bslstl_stringview_relops::
operator==(typename BloombergLP::bslstl::StringView_Identity<
                    bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS> >::type lhs,
           const bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS>            rhs)
BSLS_KEYWORD_NOEXCEPT
{
    return StringView_CompareUtil<CHAR_TYPE, CHAR_TRAITS>::equals(lhs, rhs);
}

template <class CHAR_TYPE, class CHAR_TRAITS>
inline
BSLS_KEYWORD_CONSTEXPR
bool BloombergLP::bslstl_stringview_relops::
operator==(const bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS>            lhs,
           typename BloombergLP::bslstl::StringView_Identity<
                    bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS> >::type rhs)
BSLS_KEYWORD_NOEXCEPT
{
    return StringView_CompareUtil<CHAR_TYPE, CHAR_TRAITS>::equals(lhs, rhs);
}

template <class CHAR_TYPE, class CHAR_TRAITS>
inline
BSLS_KEYWORD_CONSTEXPR
bool BloombergLP::bslstl_stringview_relops::
operator!=(bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS>             lhs,
           bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS>             rhs)
BSLS_KEYWORD_NOEXCEPT
{
    return !StringView_CompareUtil<CHAR_TYPE, CHAR_TRAITS>::equals(lhs, rhs);
}

template <class CHAR_TYPE, class CHAR_TRAITS>
inline
BSLS_KEYWORD_CONSTEXPR
bool BloombergLP::bslstl_stringview_relops::
operator!=(typename BloombergLP::bslstl::StringView_Identity<
                    bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS> >::type lhs,
           const bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS>            rhs)
BSLS_KEYWORD_NOEXCEPT
{
    return !StringView_CompareUtil<CHAR_TYPE, CHAR_TRAITS>::equals(lhs, rhs);
}

template <class CHAR_TYPE, class CHAR_TRAITS>
inline
BSLS_KEYWORD_CONSTEXPR
bool BloombergLP::bslstl_stringview_relops::
operator!=(const bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS>            lhs,
           typename BloombergLP::bslstl::StringView_Identity<
                    bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS> >::type rhs)
BSLS_KEYWORD_NOEXCEPT
{
    return !StringView_CompareUtil<CHAR_TYPE, CHAR_TRAITS>::equals(lhs, rhs);
}

template <class CHAR_TYPE, class CHAR_TRAITS>
inline
BSLS_KEYWORD_CONSTEXPR_CPP14
bool BloombergLP::bslstl_stringview_relops::
operator<(bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS>              lhs,
          bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS>              rhs)
                                                          BSLS_KEYWORD_NOEXCEPT
{
    return StringView_CompareUtil<CHAR_TYPE, CHAR_TRAITS>::lessThan(lhs, rhs);
}

template <class CHAR_TYPE, class CHAR_TRAITS>
inline
BSLS_KEYWORD_CONSTEXPR
bool BloombergLP::bslstl_stringview_relops::
operator<(typename BloombergLP::bslstl::StringView_Identity<
                    bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS> >::type lhs,
          const bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS>             rhs)
BSLS_KEYWORD_NOEXCEPT
{
    return StringView_CompareUtil<CHAR_TYPE, CHAR_TRAITS>::lessThan(lhs, rhs);
}

template <class CHAR_TYPE, class CHAR_TRAITS>
inline
BSLS_KEYWORD_CONSTEXPR
bool BloombergLP::bslstl_stringview_relops::
operator<(const bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS>             lhs,
          typename BloombergLP::bslstl::StringView_Identity<
                    bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS> >::type rhs)
BSLS_KEYWORD_NOEXCEPT
{
    return StringView_CompareUtil<CHAR_TYPE, CHAR_TRAITS>::lessThan(lhs, rhs);
}

template <class CHAR_TYPE, class CHAR_TRAITS>
inline
BSLS_KEYWORD_CONSTEXPR
bool BloombergLP::bslstl_stringview_relops::
operator>(bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS>              lhs,
          bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS>              rhs)
BSLS_KEYWORD_NOEXCEPT
{
    return StringView_CompareUtil<CHAR_TYPE, CHAR_TRAITS>::lessThan(rhs, lhs);
}

template <class CHAR_TYPE, class CHAR_TRAITS>
inline
BSLS_KEYWORD_CONSTEXPR
bool BloombergLP::bslstl_stringview_relops::
operator>(typename BloombergLP::bslstl::StringView_Identity<
                    bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS> >::type lhs,
          const bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS>             rhs)
BSLS_KEYWORD_NOEXCEPT
{
    return StringView_CompareUtil<CHAR_TYPE, CHAR_TRAITS>::lessThan(rhs, lhs);
}

template <class CHAR_TYPE, class CHAR_TRAITS>
inline
BSLS_KEYWORD_CONSTEXPR
bool BloombergLP::bslstl_stringview_relops::
operator>(const bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS>             lhs,
          typename BloombergLP::bslstl::StringView_Identity<
                    bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS> >::type rhs)
BSLS_KEYWORD_NOEXCEPT
{
    return StringView_CompareUtil<CHAR_TYPE, CHAR_TRAITS>::lessThan(rhs, lhs);
}

template <class CHAR_TYPE, class CHAR_TRAITS>
inline
BSLS_KEYWORD_CONSTEXPR
bool BloombergLP::bslstl_stringview_relops::
operator<=(bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS>             lhs,
           bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS>             rhs)
                                                          BSLS_KEYWORD_NOEXCEPT
{
    return !StringView_CompareUtil<CHAR_TYPE, CHAR_TRAITS>::lessThan(rhs, lhs);
}

template <class CHAR_TYPE, class CHAR_TRAITS>
inline
BSLS_KEYWORD_CONSTEXPR
bool BloombergLP::bslstl_stringview_relops::
operator<=(typename BloombergLP::bslstl::StringView_Identity<
                    bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS> >::type lhs,
           const bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS>            rhs)
BSLS_KEYWORD_NOEXCEPT
{
    return !StringView_CompareUtil<CHAR_TYPE, CHAR_TRAITS>::lessThan(rhs, lhs);
}

template <class CHAR_TYPE, class CHAR_TRAITS>
inline
BSLS_KEYWORD_CONSTEXPR
bool BloombergLP::bslstl_stringview_relops::
operator<=(const bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS>            lhs,
           typename BloombergLP::bslstl::StringView_Identity<
                    bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS> >::type rhs)
BSLS_KEYWORD_NOEXCEPT
{
    return !StringView_CompareUtil<CHAR_TYPE, CHAR_TRAITS>::lessThan(rhs, lhs);
}

template <class CHAR_TYPE, class CHAR_TRAITS>
inline
BSLS_KEYWORD_CONSTEXPR
bool BloombergLP::bslstl_stringview_relops::
operator>=(bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS>             lhs,
           bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS>             rhs)
BSLS_KEYWORD_NOEXCEPT
{
    return !StringView_CompareUtil<CHAR_TYPE, CHAR_TRAITS>::lessThan(lhs, rhs);
}

template <class CHAR_TYPE, class CHAR_TRAITS>
inline
BSLS_KEYWORD_CONSTEXPR
bool BloombergLP::bslstl_stringview_relops::
operator>=(typename BloombergLP::bslstl::StringView_Identity<
                    bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS> >::type lhs,
           const bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS>            rhs)
BSLS_KEYWORD_NOEXCEPT
{
    return !StringView_CompareUtil<CHAR_TYPE, CHAR_TRAITS>::lessThan(lhs, rhs);
}

template <class CHAR_TYPE, class CHAR_TRAITS>
inline
BSLS_KEYWORD_CONSTEXPR
bool BloombergLP::bslstl_stringview_relops::
operator>=(const bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS>            lhs,
           typename BloombergLP::bslstl::StringView_Identity<
                    bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS> >::type rhs)
BSLS_KEYWORD_NOEXCEPT
{
    return !StringView_CompareUtil<CHAR_TYPE, CHAR_TRAITS>::lessThan(lhs, rhs);
}

namespace bsl {

using BloombergLP::bslstl_stringview_relops::operator==;
using BloombergLP::bslstl_stringview_relops::operator!=;
using BloombergLP::bslstl_stringview_relops::operator<;
using BloombergLP::bslstl_stringview_relops::operator>;
using BloombergLP::bslstl_stringview_relops::operator<=;
using BloombergLP::bslstl_stringview_relops::operator>=;

}

template <class CHAR_TYPE, class CHAR_TRAITS>
std::basic_ostream<CHAR_TYPE>&
bsl::operator<<(std::basic_ostream<CHAR_TYPE>&            stream,
                basic_string_view<CHAR_TYPE, CHAR_TRAITS> stringView)
{
    typedef CHAR_TYPE                                           char_type;
    typedef typename std::basic_ostream<char_type>::ios_base    ios_base;
    typedef typename basic_string_view<CHAR_TYPE, CHAR_TRAITS>::size_type
                                                                size_type;

    size_type width = static_cast<size_type>(stream.width());
    size_type len = stringView.length();

    if (len < width) {
        bool leftAdjusted =
                    (stream.flags() & ios_base::adjustfield) == ios_base::left;

        char_type fillChar = stream.fill();

        if (leftAdjusted) {
            if (stringView.data()) {
                 stream.write(stringView.data(), stringView.length());
            }
        }

        for (size_type n = 0; n != width - len; ++n) {
            stream.put(fillChar);
        }

        if (!leftAdjusted) {
            if (stringView.data()) {
                 stream.write(stringView.data(), stringView.length());
            }
        }
    }
    else {
        if (stringView.data()) {
            stream.write(stringView.data(), stringView.length());
        }
    }

    stream.width(0);

    return stream;
}

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

#endif  // BSLSTL_STRING_VIEW_IS_ALIASED

#ifdef BSLSTL_STRING_VIEW_IS_ALIASED
namespace BloombergLP {

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

}  // close enterprise namespace
#endif  // BSLSTL_STRING_VIEW_IS_ALIASED

#endif

// ----------------------------------------------------------------------------
// Copyright 2019 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 ----------------------------------