// bslstl_stringref.h                                                 -*-C++-*-
#ifndef INCLUDED_BSLSTL_STRINGREF
#define INCLUDED_BSLSTL_STRINGREF

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

//@PURPOSE: Provide a reference to a 'const' string.
//
//@CLASSES:
//   bslstl::StringRefImp: reference wrapper for a generic string
//      bslstl::StringRef: reference wrapper for a 'char' string
//  bslstl::StringRefWide: reference wrapper for a 'wchar_t' string
//
//@SEE_ALSO: bdlb_stringrefutil
//
//@DESCRIPTION: This component defines two classes, 'bslstl::StringRef' and
// 'bslstl::StringRefWide', each providing a reference to a non-modifiable
// string value having an external representation.  The type of characters in
// the string value can be either 'char' (for 'bslstl::StringRef') or 'wchar_t'
// (for 'bslstl::StringRefWide').
//
// The invariant of 'bslstl::StringRef' is that it always has a valid
// non-modifiable 'std::string' value, where non-empty string values have an
// external representation.  Empty string values do not need to have an
// external representation.  Most operations on 'bslstl::StringRef' objects
// have reference semantics and apply to the string value: e.g., 'operator=='
// compares string values, not whether 'bslstl::StringRef' objects reference
// the same string object.
//
// The only operations that do not apply to the string value (i.e., that have
// pointer semantics) are copy construction and assignment.  These operations
// produce a 'bslstl::StringRef' object with the same external representation
// as the original 'bslstl::StringRef' object, which is a stronger
// post-condition than having 'operator==' return 'true' for two
// 'bslstl::StringRef' objects that have the same value.
//
// The standard notion of substitutability defined by the 'operator==' does not
// necessarily apply to 'bslstl::StringRef' since 'bslstl::StringRef' is not a
// value-semantic type (because of the external representation).  Therefore
// there can be a plausible sequence of operations applied to two "equal"
// 'bslstl::StringRef' objects that result in objects that don't compare equal.
//
// The string value that is represented by a 'bslstl::StringRef' object need
// not be null-terminated.  Moreover, the string may contain embedded null
// characters.  As such, the string referenced by 'bslstl::StringRef', in
// general, is not a C-style string.  Moreover, the notion of a null-string
// value is not supported.
//
// The address of the string referenced by 'bslstl::StringRef' is indicated by
// the 'data' accessor.  Its extent is indicated by the 'length' and 'size'
// accessors.  The referenced string is also indicated by the 'begin' and 'end'
// accessors that return STL-compatible iterators to the beginning of the
// string and one character past the end of the string, respectively.  An
// overloaded 'operator[]' is also provided for direct by-index access to
// individual characters in the string.
//
// Several overloaded free operators are provided for 'bslstl::StringRef'
// objects (as well as variants for all combinations involving
// 'bslstl::StringRef' and 'std::string', and 'bslstl::StringRef' and 'char *')
// for (1) lexicographic comparison of values, and (2) concatenation of values
// (producing an 'std::string'); also provided is an overloaded free
// 'operator<<' for writing the value of a 'bslstl::StringRef' object to a
// specified output stream.
//
// The 'bsl::hash' template class is specialized for 'bslstl::StringRef' to
// enable the use of 'bslstl::StringRef' with STL hash containers (e.g.,
// 'bsl::unordered_set' and 'bsl::unordered_map').
//
///How to include 'bslstl::StringRef'
///----------------------------------
// To include 'bslstl::StringRef' use '#include <bsl_string.h>' (*not*
// '#include <bslstl_stringref.h>').
//
///Efficiency and Usage Considerations
///-----------------------------------
// Using 'bslstl::StringRef' to pass strings as function arguments can be
// considerably more efficient than passing 'bsl::string' objects by 'const'
// reference.  First, consider a hypothetical class method in which the
// parameter is a reference to a non-modifiable 'bsl::string':
//..
//  void MyClass::setLabel(const bsl::string& label)
//  {
//      d_label = label;  // 'MyClass::d_label' is of type 'bsl::string'
//  }
//..
// Then, consider a typical call to this method:
//..
//  MyClass myClassObj;
//  myClassObj.setLabel("hello");
//..
// As a side-effect of this call, a temporary 'bsl::string' containing a *copy*
// of "hello" is created (using the default allocator), that value is copied to
// 'd_label', and the temporary is eventually destroyed.  The call thus
// requires the string data to be copied twice (as well as a possible
// allocation and deallocation).
//
// Next, consider the same method taking a reference to a non-modifiable
// 'bslstl::StringRef':
//..
//  void MyClass::setLabel(const bslstl::StringRef& label)
//  {
//      d_label.assign(label.begin(), label.end());
//  }
//..
// Now:
//..
//  myClassObj.setLabel("hello");
//..
// This call has the side-effect of creating a temporary 'bslstl::StringRef'
// object, which is likely to be more efficient than creating a temporary
// 'bsl::string' (even when implemented using the short-string optimization).
// In this case, instead of copying the *contents* of "hello", the *address* of
// the literal string is copied.  In addition, 'bsl::strlen' is applied to the
// string in order to locate its end.  There are *no* allocations done on
// behalf of the temporary object.
//
///Caveats
///-------
// 1) The string referenced by 'bslstl::StringRef' need not be null-terminated,
// and, in fact, may *contain* embedded null characters.  Thus, it is generally
// not valid to pass the address returned by the 'data' accessor to Standard C
// functions that expect a null-terminated string (e.g., 'std::strlen',
// 'std::strcmp', etc.).
//
// 2) The string referenced by 'bslstl::StringRef' must remain valid as long as
// the 'bslstl::StringRef' references that string.  Lifetime issues should be
// carefully considered when, for example, returning a 'bslstl::StringRef'
// object from a function or storing a 'bslstl::StringRef' object in a
// container.
//
// 3) Passing a null string to any function (e.g., 'operator==') without also
// passing a 0 length results in undefined behavior.
//
///Usage
///-----
// This section illustrates intended use of this component.
//
///Example 1: Basic Operations
///- - - - - - - - - - - - - -
// The following snippets of code illustrate basic and varied use of the
// 'bslstl::StringRef' class.
//
// First, we define a function, 'getNumBlanks', that returns the number of
// blank (' ') characters contained in the string referenced by a specified
// 'bslstl::StringRef':
//..
//  #include <algorithm>
//
//   bslstl::StringRef::size_type
//   getNumBlanks(const bslstl::StringRef& stringRef)
//      // Return the number of blank (' ') characters in the string referenced
//      // by the specified 'stringRef'.
//  {
//      return std::count(stringRef.begin(), stringRef.end(), ' ');
//  }
//..
// Notice that the function delegates the work to the 'std::count' STL
// algorithm.  This delegation is made possible by the STL-compatible iterators
// provided by the 'begin' and 'end' accessors.
//
// Then, call 'getNumBlanks' on a default constructed 'bslstl::StringRef':
//..
//  bslstl::StringRef            emptyRef;
//  bslstl::StringRef::size_type numBlanks = getNumBlanks(emptyRef);
//  assert(0 == numBlanks);
//
//  assert(""         == emptyRef);
//  assert("anything" >= emptyRef);
//..
// Notice that the behavior a default constructed 'bslstl::StringRef' object
// behaves the same as if it referenced an empty string.
//
// Next, we (implicitly) construct a 'bsl::string' object from
// 'bslstl::StringRef':
//..
//  bsl::string empty(emptyRef);
//  assert(0 == empty.size());
//..
// Then, we call 'getNumBlanks' on a string literal and assert that the number
// of blanks returned is as expected:
//..
//  numBlanks = getNumBlanks("Good things come to those who wait.");
//  assert(6 == numBlanks);
//..
// Next, we define a longer string literal, 'poem', that we will use in the
// rest of this usage example:
//..
//  const char poem[] =                  // by William Butler Yeats (1865-1939)
//      |....5....|....5....|....5....|....5....|   //  length  blanks
//                                                  //
//      "O love is the crooked thing,\n"            //    29      5
//      "There is nobody wise enough\n"             //    28      4
//      "To find out all that is in it,\n"          //    31      7
//      "For he would be thinking of love\n"        //    33      6
//      "Till the stars had run away\n"             //    28      5
//      "And the shadows eaten the moon.\n"         //    32      5
//      "Ah, penny, brown penny, brown penny,\n"    //    37      5
//      "One cannot begin it too soon.";            //    29      5
//                                                  //          ----
//                                                  //    total: 42
//
//  numBlanks = getNumBlanks(poem);
//  assert(42 == numBlanks);
//..
// Then, we construct a 'bslstl::StringRef' object, 'line', that refers to only
// the first line of the 'poem':
//..
//  bslstl::StringRef line(poem, 29);
//  numBlanks = getNumBlanks(line);
//
//  assert( 5 == numBlanks);
//  assert(29 == line.length());
//  assert( 0 == std::strncmp(poem, line.data(), line.length()));
//..
// Next, we use the 'assign' method to make 'line' refer to the second line of
// the 'poem':
//..
//  line.assign(poem + 29, poem + 57);
//  numBlanks = getNumBlanks(line);
//  assert(4 == numBlanks);
//  assert((57 - 29) == line.length());
//  assert("There is nobody wise enough\n" == line);
//..
// Then, we call 'getNumBlanks' with a 'bsl::string' initialized to the
// contents of the 'poem':
//..
//  const bsl::string poemString(poem);
//  numBlanks = getNumBlanks(poemString);
//  assert(42 == numBlanks);
//  assert(bslstl::StringRef(poemString) == poemString);
//  assert(bslstl::StringRef(poemString) == poemString.c_str());
//..
// Next, we make a 'bslstl::StringRef' object that refers to a string that will
// be able to hold embedded null characters:
//..
//  char poemWithNulls[512];
//  const bsl::size_t poemLength = std::strlen(poem);
//  assert(poemLength < 512);
//
//  std::memcpy(poemWithNulls, poem, poemLength + 1);
//  assert(0 == std::strcmp(poem, poemWithNulls));
//..
// Now, we replace each occurrence of a '\n' in 'poemWithNulls' with a yielding
// '\0':
//..
//  std::replace(poemWithNulls, poemWithNulls + poemLength, '\n', '\0');
//  assert(0 != std::strcmp(poem, poemWithNulls));
//..
// Finally, we observe that 'poemWithNulls' has the same number of blank
// characters as the original 'poem':
//..
//  numBlanks = getNumBlanks(bslstl::StringRef(poemWithNulls, poemLength));
//  assert(42 == numBlanks);
//..

#include <bslscm_version.h>

#include <bslstl_iterator.h>
#include <bslstl_string.h>
#include <bslstl_stringrefdata.h>

#include <bslmf_enableif.h>
#include <bslmf_isintegral.h>
#include <bslmf_istriviallycopyable.h>
#include <bslmf_nestedtraitdeclaration.h>
#include <bslmf_nil.h>

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

#include <algorithm>            // for 'std::min'
#include <cstddef>              // for 'std::size_t'
#include <cstring>
#include <iosfwd>

#if defined(BSLS_LIBRARYFEATURES_HAS_CPP17_PMR)
#include <memory_resource>  // 'std::pmr::polymorphic_allocator'
#endif

namespace BloombergLP {
namespace bslstl {

#if defined(BSLS_PLATFORM_OS_AIX)

// These 'using's are necessary for a compiler bug on Aix where sometimes when
// 'bslstl::StringRef's are compared, the ADL doesn't look in the namespace of
// the base class for candidates.

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>=;

#endif

                    // =============================
                    // class StringRefImp<CHAR_TYPE>
                    // =============================

template <class CHAR_TYPE>
class StringRefImp : public StringRefData<CHAR_TYPE> {
    // This class provides a reference-semantic-like (see below) mechanism that
    // allows 'const' 'std::string' values, which are represented externally as
    // either an 'std::string' or null-terminated c-style string (or parts
    // thereof), to be treated both uniformly and efficiently when passed as an
    // argument to a function in which the string's length will be needed.  The
    // interface of this class provides a subset of accessor methods found on
    // 'std::string' (but none of the manipulators) -- all of which apply to
    // the referenced string.  But, because only non-modifiable access is
    // afforded to the referenced string value, each of the manipulators on
    // this type -- assignment in particular -- apply to this string-reference
    // object itself (as if it had pointer semantics).  Hence, this class has a
    // hybrid of reference- and pointer-semantics.
    //
    // This class:
    //: o supports a complete set of *value-semantic* operations
    //:   o except for 'bdex' serialization
    //: o is *exception-neutral* (agnostic)
    //: o is *alias-safe*
    //: o is 'const' *thread-safe*
    // For terminology see 'bsldoc_glossary'.

  private:
    // PRIVATE TYPES
    typedef StringRefData<CHAR_TYPE> Base;

  public:
    // PUBLIC TYPES
    typedef const CHAR_TYPE                        value_type;
    typedef const CHAR_TYPE&                       reference;
    typedef const CHAR_TYPE&                       const_reference;
    typedef const CHAR_TYPE                       *iterator;
    typedef const CHAR_TYPE                       *const_iterator;
    typedef bsl::reverse_iterator<const_iterator>  const_reverse_iterator;
    typedef std::ptrdiff_t                         difference_type;
    typedef std::size_t                            size_type;
        // Standard Library general container requirements.

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

  private:
    // PRIVATE ACCESSORS
    void write(std::basic_ostream<CHAR_TYPE>& stream) const;
        // Write the value of this string reference to the specified output
        // 'stream' in the unformatted way.

  public:
    // CREATORS
    StringRefImp();
        // Create an object representing an empty 'std::string' value that is
        // independent of any external representation and with the following
        // attribute values:
        //..
        //  begin() == end()
        //  isEmpty() == true
        //..

    template <class INT_TYPE>
    StringRefImp(const CHAR_TYPE *data,
                 INT_TYPE         length,
                 typename bsl::enable_if<bsl::is_integral<INT_TYPE>::value,
                                         bslmf::Nil>::type = bslmf::Nil());
    StringRefImp(const CHAR_TYPE *data, size_type length);
        // Create a string-reference object having a valid 'std::string' value,
        // whose external representation begins at the specified 'data' address
        // and extends for the specified 'length'.  The external representation
        // must remain valid as long as it is bound to this string reference.
        // Passing 0 has the same effect as default construction.  The behavior
        // is undefined unless '0 <= length' and, if '0 == data', then
        // '0 == length'.  Note that, like an 'std::string', the 'data' need
        // not be null-terminated and may contain embedded null characters.
        // Note that the template and non-template versions combine to allow
        // various integral and enumeration types to be used for length while
        // preventing '(char *, 0)' initializer arguments from matching the
        // two-iterator constructor below.

    StringRefImp(const_iterator begin, const_iterator end);
        // Create a string-reference object having a valid 'std::string' value,
        // whose external representation begins at the specified 'begin'
        // iterator and extends up to, but not including, the specified 'end'
        // iterator.  The external representation must remain valid as long as
        // it is bound to this string reference.  The behavior is undefined
        // unless 'begin <= end'.  Note that, like an 'std::string', the string
        // need not be null-terminated and may contain embedded null
        // characters.

    StringRefImp(const CHAR_TYPE *data);                            // IMPLICIT
        // Create a string-reference object having a valid 'std::string' value,
        // whose external representation begins at the specified 'data' address
        // and extends for 'std::char_traits<CHAR_TYPE>::length(data)'
        // characters.  The external representation must remain valid as long
        // as it is bound to this string reference.  The behavior is undefined
        // unless 'data' is null-terminated.

    StringRefImp(const bsl::basic_string_view<CHAR_TYPE>& str);     // IMPLICIT
    StringRefImp(const std::basic_string<CHAR_TYPE>& str);          // IMPLICIT
    StringRefImp(const bsl::basic_string<CHAR_TYPE>& str);          // IMPLICIT
#ifdef BSLS_LIBRARYFEATURES_HAS_CPP17_PMR
    StringRefImp(const std::pmr::basic_string<CHAR_TYPE>& str);     // IMPLICIT
#endif
        // Create a string-reference object having a valid 'std::string' value,
        // whose external representation is defined by the specified 'str'
        // object.  The external representation must remain valid as long as it
        // is bound to this string reference.

#if defined(BSLS_COMPILERFEATURES_SUPPORT_DEFAULTED_FUNCTIONS)
    StringRefImp(const StringRefImp& original) = default;
        // Create a string-reference object having a valid 'std::string' value,
        // whose external representation is defined by the specified 'original'
        // object.  The external representation must remain valid as long as it
        // is bound to this string reference.  Note that this trivial copy
        // constructor's definition is compiler generated.
#endif

    StringRefImp(const StringRefImp& original,
                 size_type           startIndex,
                 size_type           numCharacters);
        // Create a string-reference object having a valid 'std::string' value,
        // whose external representation begins at the specified 'startIndex'
        // in the specified 'original' string reference, and extends either the
        // specified 'numCharacters' or until the end of the 'original' string
        // reference, whichever comes first.  The external representation must
        // remain valid as long as it is bound to this string reference.  The
        // behavior is undefined unless 'startIndex <= original.length()'.
        // Note that if 'startIndex' is 'original.length()' an empty string
        // reference is returned.

#if defined(BSLS_COMPILERFEATURES_SUPPORT_DEFAULTED_FUNCTIONS)
    ~StringRefImp() = default;
        // Destroy this object.
#endif

    // MANIPULATORS
    StringRefImp& operator=(const StringRefImp& rhs);
        // Modify this string reference to refer to the same string as the
        // specified 'rhs' string reference and return a reference providing
        // modifiable access to this object.  The assigned object is guaranteed
        // to have values of attributes 'begin' and 'end' equal to the 'rhs'
        // object's attributes.

    template <class INT_TYPE>
    void assign(const CHAR_TYPE *data,
                INT_TYPE         length,
                typename bsl::enable_if<bsl::is_integral<INT_TYPE>::value,
                                             bslmf::Nil>::type = bslmf::Nil());
    void assign(const CHAR_TYPE *data, size_type length);
        // Bind this string reference to the string at the specified 'data'
        // address and extending for the specified 'length' characters.  The
        // string indicated by 'data' and 'length' must remain valid as long as
        // it is bound to this object.  The behavior is undefined unless
        // '0 <= length' or '0 == data && 0 == length'.  Note that the string
        // need not be null-terminated and may contain embedded null
        // characters.  Note that the template and non-template versions
        // combine to allow various integral and enumeration types to be used
        // for length while preventing '(char *, 0)' initializer arguments from
        // matching the two-iterator overload of 'assign' below.

    void assign(const_iterator begin, const_iterator end);
        // Bind this string reference to the string at the specified 'begin'
        // iterator, extending up to, but not including, the character at the
        // specified 'end' iterator.  The string indicated by 'begin' and 'end'
        // must remain valid as long as it is bound to this object.  The
        // behavior is undefined unless 'begin <= end'.  Note that the string
        // need not be null-terminated and may contain embedded null
        // characters.

    void assign(const CHAR_TYPE *data);
        // Bind this string reference to the string at the specified 'data'
        // address and extending for
        // 'std::char_traits<CHAR_TYPE>::length(data)' characters.  The string
        // at the 'data' address must remain valid as long as it is bound to
        // this string reference.  The behavior is undefined unless 'data' is
        // null-terminated.

    void assign(const bsl::basic_string<CHAR_TYPE>& str);
        // Bind this string reference to the specified 'str' string.  The
        // string indicated by 'str' must remain valid as long as it is bound
        // to this object.

    void assign(const StringRefImp<CHAR_TYPE>& stringRef);
        // Modify this string reference to refer to the same string as the
        // specified 'stringRef'.  Note, that the string bound to 'stringRef'
        // must remain valid as long as it is bound to this object.

    void reset();
        // Reset this string reference to the default-constructed state having
        // an empty 'std::string' value and the following attribute values:
        //..
        //  begin() == end()
        //  isEmpty() == true
        //..

    // ACCESSORS
    const_reference operator[](size_type index) const;
        // Return a reference providing a non-modifiable access to the
        // character at the specified 'index' in the string bound to this
        // reference.  This reference remains valid as long as the string
        // currently bound to this object remains valid.  The behavior is
        // undefined unless '0 <= index < length()'.

    operator std::basic_string<CHAR_TYPE>() const;
        // Return an 'std::basic_string' (synonymous with
        // 'std::basic_string') having the value of the string bound to
        // this string reference.

    const_iterator begin() const;
        // Return an STL-compatible iterator to the first character of the
        // string bound to this string reference or 'end()' if the string
        // reference is empty.  The iterator remains valid as long as this
        // object is valid and is bound to the same string.

    const_iterator end() const;
        // Return an STL-compatible iterator one-past-the-last character of the
        // string bound to this string reference or 'begin()' if the string
        // reference is empty.  The iterator remains valid as long as this
        // object is valid and is bound to the same string.

    const_reverse_iterator rbegin() const;
        // Return an STL-compatible reverse iterator to the last character of
        // the string bound to this string reference or 'rend()' if the string
        // reference is empty.  The iterator remains valid as long as this
        // object is valid and is bound to the same string.

    const_reverse_iterator rend() const;
        // Return an STL-compatible reverse iterator to the
        // prior-to-the-beginning character of the string bound to this string
        // reference or 'rbegin()' if the string reference is empty.  The
        // iterator remains valid as long as this object is valid and is bound
        // to the same string.

    const CHAR_TYPE *data() const;
        // Return the address of the first character of the string bound to
        // this string reference such that '[data() .. data()+length())' is a
        // valid half-open range of characters.  Note that the range of
        // characters might not be null-terminated and may contain embedded
        // null characters.

    bool empty() const;
        // Return 'true' if this object represents an empty string value, and
        // 'false' otherwise.  This object represents an empty string value if
        // 'begin() == end()'.  Note that this method is functionally identical
        // with the 'isEmpty' method and allows developers to avoid distracting
        // syntax differences when 'StringRef' appears in juxtaposition with
        // 'string', which defines 'empty' but not 'isEmpty'.

    bool isEmpty() const;
        // Return 'true' if this object represents an empty string value, and
        // 'false' otherwise.  This object represents an empty string value if
        // 'begin() == end()'.

    size_type length() const;
        // Return the length of the string referred to by this object.  Note
        // that this call is equivalent to 'end() - begin()'.

    size_type size() const;
        // Return the number of characters in the string referred to by this
        // object.  Note that this call is equivalent to 'end() - begin()'.

    int compare(const StringRefImp& other) const;
        // Compare this and the specified 'other' string objects using a
        // lexicographical comparison and return a negative value if this
        // string is less than 'other' string, a positive value if this string
        // is greater than 'other' string, and 0 if this string is equal to
        // 'other' string.
};

                        // ===============================
                        // struct StringRefImp_CompareUtil
                        // ===============================

struct StringRefImp_CompareUtil {
    // [!PRIVATE!] This class provides a namespace for private comparison
    // implementation functions.

    // CLASS METHODS
    template <class CHAR_TYPE>
    static
    int compare(const StringRefImp<CHAR_TYPE>&  a,
                const CHAR_TYPE                *b);
        // Compare the specified string object 'a' with the specified
        // null-terminated C-string 'b' using a lexicographical comparison and
        // return a negative value if 'a' is less than 'b', a positive value if
        // 'a' is greater than 'b', and 0 if 'a' is equal to 'b'.

    template <class CHAR_TYPE>
    static
    bool compareEqual(const StringRefImp<CHAR_TYPE>& a,
                      const StringRefImp<CHAR_TYPE>& b);
        // Return 'true' if the specified 'a' is equal to 'b' and 'false'
        // otherwise.  Note that this function is more efficient than 'compare'
        // for non-lexicographical equality comparisons.

    template <class CHAR_TYPE>
    static
    bool compareEqual(const StringRefImp<CHAR_TYPE>&  a,
                      const CHAR_TYPE                *b);
        // Return 'true' if the specified 'a' is equal to the specified
        // null-terminated C-string 'b' and 'false' otherwise.  Note that this
        // function is more efficient than 'compare' for non-lexicographical
        // equality comparisons.
};

template <class CHAR_TYPE>
bsl::basic_string<CHAR_TYPE>
operator+(const StringRefImp<CHAR_TYPE>& lhs,
          const StringRefImp<CHAR_TYPE>& rhs);
template <class CHAR_TYPE>
bsl::basic_string<CHAR_TYPE>
operator+(const bsl::basic_string<CHAR_TYPE>& lhs,
          const StringRefImp<CHAR_TYPE>&      rhs);
template <class CHAR_TYPE>
bsl::basic_string<CHAR_TYPE>
operator+(const StringRefImp<CHAR_TYPE>&      lhs,
          const bsl::basic_string<CHAR_TYPE>& rhs);
template <class CHAR_TYPE>
bsl::basic_string<CHAR_TYPE>
operator+(const StringRefImp<CHAR_TYPE>&      lhs,
          const std::basic_string<CHAR_TYPE>& rhs);
template <class CHAR_TYPE>
bsl::basic_string<CHAR_TYPE>
operator+(const std::basic_string<CHAR_TYPE>& lhs,
          const StringRefImp<CHAR_TYPE>&      rhs);
template <class CHAR_TYPE>
bsl::basic_string<CHAR_TYPE>
operator+(const CHAR_TYPE                *lhs,
          const StringRefImp<CHAR_TYPE>&  rhs);
template <class CHAR_TYPE>
bsl::basic_string<CHAR_TYPE>
operator+(const StringRefImp<CHAR_TYPE>&  lhs,
          const CHAR_TYPE                *rhs);
    // Return a 'bsl::string' having the value of the concatenation of the
    // strings referred to by the specified 'lhs' and 'rhs' values.

// FREE FUNCTIONS
template <class CHAR_TYPE, class HASHALG>
void hashAppend(HASHALG& hashAlg, const StringRefImp<CHAR_TYPE>&  input);
    // Pass the specified 'input' to the specified 'hashAlg'

// ============================================================================
//                                  TYPEDEFS
// ============================================================================

typedef StringRefImp<char>       StringRef;
typedef StringRefImp<wchar_t>    StringRefWide;

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

                          // ------------------
                          // class StringRefImp
                          // ------------------

// PRIVATE ACCESSOR
template <class CHAR_TYPE>
inline
void StringRefImp<CHAR_TYPE>::write(
                                   std::basic_ostream<CHAR_TYPE>& stream) const
{
    if (data()) {
        stream.write(data(), length());
    }
    else {
        BSLS_ASSERT_SAFE(length() == 0);
    }
}

// CREATORS
template <class CHAR_TYPE>
inline
StringRefImp<CHAR_TYPE>::StringRefImp()
: Base(0, 0)
{
}

template <class CHAR_TYPE>
template <class INT_TYPE>
inline
StringRefImp<CHAR_TYPE>::StringRefImp(
                     const CHAR_TYPE *data,
                     INT_TYPE         length,
                     typename bsl::enable_if<bsl::is_integral<INT_TYPE>::value,
                                             bslmf::Nil>::type)
: Base(data, data + length)
{
    BSLS_ASSERT_SAFE(0 <= length);
    BSLS_ASSERT_SAFE(data || 0 == length);
}

template <class CHAR_TYPE>
inline
StringRefImp<CHAR_TYPE>::StringRefImp(const CHAR_TYPE *data, size_type length)
: Base(data, data + length)
{
    BSLS_ASSERT_SAFE(data || 0 == length);
}

template <class CHAR_TYPE>
inline
StringRefImp<CHAR_TYPE>::StringRefImp(const_iterator begin, const_iterator end)
: Base(begin, end)
{
    BSLS_ASSERT_SAFE((begin == 0) == (end == 0));
    BSLS_ASSERT_SAFE(begin <= end);
}

template <class CHAR_TYPE>
inline
StringRefImp<CHAR_TYPE>::StringRefImp(const CHAR_TYPE *data)
: Base(data, data + Base::cStringLength(data))
{
    BSLS_ASSERT_SAFE(data);
}

template <class CHAR_TYPE>
inline
StringRefImp<CHAR_TYPE>::StringRefImp(
                                  const bsl::basic_string_view<CHAR_TYPE>& str)
: Base(str)
{
}

template <class CHAR_TYPE>
inline
StringRefImp<CHAR_TYPE>::StringRefImp(const bsl::basic_string<CHAR_TYPE>& str)
: Base(str.data(), str.data() + str.length())
{
}

template <class CHAR_TYPE>
inline
StringRefImp<CHAR_TYPE>::StringRefImp(const std::basic_string<CHAR_TYPE>& str)
: Base(str.data(), str.data() + str.length())
{
}

#ifdef BSLS_LIBRARYFEATURES_HAS_CPP17_PMR
template <class CHAR_TYPE>
inline
StringRefImp<CHAR_TYPE>::StringRefImp(
                                  const std::pmr::basic_string<CHAR_TYPE>& str)
: Base(str.data(), str.data() + str.length())
{
}
#endif

template <class CHAR_TYPE>
inline
StringRefImp<CHAR_TYPE>::StringRefImp(
                                  const StringRefImp<CHAR_TYPE>& original,
                                  size_type                      startIndex,
                                  size_type                      numCharacters)
: Base(original.begin() + startIndex,
       original.begin() + startIndex +
                std::min(numCharacters, original.length() - startIndex))
{
    BSLS_ASSERT_SAFE(startIndex <= original.length());
}


// MANIPULATORS
template <class CHAR_TYPE>
inline
StringRefImp<CHAR_TYPE>&
    StringRefImp<CHAR_TYPE>::operator=(const StringRefImp& rhs)
{
    Base::operator=(rhs);
    return *this;
}

template <class CHAR_TYPE>
template <class INT_TYPE>
inline
void StringRefImp<CHAR_TYPE>::assign(
                     const CHAR_TYPE *data,
                     INT_TYPE         length,
                     typename bsl::enable_if<bsl::is_integral<INT_TYPE>::value,
                                         bslmf::Nil>::type)
{
    BSLS_ASSERT_SAFE(data || 0 == length);

    *this = StringRefImp(data, data + length);
}

template <class CHAR_TYPE>
inline
void StringRefImp<CHAR_TYPE>::assign(const CHAR_TYPE *data, size_type length)
{
    BSLS_ASSERT_SAFE(data || 0 == length);

    *this = StringRefImp(data, data + length);
}

template <class CHAR_TYPE>
inline
void StringRefImp<CHAR_TYPE>::assign(const_iterator begin, const_iterator end)
{
    *this = StringRefImp(begin, end);
}

template <class CHAR_TYPE>
inline
void StringRefImp<CHAR_TYPE>::assign(const CHAR_TYPE *data)
{
    BSLS_ASSERT_SAFE(data);

    *this = StringRefImp(
                      data,
                      data + std::char_traits<CHAR_TYPE>::length(data));
}

template <class CHAR_TYPE>
inline
void StringRefImp<CHAR_TYPE>::assign(const bsl::basic_string<CHAR_TYPE>& str)
{
    *this = StringRefImp(str.data(), str.data() + str.length());
}

template <class CHAR_TYPE>
inline
void StringRefImp<CHAR_TYPE>::assign(const StringRefImp<CHAR_TYPE>& stringRef)
{
    *this = stringRef;
}

template <class CHAR_TYPE>
inline
void StringRefImp<CHAR_TYPE>::reset()
{
    *this = StringRefImp();
}

// ACCESSORS
template <class CHAR_TYPE>
inline
typename StringRefImp<CHAR_TYPE>::const_reference
StringRefImp<CHAR_TYPE>::operator[](size_type index) const
{
    BSLS_ASSERT_SAFE(index < length());

    return begin()[index];
}

}  // close package namespace

template <class CHAR_TYPE>
inline
bslstl::StringRefImp<CHAR_TYPE>::operator std::basic_string<CHAR_TYPE>() const
{
    return std::basic_string<CHAR_TYPE>(begin(), end());
}

namespace bslstl {

template <class CHAR_TYPE>
inline
typename StringRefImp<CHAR_TYPE>::const_iterator
    StringRefImp<CHAR_TYPE>::begin() const
{
    return Base::data();
}

template <class CHAR_TYPE>
inline
typename StringRefImp<CHAR_TYPE>::const_iterator
    StringRefImp<CHAR_TYPE>::end() const
{
    return Base::data() + Base::size();
}

template <class CHAR_TYPE>
inline
typename StringRefImp<CHAR_TYPE>::const_reverse_iterator
    StringRefImp<CHAR_TYPE>::rbegin() const
{
    return const_reverse_iterator(end());
}

template <class CHAR_TYPE>
inline
typename StringRefImp<CHAR_TYPE>::const_reverse_iterator
    StringRefImp<CHAR_TYPE>::rend() const
{
    return const_reverse_iterator(begin());
}

template <class CHAR_TYPE>
inline
const CHAR_TYPE *StringRefImp<CHAR_TYPE>::data() const
{
    return begin();
}

template <class CHAR_TYPE>
inline
bool StringRefImp<CHAR_TYPE>::empty() const
{
    return begin() == end();
}

template <class CHAR_TYPE>
inline
bool StringRefImp<CHAR_TYPE>::isEmpty() const
{
    return begin() == end();
}

template <class CHAR_TYPE>
inline
typename StringRefImp<CHAR_TYPE>::size_type
    StringRefImp<CHAR_TYPE>::length() const
{
    return end() - begin();
}

template <class CHAR_TYPE>
inline
typename StringRefImp<CHAR_TYPE>::size_type
    StringRefImp<CHAR_TYPE>::size() const
{
    return end() - begin();
}

template <class CHAR_TYPE>
inline
int StringRefImp<CHAR_TYPE>::compare(
                                    const StringRefImp<CHAR_TYPE>& other) const
{
    // Note that, on some platforms but not others, if 'CHAR_TYPE' is signed,
    // char_traits<CHAR_TYPE>::compare' casts the chars to their equivalent
    // sized unsigned type before comparing them.

    int result = std::char_traits<CHAR_TYPE>::compare(
                    this->data(),
                    other.data(),
                    std::min(this->length(), other.length()));

    if (result == 0 && this->length() != other.length()) {
        result = this->length() < other.length() ? -1 : 1;
    }
    return result;
}

                          // ------------------------------
                          // class StringRefImp_CompareUtil
                          // ------------------------------

template <class CHAR_TYPE>
int StringRefImp_CompareUtil::compare(const StringRefImp<CHAR_TYPE>&  a,
                                      const CHAR_TYPE                *b)
{
    // Not inline.

    typedef typename StringRefImp<CHAR_TYPE>::const_iterator const_iterator;

    // Imitate the behavior of the other 'StringRefImp::compare' and
    // 'basic_string::privateCompareRaw' -- if one string is shorter, but they
    // match up to that point, the longer string is always greater, even if the
    // next character of the longer string has a negative value.

    const const_iterator end = a.end();
    for (const_iterator pc = a.begin(); pc < end; ++pc, ++b) {
        if (0 == *b) {
            return +1;                                                // RETURN
        }

        if (*pc != *b) {
            // 'std::char_traits::compare' is a mess, usually
            // implemented with specialized templates, with behavior that
            // varies tremendously depending upon the platform, the compiler,
            // and 'CHAR_TYPE'.  In theory, it should compare individual
            // characters with 'std::char_traits::lt', but in practice
            // that's very often not the case.  Attempting to exactly
            // anticipate its behavior under all circumstances quickly turned
            // into a hopeless, brittle horror show of '#ifdef's and template
            // programming.  So we delegate directly to
            // 'std::char_traits::compare' to compare individual
            // characters known to differ, guaranteeing that compares between
            // 'basic_string's, 'StringRefImp's, and null-terminated 'const
            // CHAR_TYPE *'s all yield matching results.

            return std::char_traits<CHAR_TYPE>::compare(pc,
                                                        b,
                                                        1);           // RETURN
        }
    }

    return *b ? -1 : 0;
}

template <class CHAR_TYPE>
inline
bool StringRefImp_CompareUtil::compareEqual(const StringRefImp<CHAR_TYPE>& a,
                                            const StringRefImp<CHAR_TYPE>& b)
{
    return a.length() == b.length() &&
           (0 == a.length() ||
            0 == std::memcmp(
                     a.data(), b.data(), a.length() * sizeof(CHAR_TYPE)));
}

template <class CHAR_TYPE>
bool StringRefImp_CompareUtil::compareEqual(const StringRefImp<CHAR_TYPE>&  a,
                                            const CHAR_TYPE                *b)
{
    // Not inline.

    typedef typename StringRefImp<CHAR_TYPE>::const_iterator const_iterator;

    const const_iterator end = a.end();
    CHAR_TYPE            c   = *b;
    for (const_iterator pc = a.begin(); pc < end; ++pc, c = *++b) {
        if (0 == c || *pc != c) {
            return false;                                             // RETURN
        }
    }

    return 0 == c;
}

}  // close package namespace

template <class CHAR_TYPE>
bsl::basic_string<CHAR_TYPE>
bslstl::operator+(const StringRefImp<CHAR_TYPE>& lhs,
                  const StringRefImp<CHAR_TYPE>& rhs)
{
    bsl::basic_string<CHAR_TYPE> result;

    result.reserve(lhs.length() + rhs.length());
    result.assign(lhs.begin(), lhs.end());
    result.append(rhs.begin(), rhs.end());

    return result;
}

template <class CHAR_TYPE>
inline
bsl::basic_string<CHAR_TYPE>
bslstl::operator+(const bsl::basic_string<CHAR_TYPE>& lhs,
                  const StringRefImp<CHAR_TYPE>&      rhs)
{
    return StringRefImp<CHAR_TYPE>(lhs) + rhs;
}

template <class CHAR_TYPE>
inline
bsl::basic_string<CHAR_TYPE>
bslstl::operator+(const StringRefImp<CHAR_TYPE>&      lhs,
                  const bsl::basic_string<CHAR_TYPE>& rhs)
{
    return lhs + StringRefImp<CHAR_TYPE>(rhs);
}

template <class CHAR_TYPE>
inline
bsl::basic_string<CHAR_TYPE>
bslstl::operator+(const std::basic_string<CHAR_TYPE>& lhs,
                  const StringRefImp<CHAR_TYPE>&      rhs)
{
    return StringRefImp<CHAR_TYPE>(lhs) + rhs;
}

template <class CHAR_TYPE>
inline
bsl::basic_string<CHAR_TYPE>
bslstl::operator+(const StringRefImp<CHAR_TYPE>&      lhs,
                  const std::basic_string<CHAR_TYPE>& rhs)
{
    return lhs + StringRefImp<CHAR_TYPE>(rhs);
}

template <class CHAR_TYPE>
inline
bsl::basic_string<CHAR_TYPE>
bslstl::operator+(const CHAR_TYPE                *lhs,
                  const StringRefImp<CHAR_TYPE>&  rhs)
{
    // We have to traverse 'lhs' to know how much space to allocate in the
    // result anyway, so best to build a 'StringRefImp' from it.

    return StringRefImp<CHAR_TYPE>(lhs) + rhs;
}

template <class CHAR_TYPE>
inline
bsl::basic_string<CHAR_TYPE>
bslstl::operator+(const StringRefImp<CHAR_TYPE>&  lhs,
                  const CHAR_TYPE                *rhs)
{
    // We have to traverse 'rhs' to know how much space to allocate in the
    // result anyway, so best to build a 'StringRefImp' from it.

    return lhs + StringRefImp<CHAR_TYPE>(rhs);
}

template <class CHAR_TYPE, class HASHALG>
inline
void bslstl::hashAppend(HASHALG&                       hashAlg,
                        const StringRefImp<CHAR_TYPE>& input)
{
    using ::BloombergLP::bslh::hashAppend;
    hashAlg(input.data(), sizeof(CHAR_TYPE)*input.length());
    hashAppend(hashAlg, input.length());
}

#if defined(BSLS_COMPILERFEATURES_SUPPORT_EXTERN_TEMPLATE)
namespace bslstl {
extern template class bslstl::StringRefImp<char>;
extern template class bslstl::StringRefImp<wchar_t>;

extern template
bsl::basic_string<char>
operator+(const StringRefImp<char>& lhs, const StringRefImp<char>& rhs);

extern template
bsl::basic_string<wchar_t>
operator+(const StringRefImp<wchar_t>& lhs, const StringRefImp<wchar_t>& rhs);

}  // close package namespace
#endif
}  // close enterprise namespace

#ifndef BDE_OPENSOURCE_PUBLICATION  // BACKWARD_COMPATIBILITY
// ============================================================================
//                           BACKWARD COMPATIBILITY
// ============================================================================

#ifdef bslstl_StringRefImp
#undef bslstl_StringRefImp
#endif
#define bslstl_StringRefImp bslstl::StringRefImp
    // This alias is defined for backward compatibility.

#ifdef bslstl_StringRefWide
#undef bslstl_StringRefWide
#endif
#define bslstl_StringRefWide bslstl::StringRefWide
    // This alias is defined for backward compatibility.

#ifdef bslstl_StringRef
#undef bslstl_StringRef
#endif
#define bslstl_StringRef bslstl::StringRef
    // This alias is defined for backward compatibility.
#endif  // BDE_OPENSOURCE_PUBLICATION -- BACKWARD_COMPATIBILITY


#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 ----------------------------------