///\file

/******************************************************************************
The MIT License(MIT)

Embedded Template Library.
https://github.com/ETLCPP/etl
https://www.etlcpp.com

Copyright(c) 2017 John Wellbelove

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files(the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions :

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
******************************************************************************/

#ifndef ETL_STRING_VIEW_INCLUDED
#define ETL_STRING_VIEW_INCLUDED

#include "platform.h"
#include "algorithm.h"
#include "basic_string.h"
#include "char_traits.h"
#include "error_handler.h"
#include "exception.h"
#include "hash.h"
#include "integral_limits.h"
#include "iterator.h"
#include "memory.h"
#include "private/minmax_push.h"

#if ETL_USING_STL && ETL_USING_CPP17
  #include <string_view>
#endif

#if ETL_USING_STD_OSTREAM
  #include <ostream>
#endif

#include <stdint.h>

namespace etl
{
  //***************************************************************************
  /// The base class for basic_string_view exceptions.
  //***************************************************************************
  class string_view_exception : public exception
  {
  public:

    string_view_exception(string_type reason_, string_type file_name_, numeric_type line_number_)
      : exception(reason_, file_name_, line_number_)
    {
    }
  };

  //***************************************************************************
  ///\ingroup string
  /// The exception thrown when the index is out of bounds.
  //***************************************************************************
  class string_view_bounds : public string_view_exception
  {
  public:

    string_view_bounds(string_type file_name_, numeric_type line_number_)
      : string_view_exception(ETL_ERROR_TEXT("basic_string_view:bounds", ETL_STRING_VIEW_FILE_ID"A"), file_name_, line_number_)
    {
    }
  };

  //***************************************************************************
  ///\ingroup string
  /// The exception thrown when the view is uninitialised.
  //***************************************************************************
  class string_view_uninitialised : public string_view_exception
  {
  public:

    string_view_uninitialised(string_type file_name_, numeric_type line_number_)
      : string_view_exception(ETL_ERROR_TEXT("basic_string_view:uninitialised", ETL_STRING_VIEW_FILE_ID"B"), file_name_, line_number_)
    {
    }
  };

  //***************************************************************************
  /// The exception thrown when the view is empty.
  //***************************************************************************
  class string_view_empty : public string_view_exception
  {
  public:

    string_view_empty(string_type file_name_, numeric_type line_number_)
      : string_view_exception(ETL_ERROR_TEXT("basic_string_view:empty", ETL_STRING_VIEW_FILE_ID"C"), file_name_, line_number_)
    {
    }
  };

  //***************************************************************************
  /// String view.
  //***************************************************************************
  template <typename T, typename TTraits = etl::char_traits<T> >
  class basic_string_view
  {
  public:

    typedef T                                            value_type;
    typedef TTraits                                      traits_type;
    typedef size_t                                       size_type;
    typedef T&                                           reference;
    typedef const T&                                     const_reference;
    typedef T*                                           pointer;
    typedef const T*                                     const_pointer;
    typedef const T*                                     iterator;
    typedef const T*                                     const_iterator;
    typedef ETL_OR_STD::reverse_iterator<const_iterator> const_reverse_iterator;

    enum
    {
      npos = etl::integral_limits<size_t>::max
    };

    //*************************************************************************
    /// Default constructor.
    //*************************************************************************
    ETL_CONSTEXPR basic_string_view() ETL_NOEXCEPT
      : mbegin(ETL_NULLPTR)
      , mend(ETL_NULLPTR)
    {
    }

    //*************************************************************************
    /// Construct from string.
    //*************************************************************************
    ETL_CONSTEXPR basic_string_view(const etl::ibasic_string<T>& str) ETL_NOEXCEPT
      : mbegin(str.begin())
      , mend(str.end())
    {
    }

    //*************************************************************************
    /// Construct from T*.
    //*************************************************************************
    ETL_CONSTEXPR14 ETL_EXPLICIT_STRING_FROM_CHAR basic_string_view(const T* begin_) ETL_NOEXCEPT
      : mbegin(begin_)
      , mend(begin_ + TTraits::length(begin_))
    {
    }

    //*************************************************************************
    /// Construct from pointer range.
    //*************************************************************************
    ETL_CONSTEXPR basic_string_view(const T* begin_, const T* end_) ETL_NOEXCEPT
      : mbegin(begin_)
      , mend(end_)
    {
    }

    //*************************************************************************
    /// Construct from pointer/size.
    //*************************************************************************
    ETL_CONSTEXPR basic_string_view(const T* begin_, size_t size_) ETL_NOEXCEPT
      : mbegin(begin_)
      , mend(begin_ + size_)
    {
    }

    //*************************************************************************
    /// Copy constructor
    //*************************************************************************
    ETL_CONSTEXPR basic_string_view(const basic_string_view& other) ETL_NOEXCEPT
      : mbegin(other.mbegin)
      , mend(other.mend)
    {
    }

    //*************************************************************************
    /// Returns a const reference to the first element.
    /// If asserts or exceptions are enabled, throws an etl::string_view_empty
    /// if the view is empty.
    //*************************************************************************
    ETL_CONSTEXPR const_reference front() const
    {
#if ETL_USING_CPP11 && ETL_NOT_USING_CPP14 && ETL_USING_EXCEPTIONS && ETL_CHECKING_EXTRA
      return !empty() ? *mbegin : throw(ETL_ERROR(string_view_empty));
#else
      ETL_ASSERT_CHECK_EXTRA(!empty(), ETL_ERROR(string_view_empty));
      return *mbegin;
#endif
    }

    //*************************************************************************
    /// Returns a const reference to the last element.
    /// If asserts or exceptions are enabled, throws an etl::string_view_empty
    /// if the view is empty.
    //*************************************************************************
    ETL_CONSTEXPR const_reference back() const
    {
#if ETL_USING_CPP11 && ETL_NOT_USING_CPP14 && ETL_USING_EXCEPTIONS && ETL_CHECKING_EXTRA
      return !empty() ? *(mend - 1) : throw(ETL_ERROR(string_view_empty));
#else
      ETL_ASSERT_CHECK_EXTRA(!empty(), ETL_ERROR(string_view_empty));
      return *(mend - 1);
#endif
    }

    //*************************************************************************
    /// Returns a const pointer to the first element of the internal storage.
    //*************************************************************************
    ETL_CONSTEXPR const_pointer data() const ETL_NOEXCEPT
    {
      return mbegin;
    }

    //*************************************************************************
    /// Returns a const iterator to the beginning of the array.
    //*************************************************************************
    ETL_CONSTEXPR const_iterator begin() const ETL_NOEXCEPT
    {
      return mbegin;
    }

    //*************************************************************************
    /// Returns a const iterator to the beginning of the array.
    //*************************************************************************
    ETL_CONSTEXPR const_iterator cbegin() const ETL_NOEXCEPT
    {
      return mbegin;
    }

    //*************************************************************************
    /// Returns a const iterator to the end of the array.
    //*************************************************************************
    ETL_CONSTEXPR const_iterator end() const ETL_NOEXCEPT
    {
      return mend;
    }

    //*************************************************************************
    // Returns a const iterator to the end of the array.
    //*************************************************************************
    ETL_CONSTEXPR const_iterator cend() const ETL_NOEXCEPT
    {
      return mend;
    }

    //*************************************************************************
    /// Returns a const reverse iterator to the reverse beginning of the array.
    //*************************************************************************
    ETL_CONSTEXPR const_reverse_iterator rbegin() const ETL_NOEXCEPT
    {
      return const_reverse_iterator(mend);
    }

    //*************************************************************************
    /// Returns a const reverse iterator to the reverse beginning of the array.
    //*************************************************************************
    ETL_CONSTEXPR const_reverse_iterator crbegin() const ETL_NOEXCEPT
    {
      return const_reverse_iterator(mend);
    }

    //*************************************************************************
    /// Returns a const reverse iterator to the end of the array.
    //*************************************************************************
    ETL_CONSTEXPR const_reverse_iterator rend() const ETL_NOEXCEPT
    {
      return const_reverse_iterator(mbegin);
    }

    //*************************************************************************
    /// Returns a const reverse iterator to the end of the array.
    //*************************************************************************
    ETL_CONSTEXPR const_reverse_iterator crend() const ETL_NOEXCEPT
    {
      return const_reverse_iterator(mbegin);
    }

    //*************************************************************************
    // Capacity
    //*************************************************************************

    //*************************************************************************
    /// Returns <b>true</b> if the array size is zero.
    //*************************************************************************
    ETL_CONSTEXPR bool empty() const ETL_NOEXCEPT
    {
      return (mbegin == mend);
    }

    //*************************************************************************
    /// Returns the size of the array.
    //*************************************************************************
    ETL_CONSTEXPR size_t size() const ETL_NOEXCEPT
    {
      return static_cast<size_t>(mend - mbegin);
    }

    //*************************************************************************
    /// Returns the size of the array.
    //*************************************************************************
    ETL_CONSTEXPR size_t length() const ETL_NOEXCEPT
    {
      return size();
    }

    //*************************************************************************
    /// Returns the maximum possible size of the array.
    //*************************************************************************
    ETL_CONSTEXPR size_t max_size() const ETL_NOEXCEPT
    {
      return size();
    }

    //*************************************************************************
    /// Assign from a view.
    //*************************************************************************
    ETL_CONSTEXPR14 etl::basic_string_view<T, TTraits>& operator=(const etl::basic_string_view<T, TTraits>& other) ETL_NOEXCEPT
    {
      mbegin = other.mbegin;
      mend   = other.mend;
      return *this;
    }

    //*************************************************************************
    /// Assign from iterators
    //*************************************************************************
    ETL_CONSTEXPR14 void assign(const_pointer begin_, const_pointer end_) ETL_NOEXCEPT
    {
      mbegin = begin_;
      mend   = end_;
    }

    //*************************************************************************
    /// Assign from iterator and size.
    //*************************************************************************
    ETL_CONSTEXPR14 void assign(const_pointer begin_, size_t size_) ETL_NOEXCEPT
    {
      mbegin = begin_;
      mend   = begin_ + size_;
    }

    //*************************************************************************
    /// Returns a const reference to the indexed value.
    /// If asserts or exceptions are enabled, throws an etl::string_view_bounds
    /// if the index is out of bounds.
    //*************************************************************************
    ETL_CONSTEXPR const_reference operator[](size_t i) const ETL_NOEXCEPT_EXPR(ETL_NOT_USING_EXCEPTIONS || ETL_NOT_CHECKING_INDEX_OPERATOR)
    {
#if ETL_USING_CPP11 && ETL_NOT_USING_CPP14 && ETL_USING_EXCEPTIONS && ETL_CHECKING_INDEX_OPERATOR
      return i < size() ? mbegin[i] : throw(ETL_ERROR(string_view_bounds));
#else
      ETL_ASSERT_CHECK_INDEX_OPERATOR(i < size(), ETL_ERROR(string_view_bounds));
      return mbegin[i];
#endif
    }

    //*************************************************************************
    /// Returns a const reference to the indexed value.
    //*************************************************************************
    const_reference at(size_t i) const
    {
      ETL_ASSERT((mbegin != ETL_NULLPTR && mend != ETL_NULLPTR), ETL_ERROR(string_view_uninitialised));
      ETL_ASSERT(i < size(), ETL_ERROR(string_view_bounds));
      return mbegin[i];
    }

    //*************************************************************************
    /// Swaps with another basic_string_view.
    //*************************************************************************
    ETL_CONSTEXPR14 void swap(basic_string_view& other) ETL_NOEXCEPT
    {
      using ETL_OR_STD::swap; // Allow ADL

      swap(mbegin, other.mbegin);
      swap(mend, other.mend);
    }

    //*************************************************************************
    /// Copies characters
    //*************************************************************************
    ETL_CONSTEXPR14 size_type copy(T* destination, size_type count, size_type position = 0) const ETL_NOEXCEPT
    {
      size_t n = 0UL;

      if (position < size())
      {
        n = etl::min(count, size() - position);

        etl::mem_copy(mbegin + position, n, destination);
      }

      return n;
    }

    //*************************************************************************
    /// Returns a substring
    //*************************************************************************
    ETL_CONSTEXPR14 basic_string_view substr(size_type position = 0, size_type count = npos) const ETL_NOEXCEPT
    {
      basic_string_view view = basic_string_view();

      if (position < size())
      {
        size_t n = etl::min(count, size() - position);

        view = basic_string_view(mbegin + position, mbegin + position + n);
      }

      return view;
    }

    //*************************************************************************
    /// Shrinks the view by moving its start forward.
    //*************************************************************************
    ETL_CONSTEXPR14 void remove_prefix(size_type n) ETL_NOEXCEPT
    {
      mbegin += n;
    }

    //*************************************************************************
    /// Shrinks the view by moving its end backward.
    //*************************************************************************
    ETL_CONSTEXPR14 void remove_suffix(size_type n) ETL_NOEXCEPT
    {
      mend -= n;
    }

    //*************************************************************************
    /// Compares two views
    //*************************************************************************
    ETL_CONSTEXPR14 int compare(basic_string_view<T, TTraits> view) const ETL_NOEXCEPT
    {
      return (*this == view) ? 0 : ((*this > view) ? 1 : -1);
    }

    ETL_CONSTEXPR14 int compare(size_type position, size_type count, basic_string_view view) const ETL_NOEXCEPT
    {
      return substr(position, count).compare(view);
    }

    ETL_CONSTEXPR14 int compare(size_type position1, size_type count1, basic_string_view view, size_type position2, size_type count2) const
      ETL_NOEXCEPT
    {
      return substr(position1, count1).compare(view.substr(position2, count2));
    }

    ETL_CONSTEXPR14 int compare(const T* text) const ETL_NOEXCEPT
    {
      const T* view_itr = mbegin;
      const T* text_itr = text;

      while (view_itr != mend && *text_itr != T(0))
      {
        if (*view_itr < *text_itr)
        {
          return -1;
        }
        else if (*view_itr > *text_itr)
        {
          return 1;
        }
        ++view_itr;
        ++text_itr;
      }

      if ((view_itr == mend) && (*text_itr == T(0)))
      {
        return 0;
      }
      else if (view_itr == mend)
      {
        return -1;
      }
      else
      {
        return 1;
      }
    }

    ETL_CONSTEXPR14 int compare(size_type position, size_type count, const T* text) const ETL_NOEXCEPT
    {
      return substr(position, count).compare(text);
    }

    ETL_CONSTEXPR14 int compare(size_type position, size_type count1, const T* text, size_type count2) const ETL_NOEXCEPT
    {
      return substr(position, count1).compare(etl::basic_string_view<T, TTraits>(text, count2));
    }

    //*************************************************************************
    /// Checks if the string view starts with the given prefix
    //*************************************************************************
    ETL_CONSTEXPR14 bool starts_with(etl::basic_string_view<T, TTraits> view) const ETL_NOEXCEPT
    {
      return (size() >= view.size()) && (compare(0, view.size(), view) == 0);
    }

    ETL_CONSTEXPR14 bool starts_with(T c) const ETL_NOEXCEPT
    {
      return !empty() && (front() == c);
    }

    ETL_CONSTEXPR14 bool starts_with(const T* text) const ETL_NOEXCEPT
    {
      size_t lengthtext = TTraits::length(text);

      return (size() >= lengthtext) && (compare(0, lengthtext, text) == 0);
    }

    //*************************************************************************
    /// Checks if the string view ends with the given suffix
    //*************************************************************************
    ETL_CONSTEXPR14 bool ends_with(etl::basic_string_view<T, TTraits> view) const ETL_NOEXCEPT
    {
      return (size() >= view.size()) && (compare(size() - view.size(), npos, view) == 0);
    }

    ETL_CONSTEXPR14 bool ends_with(T c) const
    {
      return !empty() && (back() == c);
    }

    ETL_CONSTEXPR14 bool ends_with(const T* text) const
    {
      size_t lengthtext = TTraits::length(text);
      size_t lengthview = size();

      return (lengthview >= lengthtext) && (compare(lengthview - lengthtext, lengthtext, text) == 0);
    }

    //*************************************************************************
    /// Find characters in the view
    //*************************************************************************
    ETL_CONSTEXPR14 size_type find(etl::basic_string_view<T, TTraits> view, size_type position = 0) const ETL_NOEXCEPT
    {
      if ((size() < view.size()))
      {
        return npos;
      }

      const_iterator iposition = etl::search(begin() + position, end(), view.begin(), view.end());

      if (iposition == end())
      {
        return npos;
      }
      else
      {
        return static_cast<size_type>(etl::distance(begin(), iposition));
      }
    }

    ETL_CONSTEXPR14 size_type find(T c, size_type position = 0) const ETL_NOEXCEPT
    {
      return find(etl::basic_string_view<T, TTraits>(&c, 1), position);
    }

    ETL_CONSTEXPR14 size_type find(const T* text, size_type position, size_type count) const ETL_NOEXCEPT
    {
      return find(etl::basic_string_view<T, TTraits>(text, count), position);
    }

    ETL_CONSTEXPR14 size_type find(const T* text, size_type position = 0) const ETL_NOEXCEPT
    {
      return find(etl::basic_string_view<T, TTraits>(text), position);
    }

    //*************************************************************************
    /// Find the last occurrence of a substring
    //*************************************************************************
    ETL_CONSTEXPR14 size_type rfind(etl::basic_string_view<T, TTraits> view, size_type position = npos) const ETL_NOEXCEPT
    {
      if ((size() < view.size()))
      {
        return npos;
      }

      position = etl::min(position, size());

      const_iterator iposition = etl::find_end(begin(), begin() + position, view.begin(), view.end());

      if (iposition == end())
      {
        return npos;
      }
      else
      {
        return static_cast<size_type>(etl::distance(begin(), iposition));
      }
    }

    ETL_CONSTEXPR14 size_type rfind(T c, size_type position = npos) const ETL_NOEXCEPT
    {
      return rfind(etl::basic_string_view<T, TTraits>(&c, 1), position);
    }

    ETL_CONSTEXPR14 size_type rfind(const T* text, size_type position, size_type count) const ETL_NOEXCEPT
    {
      return rfind(etl::basic_string_view<T, TTraits>(text, count), position);
    }

    ETL_CONSTEXPR14 size_type rfind(const T* text, size_type position = npos) const ETL_NOEXCEPT
    {
      return rfind(etl::basic_string_view<T, TTraits>(text), position);
    }

    //*************************************************************************
    ///  Find first occurrence of characters
    //*************************************************************************
    ETL_CONSTEXPR14 size_type find_first_of(etl::basic_string_view<T, TTraits> view, size_type position = 0) const ETL_NOEXCEPT
    {
      const size_t lengthtext = size();

      if (position < lengthtext)
      {
        for (size_t i = position; i < lengthtext; ++i)
        {
          const size_t lengthview = view.size();

          for (size_t j = 0UL; j < lengthview; ++j)
          {
            if (mbegin[i] == view[j])
            {
              return i;
            }
          }
        }
      }

      return npos;
    }

    ETL_CONSTEXPR14 size_type find_first_of(T c, size_type position = 0) const ETL_NOEXCEPT
    {
      return find_first_of(etl::basic_string_view<T, TTraits>(&c, 1), position);
    }

    ETL_CONSTEXPR14 size_type find_first_of(const T* text, size_type position, size_type count) const ETL_NOEXCEPT
    {
      return find_first_of(etl::basic_string_view<T, TTraits>(text, count), position);
    }

    ETL_CONSTEXPR14 size_type find_first_of(const T* text, size_type position = 0) const ETL_NOEXCEPT
    {
      return find_first_of(etl::basic_string_view<T, TTraits>(text), position);
    }

    //*************************************************************************
    /// Find last occurrence of characters
    //*************************************************************************
    ETL_CONSTEXPR14 size_type find_last_of(etl::basic_string_view<T, TTraits> view, size_type position = npos) const ETL_NOEXCEPT
    {
      if (empty())
      {
        return npos;
      }

      position = etl::min(position, size() - 1);

      const_reverse_iterator it = rbegin() + static_cast<ptrdiff_t>(size() - position - 1);

      while (it != rend())
      {
        const size_t viewlength = view.size();

        for (size_t j = 0UL; j < viewlength; ++j)
        {
          if (mbegin[position] == view[j])
          {
            return position;
          }
        }

        ++it;
        --position;
      }

      return npos;
    }

    ETL_CONSTEXPR14 size_type find_last_of(T c, size_type position = npos) const ETL_NOEXCEPT
    {
      return find_last_of(etl::basic_string_view<T, TTraits>(&c, 1), position);
    }

    ETL_CONSTEXPR14 size_type find_last_of(const T* text, size_type position, size_type count) const ETL_NOEXCEPT
    {
      return find_last_of(etl::basic_string_view<T, TTraits>(text, count), position);
    }

    ETL_CONSTEXPR14 size_type find_last_of(const T* text, size_type position = npos) const ETL_NOEXCEPT
    {
      return find_last_of(etl::basic_string_view<T, TTraits>(text), position);
    }

    //*************************************************************************
    /// Find first absence of characters
    //*************************************************************************
    ETL_CONSTEXPR14 size_type find_first_not_of(etl::basic_string_view<T, TTraits> view, size_type position = 0) const ETL_NOEXCEPT
    {
      const size_t lengthtext = size();

      if (position < lengthtext)
      {
        for (size_t i = position; i < lengthtext; ++i)
        {
          bool found = false;

          const size_t viewlength = view.size();

          for (size_t j = 0UL; j < viewlength; ++j)
          {
            if (mbegin[i] == view[j])
            {
              found = true;
              break;
            }
          }

          if (!found)
          {
            return i;
          }
        }
      }

      return npos;
    }

    ETL_CONSTEXPR14 size_type find_first_not_of(T c, size_type position = 0) const ETL_NOEXCEPT
    {
      return find_first_not_of(etl::basic_string_view<T, TTraits>(&c, 1), position);
    }

    ETL_CONSTEXPR14 size_type find_first_not_of(const T* text, size_type position, size_type count) const ETL_NOEXCEPT
    {
      return find_first_not_of(etl::basic_string_view<T, TTraits>(text, count), position);
    }

    ETL_CONSTEXPR14 size_type find_first_not_of(const T* text, size_type position = 0) const ETL_NOEXCEPT
    {
      return find_first_not_of(etl::basic_string_view<T, TTraits>(text), position);
    }

    //*************************************************************************
    /// Find last absence of characters
    //*************************************************************************
    ETL_CONSTEXPR14 size_type find_last_not_of(etl::basic_string_view<T, TTraits> view, size_type position = npos) const ETL_NOEXCEPT
    {
      if (empty())
      {
        return npos;
      }

      position = etl::min(position, size() - 1);

      const_reverse_iterator it = rbegin() + static_cast<ptrdiff_t>(size() - position - 1);

      while (it != rend())
      {
        bool found = false;

        const size_t viewlength = view.size();

        for (size_t j = 0UL; j < viewlength; ++j)
        {
          if (mbegin[position] == view[j])
          {
            found = true;
            break;
          }
        }

        if (!found)
        {
          return position;
        }

        ++it;
        --position;
      }

      return npos;
    }

    ETL_CONSTEXPR14 size_type find_last_not_of(T c, size_type position = npos) const ETL_NOEXCEPT
    {
      return find_last_not_of(etl::basic_string_view<T, TTraits>(&c, 1), position);
    }

    ETL_CONSTEXPR14 size_type find_last_not_of(const T* text, size_type position, size_type count) const ETL_NOEXCEPT
    {
      return find_last_not_of(etl::basic_string_view<T, TTraits>(text, count), position);
    }

    ETL_CONSTEXPR14 size_type find_last_not_of(const T* text, size_type position = npos) const ETL_NOEXCEPT
    {
      return find_last_not_of(etl::basic_string_view<T, TTraits>(text), position);
    }

    //*********************************************************************
    /// Checks that the view is within this string
    //*********************************************************************
    bool contains(const etl::basic_string_view<T, TTraits>& view) const ETL_NOEXCEPT
    {
      return find(view) != npos;
    }

    //*********************************************************************
    /// Checks that text is within this string
    //*********************************************************************
    bool contains(const_pointer s) const ETL_NOEXCEPT
    {
      return find(s) != npos;
    }

    //*********************************************************************
    /// Checks that character is within this string
    //*********************************************************************
    bool contains(value_type c) const ETL_NOEXCEPT
    {
      return find(c) != npos;
    }

    //*************************************************************************
    /// Equality for string_view.
    //*************************************************************************
    friend ETL_CONSTEXPR14 bool operator==(const etl::basic_string_view<T, TTraits>& lhs, const etl::basic_string_view<T, TTraits>& rhs)
    {
      return (lhs.size() == rhs.size()) && etl::equal(lhs.begin(), lhs.end(), rhs.begin());
    }

    //*************************************************************************
    /// Inequality for string_view.
    //*************************************************************************
    friend ETL_CONSTEXPR14 bool operator!=(const etl::basic_string_view<T, TTraits>& lhs, const etl::basic_string_view<T, TTraits>& rhs)
    {
      return !(lhs == rhs);
    }

    //*************************************************************************
    /// Less-than for string_view.
    //*************************************************************************
    friend ETL_CONSTEXPR14 bool operator<(const etl::basic_string_view<T, TTraits>& lhs, const etl::basic_string_view<T, TTraits>& rhs)
    {
      return etl::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
    }

    //*************************************************************************
    /// Greater-than for string_view.
    //*************************************************************************
    friend ETL_CONSTEXPR14 bool operator>(const etl::basic_string_view<T, TTraits>& lhs, const etl::basic_string_view<T, TTraits>& rhs)
    {
      return rhs < lhs;
    }

    //*************************************************************************
    /// Less-than-equal for string_view.
    //*************************************************************************
    friend ETL_CONSTEXPR14 bool operator<=(const etl::basic_string_view<T, TTraits>& lhs, const etl::basic_string_view<T, TTraits>& rhs)
    {
      return !(lhs > rhs);
    }

    //*************************************************************************
    /// Greater-than-equal for string_view.
    //*************************************************************************
    friend ETL_CONSTEXPR14 bool operator>=(const etl::basic_string_view<T, TTraits>& lhs, const etl::basic_string_view<T, TTraits>& rhs)
    {
      return !(lhs < rhs);
    }

  private:

    const_pointer mbegin;
    const_pointer mend;
  };

  typedef etl::basic_string_view<char>     string_view;
  typedef etl::basic_string_view<wchar_t>  wstring_view;
  typedef etl::basic_string_view<char8_t>  u8string_view;
  typedef etl::basic_string_view<char16_t> u16string_view;
  typedef etl::basic_string_view<char32_t> u32string_view;

  //*************************************************************************
  /// make_string_view.
  //*************************************************************************
  template <size_t Array_Size>
  ETL_CONSTEXPR14 string_view make_string_view(const char (&text)[Array_Size]) ETL_NOEXCEPT
  {
    size_t length = etl::char_traits<char>::length(text, Array_Size - 1U);

    return string_view(text, length);
  }

  //***********************************
  template <size_t Array_Size>
  ETL_CONSTEXPR14 wstring_view make_string_view(const wchar_t (&text)[Array_Size]) ETL_NOEXCEPT
  {
    size_t length = etl::char_traits<wchar_t>::length(text, Array_Size - 1U);

    return wstring_view(text, length);
  }

  //***********************************
  template <size_t Array_Size>
  ETL_CONSTEXPR14 u8string_view make_string_view(const char8_t (&text)[Array_Size]) ETL_NOEXCEPT
  {
    size_t length = etl::char_traits<char8_t>::length(text, Array_Size - 1U);

    return u8string_view(text, length);
  }

  //***********************************
  template <size_t Array_Size>
  ETL_CONSTEXPR14 u16string_view make_string_view(const char16_t (&text)[Array_Size]) ETL_NOEXCEPT
  {
    size_t length = etl::char_traits<char16_t>::length(text, Array_Size - 1U);

    return u16string_view(text, length);
  }

  //***********************************
  template <size_t Array_Size>
  ETL_CONSTEXPR14 u32string_view make_string_view(const char32_t (&text)[Array_Size]) ETL_NOEXCEPT
  {
    size_t length = etl::char_traits<char32_t>::length(text, Array_Size - 1U);

    return u32string_view(text, length);
  }

  //*************************************************************************
  /// Hash function.
  //*************************************************************************
#if ETL_USING_8BIT_TYPES
  template <>
  struct hash<etl::string_view>
  {
    size_t operator()(const etl::string_view& text) const
    {
      return etl::private_hash::generic_hash<size_t>(reinterpret_cast<const uint8_t*>(text.data()),
                                                     reinterpret_cast<const uint8_t*>(text.data() + text.size()));
    }
  };

  template <>
  struct hash<etl::wstring_view>
  {
    size_t operator()(const etl::wstring_view& text) const
    {
      return etl::private_hash::generic_hash<size_t>(reinterpret_cast<const uint8_t*>(text.data()),
                                                     reinterpret_cast<const uint8_t*>(text.data() + text.size()));
    }
  };

  template <>
  struct hash<etl::u16string_view>
  {
    size_t operator()(const etl::u16string_view& text) const
    {
      return etl::private_hash::generic_hash<size_t>(reinterpret_cast<const uint8_t*>(text.data()),
                                                     reinterpret_cast<const uint8_t*>(text.data() + text.size()));
    }
  };

  template <>
  struct hash<etl::u32string_view>
  {
    size_t operator()(const etl::u32string_view& text) const
    {
      return etl::private_hash::generic_hash<size_t>(reinterpret_cast<const uint8_t*>(text.data()),
                                                     reinterpret_cast<const uint8_t*>(text.data() + text.size()));
    }
  };
#endif
} // namespace etl

//*************************************************************************
/// Swaps the values.
//*************************************************************************
template <typename T, typename TTraits >
void swap(etl::basic_string_view<T, TTraits>& lhs, etl::basic_string_view<T, TTraits>& rhs) ETL_NOEXCEPT
{
  lhs.swap(rhs);
}

template <typename T>
void swap(etl::basic_string_view<T, etl::char_traits<T> >& lhs, etl::basic_string_view<T, etl::char_traits<T> >& rhs) ETL_NOEXCEPT
{
  lhs.swap(rhs);
}

//*************************************************************************
/// Operator overload to write to std basic_ostream
//*************************************************************************
#if ETL_USING_STD_OSTREAM
template <typename T>
std::basic_ostream<T, std::char_traits<T> >& operator<<(std::basic_ostream<T, std::char_traits<T> >&    os,
                                                        etl::basic_string_view<T, etl::char_traits<T> > text)
{
  os.write(text.data(), static_cast<std::streamsize>(text.size()));
  return os;
}
#endif

#include "private/minmax_pop.h"

#endif
