#pragma once
|
|
|
|
#include <assert.h>
|
|
#include <type_traits>
|
|
#include <array>
|
|
|
|
#include "utility.h"
|
|
|
|
namespace vlc
|
|
{
|
|
static constexpr const std::size_t dynamic_extent = ~0u;
|
|
|
|
namespace detail
|
|
{
|
|
template<class...> using void_t = void;
|
|
template<bool B> using bool_constant = std::integral_constant<bool, B>;
|
|
|
|
template<class T, class ElementType, typename = void> struct is_array_convertible : std::false_type {};
|
|
|
|
template<class T, class ElementType>
|
|
struct is_array_convertible<T, ElementType,
|
|
typename std::enable_if<!std::is_void<typename std::remove_pointer<decltype(vlc::data(std::declval<T>()))>::type>::value>::type
|
|
> : std::is_convertible<typename std::remove_pointer<decltype(vlc::data(std::declval<T>()))>::type(*)[], ElementType(*)[]>::type
|
|
{};
|
|
}
|
|
|
|
template<typename T, std::size_t Extent = dynamic_extent> class span
|
|
{
|
|
public:
|
|
static const std::size_t extent = Extent;
|
|
|
|
using element_type = T;
|
|
using value_type = typename std::remove_cv<T>::type;
|
|
using pointer = T * ;
|
|
using const_pointer = const T*;
|
|
using reference = T & ;
|
|
using const_reference = const T&;
|
|
|
|
using iterator = pointer;
|
|
using const_iterator = const_pointer;
|
|
using reverse_iterator = std::reverse_iterator<iterator>;
|
|
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
|
|
|
|
using index_type = std::size_t;
|
|
using difference_type = std::ptrdiff_t;
|
|
|
|
template<
|
|
std::size_t E = Extent,
|
|
class = typename std::enable_if<(E == dynamic_extent) || (E == 0)>::type
|
|
>
|
|
span() noexcept
|
|
{}
|
|
|
|
span(pointer ptr, index_type count) : m_ptr(ptr), m_size(count)
|
|
{
|
|
assert(extent == dynamic_extent || count == extent);
|
|
}
|
|
|
|
span(pointer first, pointer last) : span(first, last - first)
|
|
{}
|
|
|
|
template <std::size_t N,
|
|
std::size_t E = Extent,
|
|
class = typename std::enable_if<
|
|
(E == dynamic_extent || N == E)
|
|
&& detail::is_array_convertible<element_type(&)[N], element_type>::value
|
|
>::type
|
|
>
|
|
span(element_type(&arr)[N]) noexcept : span(arr, N)
|
|
{}
|
|
|
|
template <std::size_t N,
|
|
std::size_t E = Extent,
|
|
class = typename std::enable_if<
|
|
(E == dynamic_extent || N == E)
|
|
&& detail::is_array_convertible<std::array<value_type, N>&, element_type>::value
|
|
>::type
|
|
>
|
|
span(std::array<value_type, N>& arr) noexcept : span(vlc::data(arr), N)
|
|
{}
|
|
|
|
template <std::size_t N,
|
|
std::size_t E = Extent,
|
|
class = typename std::enable_if<
|
|
(E == dynamic_extent || N == E)
|
|
&& detail::is_array_convertible<const std::array<value_type, N>&, element_type>::value
|
|
>::type
|
|
>
|
|
span(const std::array<value_type, N>& arr) noexcept : span(vlc::data(arr), N)
|
|
{}
|
|
|
|
template<typename Container,
|
|
std::size_t E = Extent,
|
|
class = typename std::enable_if<
|
|
E == dynamic_extent &&
|
|
!std::is_same<Container, span<element_type>>::value &&
|
|
!std::is_array<Container>::value &&
|
|
detail::is_array_convertible<Container&, element_type>::value
|
|
>::type
|
|
>
|
|
span(Container& c) : span(vlc::data(c), vlc::size(c))
|
|
{}
|
|
|
|
template<typename Container,
|
|
std::size_t E = Extent,
|
|
class = typename std::enable_if<
|
|
E == dynamic_extent &&
|
|
!std::is_same<Container, span<element_type>>::value &&
|
|
!std::is_array<Container>::value &&
|
|
detail::is_array_convertible<const Container&, element_type>::value
|
|
>::type
|
|
>
|
|
span(const Container& c) : span(vlc::data(c), vlc::size(c))
|
|
{}
|
|
|
|
template<typename U, std::size_t N,
|
|
std::size_t E = Extent,
|
|
class = typename std::enable_if<
|
|
(E == dynamic_extent || N == E)
|
|
&& std::is_convertible<U(*)[], element_type(*)[]>::value
|
|
>::type
|
|
>
|
|
span(const span<U, N>& other) noexcept : m_ptr(other.data()), m_size(other.size())
|
|
{}
|
|
|
|
span(const span& other) noexcept = default;
|
|
span& operator = (const span& other) noexcept = default;
|
|
|
|
pointer data() const noexcept
|
|
{
|
|
return m_ptr;
|
|
}
|
|
|
|
index_type size() const noexcept
|
|
{
|
|
return m_size;
|
|
}
|
|
|
|
index_type size_bytes() const noexcept
|
|
{
|
|
return size() * sizeof(element_type);
|
|
}
|
|
|
|
bool empty() const noexcept
|
|
{
|
|
return !size();
|
|
}
|
|
|
|
iterator begin() const noexcept
|
|
{
|
|
return data();
|
|
}
|
|
|
|
const_iterator cbegin() const noexcept
|
|
{
|
|
return data();
|
|
}
|
|
|
|
iterator end() const noexcept
|
|
{
|
|
return data() + size();
|
|
}
|
|
|
|
const_iterator cend() const noexcept
|
|
{
|
|
return data() + size();
|
|
}
|
|
|
|
reverse_iterator rbegin() const noexcept
|
|
{
|
|
return reverse_iterator(end());
|
|
}
|
|
|
|
const_reverse_iterator crbegin() const noexcept
|
|
{
|
|
return const_reverse_iterator(end());
|
|
}
|
|
|
|
reverse_iterator rend() const noexcept
|
|
{
|
|
return reverse_iterator(begin());
|
|
}
|
|
|
|
const_reverse_iterator crend() const noexcept
|
|
{
|
|
return const_reverse_iterator(begin());
|
|
}
|
|
|
|
friend iterator begin(span s) noexcept { return s.begin(); }
|
|
friend iterator end(span s) noexcept { return s.end(); }
|
|
|
|
reference front() const
|
|
{
|
|
return *begin();
|
|
}
|
|
|
|
reference back() const
|
|
{
|
|
return *(end() - 1);
|
|
}
|
|
|
|
reference operator[](index_type idx) const
|
|
{
|
|
assert(idx < size());
|
|
return *(begin() + idx);
|
|
}
|
|
|
|
template<std::size_t Count>
|
|
span<element_type, Count> first() const
|
|
{
|
|
assert(Count <= size());
|
|
return { data(), Count };
|
|
}
|
|
|
|
template<std::size_t Count>
|
|
span<element_type, Count> last() const
|
|
{
|
|
assert(Count <= size());
|
|
return { data() + (size() - Count), Count };
|
|
}
|
|
|
|
template<std::size_t Offset, std::size_t Count = dynamic_extent,
|
|
typename return_t = span<
|
|
element_type,
|
|
Count != dynamic_extent ? Count : (Extent != dynamic_extent ? Extent - Offset : dynamic_extent)
|
|
>
|
|
>
|
|
auto subspan() const -> return_t
|
|
{
|
|
assert(Offset < size());
|
|
assert(Count == dynamic_extent || (Offset + Count <= size()));
|
|
return { data() + Offset, Count != dynamic_extent ? Count : size() - Offset };
|
|
}
|
|
|
|
span<element_type, dynamic_extent> first(std::size_t count) const
|
|
{
|
|
assert(count <= size());
|
|
return { data(), count };
|
|
}
|
|
|
|
span<element_type, dynamic_extent> last(std::size_t count) const
|
|
{
|
|
assert(count <= size());
|
|
return { data() + (size() - count), count };
|
|
}
|
|
|
|
auto subspan(std::size_t offset, std::size_t count = dynamic_extent) const
|
|
-> span<element_type, dynamic_extent>
|
|
{
|
|
assert(offset < size());
|
|
assert(count == dynamic_extent || (offset + count <= size()));
|
|
|
|
return {
|
|
data() + offset,
|
|
count != dynamic_extent ? count : size() - offset
|
|
};
|
|
}
|
|
|
|
private:
|
|
T* m_ptr = nullptr;
|
|
index_type m_size = 0;
|
|
};
|
|
|
|
template<typename ElementType, std::size_t Extent>
|
|
span<ElementType, Extent>
|
|
make_span(span<ElementType, Extent> s) noexcept
|
|
{
|
|
return s;
|
|
}
|
|
|
|
template <typename T, std::size_t N>
|
|
span<T, N> make_span(T(&arr)[N]) noexcept
|
|
{
|
|
return { arr };
|
|
}
|
|
|
|
template <typename T, std::size_t N>
|
|
span<T, N> make_span(std::array<T, N>& arr) noexcept
|
|
{
|
|
return { arr };
|
|
}
|
|
|
|
template <typename T, std::size_t N>
|
|
span<const T, N>
|
|
make_span(const std::array<T, N>& arr) noexcept
|
|
{
|
|
return { arr };
|
|
}
|
|
|
|
template <typename Container>
|
|
span<typename Container::value_type> make_span(Container& cont)
|
|
{
|
|
return { cont };
|
|
}
|
|
|
|
template <typename Container>
|
|
span<const typename Container::value_type>
|
|
make_span(const Container& cont)
|
|
{
|
|
return { cont };
|
|
}
|
|
}
|