forked from boostorg/core
		
	
		
			
				
	
	
		
			400 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			400 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
/*
 | 
						|
Copyright 2019 Glen Joseph Fernandes
 | 
						|
(glenjofe@gmail.com)
 | 
						|
 | 
						|
Distributed under the Boost Software License, Version 1.0.
 | 
						|
(http://www.boost.org/LICENSE_1_0.txt)
 | 
						|
*/
 | 
						|
#ifndef BOOST_CORE_SPAN_HPP
 | 
						|
#define BOOST_CORE_SPAN_HPP
 | 
						|
 | 
						|
#include <array>
 | 
						|
#include <iterator>
 | 
						|
#include <type_traits>
 | 
						|
#include <cstddef>
 | 
						|
 | 
						|
namespace boost {
 | 
						|
 | 
						|
constexpr std::size_t dynamic_extent = static_cast<std::size_t>(-1);
 | 
						|
 | 
						|
template<class T, std::size_t E = dynamic_extent>
 | 
						|
class span;
 | 
						|
 | 
						|
namespace detail {
 | 
						|
 | 
						|
template<class U, class T>
 | 
						|
struct span_convertible {
 | 
						|
    static constexpr bool value = std::is_convertible<U(*)[], T(*)[]>::value;
 | 
						|
};
 | 
						|
 | 
						|
template<std::size_t E, std::size_t N>
 | 
						|
struct span_capacity {
 | 
						|
    static constexpr bool value = E == boost::dynamic_extent || E == N;
 | 
						|
};
 | 
						|
 | 
						|
template<class T, std::size_t E, class U, std::size_t N>
 | 
						|
struct span_compatible {
 | 
						|
    static constexpr bool value = span_capacity<E, N>::value &&
 | 
						|
        span_convertible<U, T>::value;
 | 
						|
};
 | 
						|
 | 
						|
template<class T>
 | 
						|
struct span_uncvref {
 | 
						|
    typedef typename std::remove_cv<typename
 | 
						|
        std::remove_reference<T>::type>::type type;
 | 
						|
};
 | 
						|
 | 
						|
template<class>
 | 
						|
struct span_is_span {
 | 
						|
    static constexpr bool value = false;
 | 
						|
};
 | 
						|
 | 
						|
template<class T, std::size_t E>
 | 
						|
struct span_is_span<boost::span<T, E> > {
 | 
						|
    static constexpr bool value = true;
 | 
						|
};
 | 
						|
 | 
						|
template<class T>
 | 
						|
struct span_is_array {
 | 
						|
    static constexpr bool value = false;
 | 
						|
};
 | 
						|
 | 
						|
template<class T, std::size_t N>
 | 
						|
struct span_is_array<std::array<T, N> > {
 | 
						|
    static constexpr bool value = true;
 | 
						|
};
 | 
						|
 | 
						|
template<class, class = void>
 | 
						|
struct span_data { };
 | 
						|
 | 
						|
template<class T>
 | 
						|
struct span_data<T,
 | 
						|
    typename std::enable_if<std::is_pointer<decltype(std::declval<T
 | 
						|
        &>().data())>::value>::type> {
 | 
						|
    typedef typename std::remove_pointer<decltype(std::declval<T
 | 
						|
        &>().data())>::type type;
 | 
						|
};
 | 
						|
 | 
						|
template<class, class, class = void>
 | 
						|
struct span_has_data {
 | 
						|
    static constexpr bool value = false;
 | 
						|
};
 | 
						|
 | 
						|
template<class R, class T>
 | 
						|
struct span_has_data<R, T, typename std::enable_if<span_convertible<typename
 | 
						|
    span_data<R>::type, T>::value>::type> {
 | 
						|
    static constexpr bool value = true;
 | 
						|
};
 | 
						|
 | 
						|
template<class, class = void>
 | 
						|
struct span_has_size {
 | 
						|
    static constexpr bool value = false;
 | 
						|
};
 | 
						|
 | 
						|
template<class R>
 | 
						|
struct span_has_size<R, typename
 | 
						|
    std::enable_if<std::is_convertible<decltype(std::declval<R&>().size()),
 | 
						|
        std::size_t>::value>::type> {
 | 
						|
    static constexpr bool value = true;
 | 
						|
};
 | 
						|
 | 
						|
template<class R, class T>
 | 
						|
struct span_is_range {
 | 
						|
    static constexpr bool value = (std::is_const<T>::value ||
 | 
						|
        std::is_lvalue_reference<R>::value) &&
 | 
						|
        !span_is_span<typename span_uncvref<R>::type>::value &&
 | 
						|
        !span_is_array<typename span_uncvref<R>::type>::value &&
 | 
						|
        !std::is_array<typename span_uncvref<R>::type>::value &&
 | 
						|
        span_has_data<R, T>::value &&
 | 
						|
        span_has_size<R>::value;
 | 
						|
};
 | 
						|
 | 
						|
template<std::size_t E, std::size_t N>
 | 
						|
struct span_implicit {
 | 
						|
    static constexpr bool value = E == boost::dynamic_extent ||
 | 
						|
        N != boost::dynamic_extent;
 | 
						|
};
 | 
						|
 | 
						|
template<class T, std::size_t E, class U, std::size_t N>
 | 
						|
struct span_copyable {
 | 
						|
    static constexpr bool value = (N == boost::dynamic_extent ||
 | 
						|
        span_capacity<E, N>::value) && span_convertible<U, T>::value;
 | 
						|
};
 | 
						|
 | 
						|
template<std::size_t E, std::size_t O>
 | 
						|
struct span_sub {
 | 
						|
    static constexpr std::size_t value = E == boost::dynamic_extent ?
 | 
						|
        boost::dynamic_extent : E - O;
 | 
						|
};
 | 
						|
 | 
						|
template<class T, std::size_t E>
 | 
						|
struct span_store {
 | 
						|
    constexpr span_store(T* p_, std::size_t) noexcept
 | 
						|
        : p(p_) { }
 | 
						|
    static constexpr std::size_t n = E;
 | 
						|
    T* p;
 | 
						|
};
 | 
						|
 | 
						|
template<class T>
 | 
						|
struct span_store<T, boost::dynamic_extent> {
 | 
						|
    constexpr span_store(T* p_, std::size_t n_) noexcept
 | 
						|
        : p(p_)
 | 
						|
        , n(n_) { }
 | 
						|
    T* p;
 | 
						|
    std::size_t n;
 | 
						|
};
 | 
						|
 | 
						|
template<class T, std::size_t E>
 | 
						|
struct span_bytes {
 | 
						|
    static constexpr std::size_t value = sizeof(T) * E;
 | 
						|
};
 | 
						|
 | 
						|
template<class T>
 | 
						|
struct span_bytes<T, boost::dynamic_extent> {
 | 
						|
    static constexpr std::size_t value = boost::dynamic_extent;
 | 
						|
};
 | 
						|
 | 
						|
} /* detail */
 | 
						|
 | 
						|
template<class T, std::size_t E>
 | 
						|
class span {
 | 
						|
public:
 | 
						|
    typedef T element_type;
 | 
						|
    typedef typename std::remove_cv<T>::type value_type;
 | 
						|
    typedef std::size_t size_type;
 | 
						|
    typedef std::ptrdiff_t difference_type;
 | 
						|
    typedef T* pointer;
 | 
						|
    typedef const T* const_pointer;
 | 
						|
    typedef T& reference;
 | 
						|
    typedef const T& const_reference;
 | 
						|
    typedef T* iterator;
 | 
						|
    typedef const T* const_iterator;
 | 
						|
    typedef std::reverse_iterator<T*> reverse_iterator;
 | 
						|
    typedef std::reverse_iterator<const T*> const_reverse_iterator;
 | 
						|
 | 
						|
    static constexpr std::size_t extent = E;
 | 
						|
 | 
						|
    template<std::size_t N = E,
 | 
						|
        typename std::enable_if<N == dynamic_extent || N == 0, int>::type = 0>
 | 
						|
    constexpr span() noexcept
 | 
						|
        : s_(0, 0) { }
 | 
						|
 | 
						|
    template<class I,
 | 
						|
        typename std::enable_if<E == dynamic_extent &&
 | 
						|
            detail::span_convertible<I, T>::value, int>::type = 0>
 | 
						|
    constexpr span(I* f, size_type c)
 | 
						|
        : s_(f, c) { }
 | 
						|
 | 
						|
    template<class I,
 | 
						|
        typename std::enable_if<E != dynamic_extent &&
 | 
						|
            detail::span_convertible<I, T>::value, int>::type = 0>
 | 
						|
    explicit constexpr span(I* f, size_type c)
 | 
						|
        : s_(f, c) { }
 | 
						|
 | 
						|
    template<class I, class L,
 | 
						|
        typename std::enable_if<E == dynamic_extent &&
 | 
						|
            detail::span_convertible<I, T>::value, int>::type = 0>
 | 
						|
    constexpr span(I* f, L* l)
 | 
						|
        : s_(f, l - f) { }
 | 
						|
 | 
						|
    template<class I, class L,
 | 
						|
        typename std::enable_if<E != dynamic_extent &&
 | 
						|
            detail::span_convertible<I, T>::value, int>::type = 0>
 | 
						|
    explicit constexpr span(I* f, L* l)
 | 
						|
        : s_(f, l - f) { }
 | 
						|
 | 
						|
    template<std::size_t N,
 | 
						|
        typename std::enable_if<detail::span_capacity<E, N>::value,
 | 
						|
            int>::type = 0>
 | 
						|
    constexpr span(typename std::enable_if<true, T>::type (&a)[N]) noexcept
 | 
						|
        : s_(a, N) { }
 | 
						|
 | 
						|
    template<class U, std::size_t N,
 | 
						|
        typename std::enable_if<detail::span_compatible<T, E, U, N>::value,
 | 
						|
            int>::type = 0>
 | 
						|
    constexpr span(std::array<U, N>& a) noexcept
 | 
						|
        : s_(a.data(), N) { }
 | 
						|
 | 
						|
    template<class U, std::size_t N,
 | 
						|
        typename std::enable_if<detail::span_compatible<T, E, const U,
 | 
						|
            N>::value, int>::type = 0>
 | 
						|
    constexpr span(const std::array<U, N>& a) noexcept
 | 
						|
        : s_(a.data(), N) { }
 | 
						|
 | 
						|
    template<class R,
 | 
						|
        typename std::enable_if<E == dynamic_extent &&
 | 
						|
            detail::span_is_range<R, T>::value, int>::type = 0>
 | 
						|
    constexpr span(R&& r) noexcept(noexcept(r.data()) && noexcept(r.size()))
 | 
						|
        : s_(r.data(), r.size()) { }
 | 
						|
 | 
						|
    template<class R,
 | 
						|
        typename std::enable_if<E != dynamic_extent &&
 | 
						|
            detail::span_is_range<R, T>::value, int>::type = 0>
 | 
						|
    explicit constexpr span(R&& r) noexcept(noexcept(r.data()) &&
 | 
						|
        noexcept(r.size()))
 | 
						|
        : s_(r.data(), r.size()) { }
 | 
						|
 | 
						|
    template<class U, std::size_t N,
 | 
						|
        typename std::enable_if<detail::span_implicit<E, N>::value &&
 | 
						|
            detail::span_copyable<T, E, U, N>::value, int>::type = 0>
 | 
						|
    constexpr span(const span<U, N>& s) noexcept
 | 
						|
        : s_(s.data(), s.size()) { }
 | 
						|
 | 
						|
    template<class U, std::size_t N,
 | 
						|
        typename std::enable_if<!detail::span_implicit<E, N>::value &&
 | 
						|
            detail::span_copyable<T, E, U, N>::value, int>::type = 0>
 | 
						|
    explicit constexpr span(const span<U, N>& s) noexcept
 | 
						|
        : s_(s.data(), s.size()) { }
 | 
						|
 | 
						|
    template<std::size_t C>
 | 
						|
    constexpr span<T, C> first() const {
 | 
						|
        static_assert(C <= E, "Count <= Extent");
 | 
						|
        return span<T, C>(s_.p, C);
 | 
						|
    }
 | 
						|
 | 
						|
    template<std::size_t C>
 | 
						|
    constexpr span<T, C> last() const {
 | 
						|
        static_assert(C <= E, "Count <= Extent");
 | 
						|
        return span<T, C>(s_.p + (s_.n - C), C);
 | 
						|
    }
 | 
						|
 | 
						|
    template<std::size_t O, std::size_t C = dynamic_extent>
 | 
						|
    constexpr typename std::enable_if<C == dynamic_extent,
 | 
						|
        span<T, detail::span_sub<E, O>::value> >::type subspan() const {
 | 
						|
        static_assert(O <= E, "Offset <= Extent");
 | 
						|
        return span<T, detail::span_sub<E, O>::value>(s_.p + O, s_.n - O);
 | 
						|
    }
 | 
						|
 | 
						|
    template<std::size_t O, std::size_t C = dynamic_extent>
 | 
						|
    constexpr typename std::enable_if<C != dynamic_extent,
 | 
						|
        span<T, C> >::type subspan() const {
 | 
						|
        static_assert(O <= E && C <= E - O,
 | 
						|
            "Offset <= Extent && Count <= Extent - Offset");
 | 
						|
        return span<T, C>(s_.p + O, C);
 | 
						|
    }
 | 
						|
 | 
						|
    constexpr span<T, dynamic_extent> first(size_type c) const {
 | 
						|
        return span<T, dynamic_extent>(s_.p, c);
 | 
						|
    }
 | 
						|
 | 
						|
    constexpr span<T, dynamic_extent> last(size_type c) const {
 | 
						|
        return span<T, dynamic_extent>(s_.p + (s_.n - c), c);
 | 
						|
    }
 | 
						|
 | 
						|
    constexpr span<T, dynamic_extent> subspan(size_type o,
 | 
						|
        size_type c = dynamic_extent) const {
 | 
						|
        return span<T, dynamic_extent>(s_.p + o,
 | 
						|
            c == dynamic_extent ? s_.n - o : c);
 | 
						|
    }
 | 
						|
 | 
						|
    constexpr size_type size() const noexcept {
 | 
						|
        return s_.n;
 | 
						|
    }
 | 
						|
 | 
						|
    constexpr size_type size_bytes() const noexcept {
 | 
						|
        return s_.n * sizeof(T);
 | 
						|
    }
 | 
						|
 | 
						|
    constexpr bool empty() const noexcept {
 | 
						|
        return s_.n == 0;
 | 
						|
    }
 | 
						|
 | 
						|
    constexpr reference operator[](size_type i) const {
 | 
						|
        return s_.p[i];
 | 
						|
    }
 | 
						|
 | 
						|
    constexpr reference front() const {
 | 
						|
        return *s_.p;
 | 
						|
    }
 | 
						|
 | 
						|
    constexpr reference back() const {
 | 
						|
        return s_.p[s_.n - 1];
 | 
						|
    }
 | 
						|
 | 
						|
    constexpr pointer data() const noexcept {
 | 
						|
        return s_.p;
 | 
						|
    }
 | 
						|
 | 
						|
    constexpr iterator begin() const noexcept {
 | 
						|
        return s_.p;
 | 
						|
    }
 | 
						|
 | 
						|
    constexpr iterator end() const noexcept {
 | 
						|
        return s_.p + s_.n;
 | 
						|
    }
 | 
						|
 | 
						|
    constexpr reverse_iterator rbegin() const noexcept {
 | 
						|
        return reverse_iterator(s_.p + s_.n);
 | 
						|
    }
 | 
						|
 | 
						|
    constexpr reverse_iterator rend() const noexcept {
 | 
						|
        return reverse_iterator(s_.p);
 | 
						|
    }
 | 
						|
 | 
						|
    constexpr const_iterator cbegin() const noexcept {
 | 
						|
        return s_.p;
 | 
						|
    }
 | 
						|
 | 
						|
    constexpr const_iterator cend() const noexcept {
 | 
						|
        return s_.p + s_.n;
 | 
						|
    }
 | 
						|
 | 
						|
    constexpr const_reverse_iterator crbegin() const noexcept {
 | 
						|
        return const_reverse_iterator(s_.p + s_.n);
 | 
						|
    }
 | 
						|
 | 
						|
    constexpr const_reverse_iterator crend() const noexcept {
 | 
						|
        return const_reverse_iterator(s_.p);
 | 
						|
    }
 | 
						|
 | 
						|
private:
 | 
						|
    detail::span_store<T, E> s_;
 | 
						|
};
 | 
						|
 | 
						|
template<class T, std::size_t E>
 | 
						|
constexpr std::size_t span<T, E>::extent;
 | 
						|
 | 
						|
#ifdef __cpp_deduction_guides
 | 
						|
template<class I, class L>
 | 
						|
span(I*, L) -> span<I>;
 | 
						|
 | 
						|
template<class T, std::size_t N>
 | 
						|
span(T(&)[N]) -> span<T, N>;
 | 
						|
 | 
						|
template<class T, std::size_t N>
 | 
						|
span(std::array<T, N>&) -> span<T, N>;
 | 
						|
 | 
						|
template<class T, std::size_t N>
 | 
						|
span(const std::array<T, N>&) -> span<const T, N>;
 | 
						|
 | 
						|
template<class R>
 | 
						|
span(R&&) -> span<typename detail::span_data<R>::type>;
 | 
						|
 | 
						|
template<class T, std::size_t E>
 | 
						|
span(span<T, E>) -> span<T, E>;
 | 
						|
#endif
 | 
						|
 | 
						|
#ifdef __cpp_lib_byte
 | 
						|
template<class T, std::size_t E>
 | 
						|
inline span<const std::byte, detail::span_bytes<T, E>::value>
 | 
						|
as_bytes(span<T, E> s) noexcept
 | 
						|
{
 | 
						|
    return span<const std::byte, detail::span_bytes<T,
 | 
						|
        E>::value>(reinterpret_cast<const std::byte*>(s.data()),
 | 
						|
            s.size_bytes());
 | 
						|
}
 | 
						|
 | 
						|
template<class T, std::size_t E>
 | 
						|
inline typename std::enable_if<!std::is_const<T>::value,
 | 
						|
    span<std::byte, detail::span_bytes<T, E>::value> >::type
 | 
						|
as_writable_bytes(span<T, E> s) noexcept
 | 
						|
{
 | 
						|
    return span<std::byte, detail::span_bytes<T,
 | 
						|
        E>::value>(reinterpret_cast<std::byte*>(s.data()), s.size_bytes());
 | 
						|
}
 | 
						|
#endif
 | 
						|
 | 
						|
} /* boost */
 | 
						|
 | 
						|
#endif
 |