//
// Copyright (c) 2015 Arthur O'Dwyer
// Copyright 2017-2018 by Martin Moene
//
// https://github.com/martinmoene/ring-span-lite
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)

#pragma once

#ifndef NONSTD_RING_SPAN_LITE_HPP
#    define NONSTD_RING_SPAN_LITE_HPP

#    define ring_span_lite_MAJOR 0
#    define ring_span_lite_MINOR 2
#    define ring_span_lite_PATCH 0

#    define ring_span_lite_VERSION \
        nsrs_STRINGIFY(ring_span_lite_MAJOR) "." nsrs_STRINGIFY( \
            ring_span_lite_MINOR) "." nsrs_STRINGIFY(ring_span_lite_PATCH)

#    define nsrs_STRINGIFY(x)  nsrs_STRINGIFY_(x)
#    define nsrs_STRINGIFY_(x) #    x

// ring-span-lite configuration:

#    define nsrs_RING_SPAN_DEFAULT 0
#    define nsrs_RING_SPAN_NONSTD  1
#    define nsrs_RING_SPAN_STD     2

#    if !defined(nsrs_CONFIG_SELECT_RING_SPAN)
#        define nsrs_CONFIG_SELECT_RING_SPAN \
            (nsrs_HAVE_STD_RING_SPAN ? nsrs_RING_SPAN_STD \
                                     : nsrs_RING_SPAN_NONSTD)
#    endif

#    ifndef nsrs_CONFIG_STRICT_P0059
#        define nsrs_CONFIG_STRICT_P0059 0
#    endif

#    define nsrs_RING_SPAN_LITE_EXTENSION (!nsrs_CONFIG_STRICT_P0059)

#    ifndef nsrs_CONFIG_CONFIRMS_COMPILATION_ERRORS
#        define nsrs_CONFIG_CONFIRMS_COMPILATION_ERRORS 0
#    endif

// C++ language version detection (C++20 is speculative):
// Note: VC14.0/1900 (VS2015) lacks too much from C++14.

#    ifndef nsrs_CPLUSPLUS
#        if defined(_MSVC_LANG) && !defined(__clang__)
#            define nsrs_CPLUSPLUS (_MSC_VER == 1900 ? 201103L : _MSVC_LANG)
#        else
#            define nsrs_CPLUSPLUS __cplusplus
#        endif
#    endif

#    define nsrs_CPP98_OR_GREATER  (nsrs_CPLUSPLUS >= 199711L)
#    define nsrs_CPP11_OR_GREATER  (nsrs_CPLUSPLUS >= 201103L)
#    define nsrs_CPP11_OR_GREATER_ (nsrs_CPLUSPLUS >= 201103L)
#    define nsrs_CPP14_OR_GREATER  (nsrs_CPLUSPLUS >= 201402L)
#    define nsrs_CPP17_OR_GREATER  (nsrs_CPLUSPLUS >= 201703L)
#    define nsrs_CPP20_OR_GREATER  (nsrs_CPLUSPLUS >= 202000L)

// Use C++XX std::ring_span if available and requested:

#    define nsrs_HAVE_STD_RING_SPAN 0

//#if nsrs_CPP17_OR_GREATER && defined(__has_include )
//# if __has_include( <any> )
//#  define nsrs_HAVE_STD_RING_SPAN  1
//# else
//#  define nsrs_HAVE_STD_RING_SPAN  0
//# endif
//#else
//# define  nsrs_HAVE_STD_RING_SPAN  0
//#endif

#    define nsrs_USES_STD_RING_SPAN \
        ((nsrs_CONFIG_SELECT_RING_SPAN == nsrs_RING_SPAN_STD) \
         || ((nsrs_CONFIG_SELECT_RING_SPAN == nsrs_RING_SPAN_DEFAULT) \
             && nsrs_HAVE_STD_RING_SPAN))

// Compiler versions:
//
// MSVC++ 6.0  _MSC_VER == 1200 (Visual Studio 6.0)
// MSVC++ 7.0  _MSC_VER == 1300 (Visual Studio .NET 2002)
// MSVC++ 7.1  _MSC_VER == 1310 (Visual Studio .NET 2003)
// MSVC++ 8.0  _MSC_VER == 1400 (Visual Studio 2005)
// MSVC++ 9.0  _MSC_VER == 1500 (Visual Studio 2008)
// MSVC++ 10.0 _MSC_VER == 1600 (Visual Studio 2010)
// MSVC++ 11.0 _MSC_VER == 1700 (Visual Studio 2012)
// MSVC++ 12.0 _MSC_VER == 1800 (Visual Studio 2013)
// MSVC++ 14.0 _MSC_VER == 1900 (Visual Studio 2015)
// ............_MSVC_LANG: 201402 for -std:c++14, default
// MSVC++ 14.1 _MSC_VER >= 1910 (Visual Studio 2017)
// ............_MSVC_LANG: 201402 for -std:c++14, default
// ............_MSVC_LANG: 201703 for -std:c++17

#    if defined(_MSC_VER) && !defined(__clang__)
#        define nsrs_COMPILER_MSVC_VER (_MSC_VER)
#        define nsrs_COMPILER_MSVC_VERSION \
            (_MSC_VER / 10 - 10 * (5 + (_MSC_VER < 1900)))
#    else
#        define nsrs_COMPILER_MSVC_VER     0
#        define nsrs_COMPILER_MSVC_VERSION 0
#    endif

#    define nsrs_COMPILER_VERSION(major, minor, patch) \
        (10 * (10 * major + minor) + patch)

#    if defined(__clang__)
#        define nsrs_COMPILER_CLANG_VERSION \
            nsrs_COMPILER_VERSION( \
                __clang_major__, __clang_minor__, __clang_patchlevel__)
#    else
#        define nsrs_COMPILER_CLANG_VERSION 0
#    endif

#    if defined(__GNUC__) && !defined(__clang__)
#        define nsrs_COMPILER_GNUC_VERSION \
            nsrs_COMPILER_VERSION(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__)
#    else
#        define nsrs_COMPILER_GNUC_VERSION 0
#    endif

// half-open range [lo..hi):
//#define nsrs_BETWEEN( v, lo, hi ) ( (lo) <= (v) && (v) < (hi) )

// Presence of language and library features:

#    ifdef _HAS_CPP0X
#        define nsrs_HAS_CPP0X _HAS_CPP0X
#    else
#        define nsrs_HAS_CPP0X 0
#    endif

// Unless defined otherwise below, consider VC14 as C++11 for ring-span-lite:

#    if nsrs_COMPILER_MSVC_VER >= 1900
#        undef nsrs_CPP11_OR_GREATER
#        define nsrs_CPP11_OR_GREATER 1
#    endif

#    define nsrs_CPP11_90 \
        (nsrs_CPP11_OR_GREATER_ || nsrs_COMPILER_MSVC_VER >= 1500)
#    define nsrs_CPP11_100 \
        (nsrs_CPP11_OR_GREATER_ || nsrs_COMPILER_MSVC_VER >= 1600)
#    define nsrs_CPP11_110 \
        (nsrs_CPP11_OR_GREATER_ || nsrs_COMPILER_MSVC_VER >= 1700)
#    define nsrs_CPP11_120 \
        (nsrs_CPP11_OR_GREATER_ || nsrs_COMPILER_MSVC_VER >= 1800)
#    define nsrs_CPP11_140 \
        (nsrs_CPP11_OR_GREATER_ || nsrs_COMPILER_MSVC_VER >= 1900)

#    define nsrs_CPP14_000 (nsrs_CPP14_OR_GREATER)
#    define nsrs_CPP17_000 (nsrs_CPP17_OR_GREATER)

// Presence of C++11 language features:

// half-open range [lo..hi):
#    define nsrs_BETWEEN(v, lo, hi) ((lo) <= (v) && (v) < (hi))

// Presence of C++11 language features:

#    define nsrs_HAVE_CONSTEXPR_11 nsrs_CPP11_140
#    define nsrs_HAVE_IS_DEFAULT   nsrs_CPP11_140
#    define nsrs_HAVE_IS_DELETE    nsrs_CPP11_140
#    define nsrs_HAVE_NOEXCEPT     nsrs_CPP11_140
#    define nsrs_HAVE_NULLPTR      nsrs_CPP11_100

// Presence of C++14 language features:

#    define nsrs_HAVE_CONSTEXPR_14 nsrs_CPP14_000

// Presence of C++17 language features:
// no tag

// Presence of C++ library features:
// no tag

// Compiler warning suppression:

#    if defined(__clang__)
#        pragma clang diagnostic push
#        pragma clang diagnostic ignored "-Wundef"
#        define nsrs_RESTORE_WARNINGS() _Pragma("clang diagnostic pop")

#    elif defined __GNUC__
#        pragma GCC diagnostic push
#        pragma GCC diagnostic ignored "-Wundef"
#        define nsrs_RESTORE_WARNINGS() _Pragma("GCC diagnostic pop")

#    elif nsrs_COMPILER_MSVC_VERSION >= 140
#        define nsrs_DISABLE_MSVC_WARNINGS(codes) \
            __pragma(warning(push)) __pragma(warning(disable : codes))
#        define nsrs_RESTORE_WARNINGS() __pragma(warning(pop))

// Suppress the following MSVC warnings:
// - C4345: initialization behavior changed
//
// Suppress the following MSVC GSL warnings:
// - C26439, gsl::f.6 : special function 'function' can be declared 'noexcept'
// - C26440, gsl::f.6 : function 'function' can be declared 'noexcept'
// - C26472, gsl::t.1 : don't use a static_cast for arithmetic conversions;
//                      use brace initialization, gsl::narrow_cast or
//                      gsl::narrow
// - C26473: gsl::t.1 : don't cast between pointer types where the source type
// and the target type are the same
// - C26481: gsl::b.1 : don't use pointer arithmetic. Use span instead
// - C26490: gsl::t.1 : don't use reinterpret_cast

nsrs_DISABLE_MSVC_WARNINGS(4345 26439 26440 26472 26473 26481 26490)

#    else
#        define nsrs_RESTORE_WARNINGS() /*empty*/
#    endif

// C++ feature usage:

#    if nsrs_HAVE_CONSTEXPR_11
#        define nsrs_constexpr constexpr
#    else
#        define nsrs_constexpr /*constexpr*/
#    endif

#    if nsrs_HAVE_CONSTEXPR_14
#        define nsrs_constexpr14 constexpr
#    else
#        define nsrs_constexpr14 /*constexpr*/
#    endif

#    if nsrs_HAVE_NOEXCEPT
#        define nsrs_noexcept    noexcept
#        define nsrs_noexcept_op noexcept
#    else
#        define nsrs_noexcept          /*noexcept*/
#        define nsrs_noexcept_op(expr) /*noexcept(expr)*/
#    endif

#    if nsrs_HAVE_NULLPTR
#        define nsrs_nullptr nullptr
#    else
#        define nsrs_nullptr NULL
#    endif

// includes:

#    include <cassert>
#    include <iterator>
#    include <utility>

// additional includes:

#    if !nsrs_CPP11_OR_GREATER
#        include <algorithm>  // std::swap() until C++11
#    endif

namespace nonstd {

#    if nsrs_CPP11_OR_GREATER
using std::move;
#    else
template<typename T>
T const&
move(T const& t)
{
    return t;
}
#    endif

template<bool B, class T, class F>
struct conditional {
    typedef T type;
};

template<class T, class F>
struct conditional<false, T, F> {
    typedef F type;
};

#    if nsrs_CPP11_OR_GREATER

template<bool B, class T, class F>
using conditional_t = typename conditional<B, T, F>::type;

template<bool B, class T = void>
using enable_if_t = typename std::enable_if<B, T>::type;

#    endif

//
// element extraction policies:
//

template<class T>
struct null_popper {
    typedef void return_type;

    void operator()(T&) const nsrs_noexcept {}
};

template<class T>
struct default_popper {
    typedef T return_type;

    T operator()(T& t) const
    {
        return nonstd::move(t);
    }
};

template<class T>
struct copy_popper {
    typedef T return_type;

#    if nsrs_RING_SPAN_LITE_EXTENSION
#        if nsrs_CPP11_OR_GREATER
    copy_popper(T t) : m_copy(std::move(t)) {}
#        else
    copy_popper(T const& t) : m_copy(t) {}
#        endif
#    else
    copy_popper(T&& t) : copy(std::move(t)) {}
#    endif

    T operator()(T& t) const
    {
        using std::swap;
        T result(m_copy);
        swap(t, result);
        return result;
    }

    T m_copy;
};

// forward-declare iterator:

namespace ring_detail {

template<class, bool>
class ring_iterator;

}

//
// ring span:
//
template<class T, class Popper = default_popper<T> >
class ring_span {
public:
    typedef T value_type;
    typedef T* pointer;
    typedef T& reference;
    typedef T const& const_reference;

    typedef std::size_t size_type;

    typedef ring_span<T, Popper> type;

    typedef ring_detail::ring_iterator<type, false> iterator;
    typedef ring_detail::ring_iterator<type, true> const_iterator;

#    if nsrs_RING_SPAN_LITE_EXTENSION
    typedef std::reverse_iterator<iterator> reverse_iterator;
    typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
#    endif

    // construction:

    template<class ContiguousIterator>
    ring_span(ContiguousIterator begin,
              ContiguousIterator end,
              Popper popper = Popper()) nsrs_noexcept
        : m_data(&*begin)
        , m_size(0)
        , m_capacity(static_cast<size_type>(end - begin))
        , m_front_idx(0)
        , m_popper(nonstd::move(popper))
    {
    }

    template<class ContiguousIterator>
    ring_span(ContiguousIterator begin,
              ContiguousIterator end,
              ContiguousIterator first,
              size_type size,
              Popper popper = Popper()) nsrs_noexcept
        : m_data(&*begin)
        , m_size(size)
        , m_capacity(static_cast<size_type>(end - begin))
        , m_front_idx(static_cast<size_type>(first - begin))
        , m_popper(nonstd::move(popper))
    {
    }

#    if nsrs_HAVE_IS_DEFAULT
    ring_span(ring_span&&) = default;
    ring_span& operator=(ring_span&&) = default;
#    else
private:
    ring_span(ring_span const&);
    ring_span& operator=(ring_span const&);

public:
#    endif

    // observers:

    bool empty() const nsrs_noexcept
    {
        return m_size == 0;
    }

    bool full() const nsrs_noexcept
    {
        return m_size == m_capacity;
    }

    size_type size() const nsrs_noexcept
    {
        return m_size;
    }

    size_type capacity() const nsrs_noexcept
    {
        return m_capacity;
    }

    // element access:

    reference front() nsrs_noexcept
    {
        return *begin();
    }

    const_reference front() const nsrs_noexcept
    {
        return *begin();
    }

    reference back() nsrs_noexcept
    {
        return *(--end());
    }

    const_reference back() const nsrs_noexcept
    {
        return *(--end());
    }

    // iteration:

    iterator begin() nsrs_noexcept
    {
        return iterator(0, this);
    }

    const_iterator begin() const nsrs_noexcept
    {
        return cbegin();
    }

    const_iterator cbegin() const nsrs_noexcept
    {
        return const_iterator(0, this);
    }

    iterator end() nsrs_noexcept
    {
        return iterator(size(), this);
    }

    const_iterator end() const nsrs_noexcept
    {
        return cend();
    }

    const_iterator cend() const nsrs_noexcept
    {
        return const_iterator(size(), this);
    }

#    if nsrs_RING_SPAN_LITE_EXTENSION

    reverse_iterator rbegin() nsrs_noexcept
    {
        return reverse_iterator(end());
    }

    reverse_iterator rend() nsrs_noexcept
    {
        return reverse_iterator(begin());
    }

    const_reverse_iterator rbegin() const nsrs_noexcept
    {
        return crbegin();
    }

    const_reverse_iterator rend() const nsrs_noexcept
    {
        return crend();
    }

    const_reverse_iterator crbegin() const nsrs_noexcept
    {
        return const_reverse_iterator(cend());
    }

    const_reverse_iterator crend() const nsrs_noexcept
    {
        return const_reverse_iterator(cbegin());
    }
#    endif

    void erase_from(iterator first)
    {
        m_size = static_cast<size_type>(std::distance(begin(), first));
    }

    // element insertion, extraction:

    typename Popper::return_type pop_front()
    {
        assert(!empty());

        reference element = front_();
        increment_front_();

        return m_popper(element);
    }

#    if nsrs_RING_SPAN_LITE_EXTENSION
    typename Popper::return_type pop_back()
    {
        assert(!empty());

        reference element = back_();
        decrement_back_();

        return m_popper(element);
    }
#    endif

#    if nsrs_CPP11_OR_GREATER
    template<bool b = true,
             typename
             = nonstd::enable_if_t<b && std::is_copy_assignable<T>::value> >
    void push_back(value_type const& value)
        nsrs_noexcept_op((std::is_nothrow_copy_assignable<T>::value))
#    else
    void push_back(value_type const& value)
#    endif
    {
        if (full())
            increment_front_and_back_();
        else
            increment_back_();

        back_() = value;
    }

#    if nsrs_CPP11_OR_GREATER
    template<bool b = true,
             typename
             = nonstd::enable_if_t<b && std::is_move_assignable<T>::value> >
    void push_back(value_type&& value)
        nsrs_noexcept_op((std::is_nothrow_move_assignable<T>::value))
    {
        if (full())
            increment_front_and_back_();
        else
            increment_back_();

        back_() = std::move(value);
    }

    template<class... Args>
    void emplace_back(Args&&... args)
        nsrs_noexcept_op((std::is_nothrow_constructible<T, Args...>::value
                          && std::is_nothrow_move_assignable<T>::value))
    {
        if (full())
            increment_front_and_back_();
        else
            increment_back_();

        back_() = T(std::forward<Args>(args)...);
    }
#    endif

#    if nsrs_RING_SPAN_LITE_EXTENSION

#        if nsrs_CPP11_OR_GREATER
    template<bool b = true,
             typename
             = nonstd::enable_if_t<b && std::is_copy_assignable<T>::value> >
    void push_front(T const& value)
        nsrs_noexcept_op((std::is_nothrow_copy_assignable<T>::value))
#        else
    void push_front(T const& value)
#        endif
    {
        if (full())
            decrement_front_and_back_();
        else
            decrement_front_();

        front_() = value;
    }

#        if nsrs_CPP11_OR_GREATER
    template<bool b = true,
             typename
             = nonstd::enable_if_t<b && std::is_move_assignable<T>::value> >
    void push_front(T&& value)
        nsrs_noexcept_op((std::is_nothrow_move_assignable<T>::value))
    {
        if (full())
            decrement_front_and_back_();
        else
            decrement_front_();

        front_() = std::move(value);
    }

    template<typename... Args>
    void emplace_front(Args&&... args)
        nsrs_noexcept_op((std::is_nothrow_constructible<T, Args...>::value
                          && std::is_nothrow_move_assignable<T>::value))
    {
        if (full())
            decrement_front_and_back_();
        else
            decrement_front_();

        front_() = T(std::forward<Args>(args)...);
    }
#        endif
#    endif  // nsrs_RING_SPAN_LITE_EXTENSION

    // swap:

    void swap(type& rhs)
        nsrs_noexcept  // nsrs_noexcept_op(std::is_nothrow_swappable<Popper>::value);
    {
        using std::swap;
        swap(m_data, rhs.m_data);
        swap(m_size, rhs.m_size);
        swap(m_capacity, rhs.m_capacity);
        swap(m_front_idx, rhs.m_front_idx);
        swap(m_popper, rhs.m_popper);
    }

private:
    friend class ring_detail::ring_iterator<ring_span,
                                            true>;  // const_iterator;
    friend class ring_detail::ring_iterator<ring_span, false>;  // iterator;

    size_type normalize_(size_type const idx) const nsrs_noexcept
    {
        return idx % m_capacity;
    }

    reference at(size_type idx) nsrs_noexcept
    {
        return m_data[normalize_(m_front_idx + idx)];
    }

    const_reference at(size_type idx) const nsrs_noexcept
    {
        return m_data[normalize_(m_front_idx + idx)];
    }

    reference front_() nsrs_noexcept
    {
        return *(m_data + m_front_idx);
    }

    const_reference front_() const nsrs_noexcept
    {
        return *(m_data + m_front_idx);
    }

    reference back_() nsrs_noexcept
    {
        return *(m_data + normalize_(m_front_idx + m_size - 1));
    }

    const_reference back_() const nsrs_noexcept
    {
        return *(m_data + normalize_(m_front_idx + m_size - 1));
    }

    void increment_front_() nsrs_noexcept
    {
        m_front_idx = normalize_(m_front_idx + 1);
        --m_size;
    }

    void decrement_front_() nsrs_noexcept
    {
        m_front_idx = normalize_(m_front_idx + m_capacity - 1);
        ++m_size;
    }

    void increment_back_() nsrs_noexcept
    {
        ++m_size;
    }

    void decrement_back_() nsrs_noexcept
    {
        --m_size;
    }

    void increment_front_and_back_() nsrs_noexcept
    {
        m_front_idx = normalize_(m_front_idx + 1);
    }

    void decrement_front_and_back_() nsrs_noexcept
    {
        m_front_idx = normalize_(m_front_idx + m_capacity - 1);
    }

private:
    pointer m_data;
    size_type m_size;
    size_type m_capacity;
    size_type m_front_idx;
    Popper m_popper;
};

// swap:

template<class T, class Popper>
inline void
swap(ring_span<T, Popper>& lhs, ring_span<T, Popper>& rhs)
    nsrs_noexcept_op(nsrs_noexcept_op(lhs.swap(rhs)))
{
    lhs.swap(rhs);
}

namespace ring_detail {

//
// ring iterator:
//
#    if 0
template< class RS, bool is_const >
class ring_iterator : public std::iterator
<
    std::random_access_iterator_tag
    , typename nonstd::conditional<is_const, const typename RS::value_type, typename RS::value_type>::type
>
#    endif

template<class RS, bool is_const>
class ring_iterator {
public:
    typedef ring_iterator<RS, is_const> type;

    typedef std::ptrdiff_t difference_type;
    typedef typename RS::value_type value_type;

    typedef typename nonstd::
        conditional<is_const, const value_type, value_type>::type* pointer;
    typedef typename nonstd::
        conditional<is_const, const value_type, value_type>::type& reference;
    typedef std::random_access_iterator_tag iterator_category;

#    if nsrs_CPP11_OR_GREATER
    ring_iterator() = default;
#    else
    ring_iterator() : m_idx(), m_rs() {}
#    endif

#    if nsrs_RING_SPAN_LITE_EXTENSION
    // conversion to const iterator:

    operator ring_iterator<RS, true>() const nsrs_noexcept
    {
        return ring_iterator<RS, true>(m_idx, m_rs);
    }
#    endif

    // access content:

    reference operator*() const nsrs_noexcept
    {
        return m_rs->at(m_idx);
    }

    // advance iterator:

    type& operator++() nsrs_noexcept
    {
        ++m_idx;
        return *this;
    }

    type operator++(int) nsrs_noexcept
    {
        type r(*this);
        ++*this;
        return r;
    }

    type& operator--() nsrs_noexcept
    {
        --m_idx;
        return *this;
    }

    type operator--(int) nsrs_noexcept
    {
        type r(*this);
        --*this;
        return r;
    }

#    if defined(__clang__) || defined(__GNUC__)
#        pragma GCC diagnostic push
#        pragma GCC diagnostic ignored "-Wsign-conversion"
#    endif

    type& operator+=(int i) nsrs_noexcept
    {
        m_idx += i;
        return *this;
    }

    type& operator-=(int i) nsrs_noexcept
    {
        m_idx -= i;
        return *this;
    }

#    if defined(__clang__) || defined(__GNUC__)
#        pragma GCC diagnostic pop
#    endif

#    if nsrs_RING_SPAN_LITE_EXTENSION

    template<bool C>
    difference_type operator-(ring_iterator<RS, C> const& rhs) const
        nsrs_noexcept
    {
        return static_cast<difference_type>(this->m_idx)
            - static_cast<difference_type>(rhs.m_idx);
    }
#    endif

    // comparison:

    template<bool C>
    bool operator<(ring_iterator<RS, C> const& rhs) const nsrs_noexcept
    {
        assert(this->m_rs == rhs.m_rs);
        return (this->m_idx < rhs.m_idx);
    }

    template<bool C>
    bool operator==(ring_iterator<RS, C> const& rhs) const nsrs_noexcept
    {
        assert(this->m_rs == rhs.m_rs);
        return (this->m_idx == rhs.m_idx);
    }

    // other comparisons expressed in <, ==:

    template<bool C>
    inline bool operator!=(ring_iterator<RS, C> const& rhs) const nsrs_noexcept
    {
        return !(*this == rhs);
    }

    template<bool C>
    inline bool operator<=(ring_iterator<RS, C> const& rhs) const nsrs_noexcept
    {
        return !(rhs < *this);
    }

    template<bool C>
    inline bool operator>(ring_iterator<RS, C> const& rhs) const nsrs_noexcept
    {
        return rhs < *this;
    }

    template<bool C>
    inline bool operator>=(ring_iterator<RS, C> const& rhs) const nsrs_noexcept
    {
        return !(*this < rhs);
    }

private:
    friend RS;  // clang: non-class friend type 'RS' is a C++11 extension
                // [-Wc++11-extensions]
    friend class ring_iterator<RS, !is_const>;

    typedef typename RS::size_type size_type;
    typedef
        typename nonstd::conditional<is_const, const RS, RS>::type ring_type;

    ring_iterator(size_type idx,
                  typename nonstd::conditional<is_const, const RS, RS>::type*
                      rs) nsrs_noexcept
        : m_idx(idx)
        , m_rs(rs)
    {
    }

private:
    size_type m_idx;
    ring_type* m_rs;
};

// advanced iterator:

template<class RS, bool C>
inline ring_iterator<RS, C>
operator+(ring_iterator<RS, C> it, int i) nsrs_noexcept
{
    it += i;
    return it;
}

template<class RS, bool C>
inline ring_iterator<RS, C>
operator-(ring_iterator<RS, C> it, int i) nsrs_noexcept
{
    it -= i;
    return it;
}

}  // namespace ring_detail
}  // namespace nonstd

nsrs_RESTORE_WARNINGS()

#endif  // NONSTD_RING_SPAN_LITE_HPP
