You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

302 lines
7.0 KiB

#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 };
}
}