//
// 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 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 detail::ring_iterator< type, false  > iterator;
    typedef 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

    // 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 detail::ring_iterator<ring_span, true >;   // const_iterator;
    friend class 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 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 detail
} // namespace nonstd

nsrs_RESTORE_WARNINGS()

#endif // NONSTD_RING_SPAN_LITE_HPP
