vc/godbolt/containers

1650 lines
52 KiB
Plaintext

#ifndef VC_VC_
#define VC_VC_
#ifndef VC_IO_
#define VC_IO_
#include <iostream>
#if defined(__GNUC__) && !defined(_WIN32) && defined(_GLIBCXX_OSTREAM)
#define Vc_HACK_OSTREAM_FOR_TTY 1
#endif
#ifdef Vc_HACK_OSTREAM_FOR_TTY
#include <unistd.h>
#include <ext/stdio_sync_filebuf.h>
#endif
namespace Vc_VERSIONED_NAMESPACE
{
namespace
{
#ifdef Vc_HACK_OSTREAM_FOR_TTY
class hacked_ostream : public std::ostream
{
public:
using std::ostream::_M_streambuf;
};
bool mayUseColor(const std::ostream &os) __attribute__((__const__));
bool mayUseColor(const std::ostream &os)
{
std::basic_streambuf<char> *hack1 =
const_cast<std::basic_streambuf<char> *>(os.*(&hacked_ostream::_M_streambuf));
__gnu_cxx::stdio_sync_filebuf<char> *hack =
dynamic_cast<__gnu_cxx::stdio_sync_filebuf<char> *>(hack1);
if (!hack) {
return false;
}
FILE *file = hack->file();
return 1 == isatty(fileno(file));
}
#else
bool mayUseColor(const std::ostream &) { return false; }
#endif
}
namespace AnsiColor
{
struct Type
{
const char *data;
};
static const Type green = {"\033[1;40;32m"};
static const Type yellow = {"\033[1;40;33m"};
static const Type blue = {"\033[1;40;34m"};
static const Type normal = {"\033[0m"};
inline std::ostream &operator<<(std::ostream &out, const Type &c)
{
if (mayUseColor(out)) {
out << c.data;
}
return out;
}
}
template <typename T, typename Abi>
inline std::ostream &operator<<(std::ostream &out, const Vc::Vector<T, Abi> &v)
{
using TT = typename std::conditional<std::is_same<T, char>::value ||
std::is_same<T, unsigned char>::value ||
std::is_same<T, signed char>::value,
int,
T>::type;
out << AnsiColor::green << '[';
out << TT(v[0]);
for (size_t i = 1; i < v.Size; ++i) {
out << ", " << TT(v[i]);
}
out << ']' << AnsiColor::normal;
return out;
}
template <typename T, typename Abi>
inline std::ostream &operator<<(std::ostream &out, const Vc::Mask<T, Abi> &m)
{
out << AnsiColor::blue << "m[";
for (unsigned int i = 0; i < m.Size; ++i) {
if (i > 0 && (i % 4) == 0) {
out << ' ';
}
if (m[i]) {
out << AnsiColor::yellow << '1';
} else {
out << AnsiColor::blue << '0';
}
}
out << AnsiColor::blue << ']' << AnsiColor::normal;
return out;
}
namespace Common
{
#ifdef DOXYGEN
template<typename V, typename Parent, typename Dimension, typename RM>
inline std::ostream &operator<<(std::ostream &s, const Vc::MemoryBase<V, Parent, Dimension, RM> &m);
#endif
template<typename V, typename Parent, typename RM>
inline std::ostream &operator<<(std::ostream &out, const MemoryBase<V, Parent, 1, RM> &m )
{
out << AnsiColor::blue << '{' << AnsiColor::normal;
for (unsigned int i = 0; i < m.vectorsCount(); ++i) {
out << V(m.vector(i));
}
out << AnsiColor::blue << '}' << AnsiColor::normal;
return out;
}
template<typename V, typename Parent, typename RM>
inline std::ostream &operator<<(std::ostream &out, const MemoryBase<V, Parent, 2, RM> &m )
{
out << AnsiColor::blue << '{' << AnsiColor::normal;
for (size_t i = 0; i < m.rowsCount(); ++i) {
if (i > 0) {
out << "\n ";
}
const size_t vcount = m[i].vectorsCount();
for (size_t j = 0; j < vcount; ++j) {
out << V(m[i].vector(j));
}
}
out << AnsiColor::blue << '}' << AnsiColor::normal;
return out;
}
}
template<typename T, std::size_t N>
inline std::ostream &operator<<(std::ostream &out, const SimdArray<T, N> &v)
{
out << AnsiColor::green << '<' << v[0];
for (size_t i = 1; i < N; ++i) {
if (i % 4 == 0) out << " |";
out << ' ' << v[i];
}
return out << '>' << AnsiColor::normal;
}
template<typename T, std::size_t N>
inline std::ostream &operator<<(std::ostream &out, const SimdMaskArray<T, N> &m)
{
out << AnsiColor::blue << "«";
for (size_t i = 0; i < N; ++i) {
if (i > 0 && (i % 4) == 0) {
out << ' ';
}
if ( m[i] ) {
out << AnsiColor::yellow << '1';
} else {
out << AnsiColor::blue << '0';
}
}
return out << AnsiColor::blue << "»" << AnsiColor::normal;
}
}
#endif
#ifndef VC_MEMORY_
#define VC_MEMORY_
#ifndef VC_COMMON_MAKE_UNIQUE_H_
#define VC_COMMON_MAKE_UNIQUE_H_
#include <memory>
#ifndef VC_COMMON_MALLOC_H_
#define VC_COMMON_MALLOC_H_
#ifndef Vc_VECTOR_DECLARED_
#error "Incorrect inclusion order. This header must be included from Vc/vector.h only."
#endif
#if defined _WIN32 || defined _WIN64
#include <malloc.h>
#else
#include <cstdlib>
#endif
namespace Vc_VERSIONED_NAMESPACE
{
namespace Common
{
template <size_t X> static constexpr size_t nextMultipleOf(size_t value)
{
return (value % X) > 0 ? value + X - (value % X) : value;
}
template <std::size_t alignment> Vc_INTRINSIC void *aligned_malloc(std::size_t n)
{
#ifdef __MIC__
return _mm_malloc(nextMultipleOf<alignment>(n), alignment);
#elif defined(_WIN32)
# ifdef __GNUC__
return __mingw_aligned_malloc(nextMultipleOf<alignment>(n), alignment);
# else
return _aligned_malloc(nextMultipleOf<alignment>(n), alignment);
# endif
#else
void *ptr = nullptr;
if (0 == posix_memalign(&ptr, alignment < sizeof(void *) ? sizeof(void *) : alignment,
nextMultipleOf<alignment>(n))) {
return ptr;
}
return ptr;
#endif
}
template <Vc::MallocAlignment A> Vc_ALWAYS_INLINE void *malloc(size_t n)
{
switch (A) {
case Vc::AlignOnVector:
return aligned_malloc<Vc::VectorAlignment>(n);
case Vc::AlignOnCacheline:
return aligned_malloc<64>(n);
case Vc::AlignOnPage:
return aligned_malloc<4096>(n);
}
return nullptr;
}
Vc_ALWAYS_INLINE void free(void *p)
{
#ifdef __MIC__
_mm_free(p);
#elif defined(_WIN32)
# ifdef __GNUC__
return __mingw_aligned_free(p);
# else
return _aligned_free(p);
# endif
#else
std::free(p);
#endif
}
}
template<typename T, Vc::MallocAlignment A>
Vc_ALWAYS_INLINE T *malloc(size_t n)
{
return static_cast<T *>(Common::malloc<A>(n * sizeof(T)));
}
template<typename T>
Vc_ALWAYS_INLINE void free(T *p)
{
Common::free(p);
}
}
#endif
namespace Vc_VERSIONED_NAMESPACE
{
namespace Common
{
template<typename T> struct Deleter
{
Vc_ALWAYS_INLINE void operator()(T *ptr) {
ptr->~T();
Vc::free(ptr);
}
};
template<class T, MallocAlignment A = Vc::AlignOnVector, class... Args>
inline std::unique_ptr<T, Deleter<T>> make_unique(Args&&... args)
{
return std::unique_ptr<T, Deleter<T>>(new(Vc::malloc<T, A>(1)) T(std::forward<Args>(args)...));
}
}
}
#endif
namespace Vc_VERSIONED_NAMESPACE
{
using Common::make_unique;
}
#endif
#ifndef VC_UTILS_
#define VC_UTILS_
#ifdef Vc_IMPL_Scalar
#define VECTOR_NAMESPACE Scalar
#else
#define VECTOR_NAMESPACE SSE
#endif
#ifndef VC_COMMON_DEINTERLEAVE_H_
#define VC_COMMON_DEINTERLEAVE_H_
namespace Vc_VERSIONED_NAMESPACE
{
template<typename V, typename M, typename A> Vc_ALWAYS_INLINE void deinterleave(V *a, V *b,
const M *memory, A align)
{
Detail::deinterleave(*a, *b, memory, align);
}
template<typename V, typename M> Vc_ALWAYS_INLINE void deinterleave(V *a, V *b,
const M *memory)
{
Detail::deinterleave(*a, *b, memory, Aligned);
}
}
#endif
#ifndef VC_COMMON_MAKECONTAINER_H_
#define VC_COMMON_MAKECONTAINER_H_
#include <initializer_list>
namespace Vc_VERSIONED_NAMESPACE
{
namespace
{
template<typename Container, typename T> struct make_container_helper
{
static constexpr Container help(std::initializer_list<T> list) { return { list }; }
};
template <typename T_, typename Abi, typename Alloc,
template <class, class> class Container>
struct make_container_helper<Container<Vector<T_, Abi>, Alloc>,
typename Vector<T_, Abi>::EntryType> {
typedef Vector<T_, Abi> V;
typedef typename V::EntryType T;
typedef Container<V, Alloc> C;
static inline C help(std::initializer_list<T> list) {
const std::size_t size = (list.size() + (V::Size - 1)) / V::Size;
C v(size);
auto containerIt = v.begin();
auto init = std::begin(list);
const auto initEnd = std::end(list);
for (std::size_t i = 0; i < size - 1; ++i) {
*containerIt++ = V(init, Vc::Unaligned);
init += V::Size;
}
Vc_ASSERT(all_of(*containerIt == V::Zero()));
int j = 0;
while (init != initEnd) {
(*containerIt)[j++] = *init++;
}
return v;
}
};
template <typename T_, typename Abi, std::size_t N,
template <class, std::size_t> class Container>
struct make_container_helper<Container<Vector<T_, Abi>, N>,
typename Vector<T_, Abi>::EntryType> {
typedef Vector<T_, Abi> V;
typedef typename V::EntryType T;
static constexpr std::size_t size = (N + (V::Size - 1)) / V::Size;
typedef Container<
V,
#if defined Vc_CLANG && Vc_CLANG < 0x30700
(size == 1 && std::is_same<Abi, VectorAbi::Avx>::value) ? 2 :
#endif
size> C;
static inline C help(std::initializer_list<T> list) {
Vc_ASSERT(N == list.size())
Vc_ASSERT(size == (list.size() + (V::Size - 1)) / V::Size)
C v;
auto containerIt = v.begin();
auto init = std::begin(list);
const auto initEnd = std::end(list);
for (std::size_t i = 0; i < size - 1; ++i) {
*containerIt++ = V(init, Vc::Unaligned);
init += V::Size;
}
Vc_ASSERT(all_of(*containerIt == V::Zero()));
int j = 0;
while (init != initEnd) {
(*containerIt)[j++] = *init++;
}
return v;
}
};
}
template<typename Container, typename T>
constexpr auto makeContainer(std::initializer_list<T> list) -> decltype(make_container_helper<Container, T>::help(list))
{
return make_container_helper<Container, T>::help(list);
}
template<typename Container, typename T>
constexpr auto make_container(std::initializer_list<T> list) -> decltype(makeContainer<Container, T>(list))
{
return makeContainer<Container, T>(list);
}
}
#endif
#endif
#ifndef VC_INCLUDE_VC_ITERATORS_H_
#define VC_INCLUDE_VC_ITERATORS_H_
#ifndef VC_COMMON_ITERATORS_H_
#define VC_COMMON_ITERATORS_H_
#include <array>
#include <iterator>
#ifdef Vc_MSVC
#include <intrin.h>
#endif
namespace Vc_VERSIONED_NAMESPACE
{
namespace Common
{
template<typename _V, typename Flags> class MemoryVector;
template<typename _V, typename Flags> class MemoryVectorIterator;
template <typename V> class Iterator;
template <typename V, bool> class IteratorBase;
template <typename V> class IteratorBase<V, true>
{
public:
using iterator_category = std::input_iterator_tag;
using value_type = typename V::value_type;
using difference_type = int;
using reference = value_type;
Vc_ALWAYS_INLINE reference operator*() const { return v()[i()]; }
Vc_ALWAYS_INLINE reference operator[](difference_type i2) const { return v()[i2]; }
private:
Vc_INTRINSIC V &v() const { return *static_cast<const Iterator<V> *>(this)->v; }
Vc_INTRINSIC difference_type i() const
{
return static_cast<const Iterator<V> *>(this)->i;
}
};
template <typename V> class IteratorBase<V, false>
{
public:
using iterator_category = std::input_iterator_tag;
using value_type = typename V::value_type;
using difference_type = int;
using reference = Vc::Detail::ElementReference<V, IteratorBase>;
Vc_ALWAYS_INLINE reference operator*() const { return {*v(), i()}; }
Vc_ALWAYS_INLINE reference operator[](difference_type i2) const { return {*v(), i2}; }
private:
Vc_INTRINSIC V *v() const { return static_cast<const Iterator<V> *>(this)->v; }
Vc_INTRINSIC difference_type i() const
{
return static_cast<const Iterator<V> *>(this)->i;
}
friend reference;
static Vc_INTRINSIC value_type get(const V &o, int i)
{
return o[i];
}
template <typename T> static Vc_INTRINSIC void set(V &o, int i, T &&v)
{
o[i] = std::forward<T>(v);
}
};
template <typename V> class Iterator : public IteratorBase<V, std::is_const<V>::value>
{
using Base = IteratorBase<V, std::is_const<V>::value>;
friend Base;
public:
using typename Base::iterator_category;
using typename Base::value_type;
using typename Base::difference_type;
using pointer = const Iterator *;
using typename Base::reference;
constexpr Iterator() = default;
constexpr Iterator(V &_v, difference_type _i) : v(&_v), i(_i) {}
Vc_ALWAYS_INLINE pointer operator->() const { return this; }
using Base::operator*;
Vc_ALWAYS_INLINE Iterator &operator++() { ++i; return *this; }
Vc_ALWAYS_INLINE Iterator operator++(int) { Iterator tmp = *this; ++i; return tmp; }
Vc_ALWAYS_INLINE Iterator &operator--() { --i; return *this; }
Vc_ALWAYS_INLINE Iterator operator--(int) { Iterator tmp = *this; --i; return tmp; }
using Base::operator[];
Vc_ALWAYS_INLINE Iterator &operator+=(difference_type d) { i += d; return *this; }
Vc_ALWAYS_INLINE Iterator &operator-=(difference_type d) { i -= d; return *this; }
Vc_ALWAYS_INLINE Iterator operator+(difference_type d) const { return {*v, i + d}; }
Vc_ALWAYS_INLINE Iterator operator-(difference_type d) const { return {*v, i - d}; }
Vc_ALWAYS_INLINE difference_type operator-(const Iterator &rhs) const { return i - rhs.i; }
friend Vc_ALWAYS_INLINE Iterator operator+(difference_type d, const Iterator &rhs)
{
return {*rhs.v, rhs.i + d};
}
Vc_ALWAYS_INLINE bool operator==(const Iterator<V> &rhs) const { return v == rhs.v && i == rhs.i; }
Vc_ALWAYS_INLINE bool operator!=(const Iterator<V> &rhs) const { return v == rhs.v && i != rhs.i; }
Vc_ALWAYS_INLINE bool operator< (const Iterator<V> &rhs) const { return v == rhs.v && i < rhs.i; }
Vc_ALWAYS_INLINE bool operator<=(const Iterator<V> &rhs) const { return v == rhs.v && i <= rhs.i; }
Vc_ALWAYS_INLINE bool operator> (const Iterator<V> &rhs) const { return v == rhs.v && i > rhs.i; }
Vc_ALWAYS_INLINE bool operator>=(const Iterator<V> &rhs) const { return v == rhs.v && i >= rhs.i; }
private:
V *v = nullptr;
difference_type i = 0;
};
template <typename V> using ConstIterator = Iterator<const V>;
class BitmaskIterator
{
#ifdef Vc_MSVC
unsigned long mask;
unsigned long bit;
#else
size_t mask;
size_t bit;
#endif
void nextBit()
{
#ifdef Vc_GNU_ASM
bit = __builtin_ctzl(mask);
#elif defined(Vc_MSVC)
_BitScanForward(&bit, mask);
#else
#error "Not implemented yet. Please contact vc-devel@compeng.uni-frankfurt.de"
#endif
}
void resetLsb()
{
mask &= (mask - 1);
}
public:
BitmaskIterator(decltype(mask) m) : mask(m) { nextBit(); }
BitmaskIterator(const BitmaskIterator &) = default;
BitmaskIterator(BitmaskIterator &&) = default;
Vc_ALWAYS_INLINE size_t operator->() const { return bit; }
Vc_ALWAYS_INLINE size_t operator*() const { return bit; }
Vc_ALWAYS_INLINE BitmaskIterator &operator++() { resetLsb(); nextBit(); return *this; }
Vc_ALWAYS_INLINE BitmaskIterator operator++(int) { BitmaskIterator tmp = *this; resetLsb(); nextBit(); return tmp; }
Vc_ALWAYS_INLINE bool operator==(const BitmaskIterator &rhs) const { return mask == rhs.mask; }
Vc_ALWAYS_INLINE bool operator!=(const BitmaskIterator &rhs) const { return mask != rhs.mask; }
};
template <typename T>
Vc_ALWAYS_INLINE
enable_if<Traits::is_simd_vector<T>::value || Traits::is_simd_mask<T>::value,
Iterator<typename std::remove_reference<T>::type>>
begin(T &&x)
{
return {std::forward<T>(x), 0};
}
template <typename T>
Vc_ALWAYS_INLINE
enable_if<Traits::is_simd_vector<T>::value || Traits::is_simd_mask<T>::value,
Iterator<typename std::remove_reference<T>::type>>
end(T &&x)
{
using TT = typename std::decay<T>::type;
return {std::forward<T>(x), int(TT::size())};
}
template <typename T>
Vc_ALWAYS_INLINE enable_if<
Traits::is_simd_mask<T>::value || Traits::is_simd_vector<T>::value, ConstIterator<T>>
cbegin(const T &v)
{
return {v, 0};
}
template <typename T>
Vc_ALWAYS_INLINE enable_if<
Traits::is_simd_mask<T>::value || Traits::is_simd_vector<T>::value, ConstIterator<T>>
cend(const T &v)
{
return {v, int(T::size())};
}
template<typename M> Vc_ALWAYS_INLINE BitmaskIterator begin(const WhereImpl::WhereMask<M> &w)
{
return w.mask.toInt();
}
template<typename M> Vc_ALWAYS_INLINE BitmaskIterator end(const WhereImpl::WhereMask<M> &)
{
return 0;
}
template<typename V, typename Flags, typename T> Vc_ALWAYS_INLINE MemoryVectorIterator<V, Flags>
makeIterator(T *mem, Flags)
{
return new(mem) MemoryVector<V, Flags>;
}
template<typename V, typename Flags, typename T> Vc_ALWAYS_INLINE MemoryVectorIterator<const V, Flags>
makeIterator(const T *mem, Flags)
{
return new(const_cast<T *>(mem)) MemoryVector<const V, Flags>;
}
template<typename V, typename Flags, typename FlagsX> Vc_ALWAYS_INLINE MemoryVectorIterator<V, Flags>
makeIterator(MemoryVector<V, FlagsX> &mv, Flags)
{
return new(&mv) MemoryVector<V, Flags>;
}
template<typename V, typename Flags, typename FlagsX> Vc_ALWAYS_INLINE MemoryVectorIterator<const V, Flags>
makeIterator(MemoryVector<const V, FlagsX> &mv, Flags)
{
return new(&mv) MemoryVector<const V, Flags>;
}
}
using Common::begin;
using Common::end;
using Common::cbegin;
using Common::cend;
using Common::makeIterator;
}
#endif
namespace Vc_VERSIONED_NAMESPACE
{
using ::Vc::Common::begin;
using ::Vc::Common::end;
using ::Vc::Common::makeIterator;
}
#endif
#ifndef VC_INCLUDE_VC_ARRAY_
#define VC_INCLUDE_VC_ARRAY_
#include <type_traits>
#include <utility>
#include <iterator>
#include <algorithm>
#include <stdexcept>
#ifndef VC_COMMON_SUBSCRIPT_H_
#define VC_COMMON_SUBSCRIPT_H_
#include <initializer_list>
#include <type_traits>
#include <vector>
#include <assert.h>
namespace Vc_VERSIONED_NAMESPACE
{
namespace Common
{
template <typename Base> class AdaptSubscriptOperator : public Base
{
public:
template <typename... Args>
Vc_ALWAYS_INLINE AdaptSubscriptOperator(Args &&... arguments)
: Base(std::forward<Args>(arguments)...)
{
}
template <typename T>
Vc_ALWAYS_INLINE AdaptSubscriptOperator(std::initializer_list<T> l)
: Base(l)
{
}
using Base::operator[];
template <typename I,
typename = enable_if<!std::is_arithmetic<
typename std::decay<I>::type>::value>
>
Vc_ALWAYS_INLINE auto operator[](I &&arg_)
-> decltype(subscript_operator(*this, std::forward<I>(arg_)))
{
return subscript_operator(*this, std::forward<I>(arg_));
}
template <typename I, typename = enable_if<
!std::is_arithmetic<typename std::decay<I>::type>::value>>
Vc_ALWAYS_INLINE auto operator[](I &&arg_) const
-> decltype(subscript_operator(*this, std::forward<I>(arg_)))
{
return subscript_operator(*this, std::forward<I>(arg_));
}
};
template <class T, class = decltype(convertIndexVector(std::declval<T>()))>
std::true_type is_valid_indexvector(T &&);
std::false_type is_valid_indexvector(...);
template <class IndexVector, class Test = decltype(is_valid_indexvector(
std::declval<const IndexVector &>()))>
struct is_valid_indexvector_ : public std::integral_constant<bool, Test::value> {
};
static_assert(!is_valid_indexvector_<const int *>::value,
"Pointer is incorrectly classified as valid index vector type");
static_assert(is_valid_indexvector_<const int[4]>::value,
"C-Array is incorrectly classified as invalid index vector type");
template <typename Scale, typename T>
Vc_ALWAYS_INLINE enable_if<Scale::num == Scale::den, Traits::decay<T>> applyScale(T &&x)
{
return std::forward<T>(x);
}
template <typename Scale, typename T>
Vc_ALWAYS_INLINE enable_if<
Scale::num != Scale::den && Traits::has_multiply_operator<T, int>::value,
Traits::decay<T>>
applyScale(T &&x)
{
static_assert(Scale::num % Scale::den == 0,
"Non-integral index scaling requested. This typically happens only for "
"Vc::Scalar on 32-bit for gathers on double. You can work around the "
"issue by ensuring that all doubles in the structure are aligned on 8 "
"Bytes.");
constexpr int value = Scale::num / Scale::den;
Vc_ASSERT(Vc::all_of((x * value) / value == x));
return std::forward<T>(x) * value;
}
template <typename Scale, typename T>
Vc_ALWAYS_INLINE enable_if<
Scale::num != Scale::den && !Traits::has_multiply_operator<T, int>::value,
T>
applyScale(T x)
{
static_assert(Scale::num % Scale::den == 0,
"Non-integral index scaling requested. This typically happens only for "
"Vc::Scalar on 32-bit for gathers on double. You can work around the "
"issue by ensuring that all doubles in the structure are aligned on 8 "
"Bytes.");
constexpr int value = Scale::num / Scale::den;
for (size_t i = 0; i < x.size(); ++i) {
Vc_ASSERT((x[i] * value) / value == x[i]);
x[i] *= value;
}
return x;
}
template <typename Scale, typename T, typename U,
typename = enable_if<Traits::has_multiply_operator<T, int>::value &&
Traits::has_addition_operator<T, U>::value>>
Vc_ALWAYS_INLINE typename std::decay<T>::type applyScaleAndAdd(T &&x, U &&y)
{
constexpr int value = Scale::num / Scale::den;
if (value == 1) {
return std::forward<T>(x) + std::forward<U>(y);
}
return std::forward<T>(x) * value + std::forward<U>(y);
}
template <
typename Scale, typename T, typename U,
typename = enable_if<
!(Traits::has_multiply_operator<T &, int>::value &&
Traits::has_addition_operator<T &, decltype(std::declval<U>()[0])>::value) &&
Traits::has_subscript_operator<U>::value>>
Vc_ALWAYS_INLINE T applyScaleAndAdd(T x, U &&y)
{
constexpr int value = Scale::num / Scale::den;
for (size_t i = 0; i < x.size(); ++i) {
if (value == 1) {
x[i] = x[i] + y[i];
} else {
x[i] = x[i] * value + y[i];
}
}
return x;
}
template <typename Scale, typename T, typename U>
Vc_ALWAYS_INLINE enable_if<!(Traits::has_multiply_operator<T &, int>::value &&
Traits::has_addition_operator<T &, U>::value) &&
!Traits::has_subscript_operator<U>::value,
T>
applyScaleAndAdd(T x, U &&y)
{
constexpr int value = Scale::num / Scale::den;
for (size_t i = 0; i < x.size(); ++i) {
if (value == 1) {
x[i] = x[i] + y;
} else {
x[i] = x[i] * value + y;
}
}
return x;
}
template <std::size_t MinSize,
typename IndexT,
bool = Traits::is_simd_vector<IndexT>::value>
struct IndexVectorSizeMatches
: public std::true_type
{
};
template <std::size_t MinSize, typename V>
struct IndexVectorSizeMatches<MinSize,
V,
true> : public std::integral_constant<bool, (MinSize <= V::Size)>
{
};
template <std::size_t MinSize, typename T, std::size_t ArraySize>
struct IndexVectorSizeMatches<MinSize,
T[ArraySize],
false> : public std::integral_constant<bool, (MinSize <= ArraySize)>
{
};
template <std::size_t MinSize, typename T, std::size_t ArraySize>
struct IndexVectorSizeMatches<MinSize,
std::array<T, ArraySize>,
false> : public std::integral_constant<bool, (MinSize <= ArraySize)>
{
};
template <std::size_t MinSize, typename T, std::size_t ArraySize>
struct IndexVectorSizeMatches<MinSize,
Vc::array<T, ArraySize>,
false> : public std::integral_constant<bool, (MinSize <= ArraySize)>
{
};
template <std::size_t MinSize, typename T, std::ptrdiff_t N>
struct IndexVectorSizeMatches<MinSize, Vc::Common::span<T, N>, false>
: public std::integral_constant<bool, (N == -1 || static_cast<std::ptrdiff_t>(MinSize) <= N)> {
};
template <
typename T, typename IndexVector, typename Scale = std::ratio<1, 1>,
bool = is_valid_indexvector_<IndexVector>::value>
class SubscriptOperation
{
const IndexVector m_indexes;
T *const m_address;
using ScalarType = typename std::decay<T>::type;
using IndexVectorScaled = Traits::decay<decltype(convertIndexVector(std::declval<const IndexVector &>()))>;
public:
SubscriptOperation &operator=(const SubscriptOperation &) = delete;
SubscriptOperation(const SubscriptOperation &) = delete;
#ifndef __cpp_guaranteed_copy_elision
constexpr SubscriptOperation(SubscriptOperation &&) = default;
#endif
template <typename U,
typename = enable_if<((std::is_convertible<const U &, IndexVector>::value ||
std::is_same<U, IndexVector>::value) &&
std::is_copy_constructible<IndexVector>::value)>>
constexpr Vc_ALWAYS_INLINE SubscriptOperation(T *address, const U &indexes)
: m_indexes(indexes), m_address(address)
{
}
template <std::size_t... Indexes>
constexpr Vc_ALWAYS_INLINE SubscriptOperation(T *address, const IndexVector &indexes,
index_sequence<Indexes...>)
: m_indexes{indexes[Indexes]...}, m_address(address)
{}
template <typename U>
constexpr Vc_ALWAYS_INLINE SubscriptOperation(
T *address, const U &indexes,
enable_if<((std::is_convertible<const U &, IndexVector>::value ||
std::is_same<U, IndexVector>::value) &&
!std::is_copy_constructible<IndexVector>::value &&
std::is_array<IndexVector>::value &&
std::extent<IndexVector>::value > 0)> = nullarg)
: SubscriptOperation(address, indexes,
make_index_sequence<std::extent<IndexVector>::value>())
{
}
static constexpr bool need_explicit_scaling =
Scale::num % Scale::den != 0 || Scale::num / Scale::den * sizeof(T) > 8;
Vc_ALWAYS_INLINE
GatherArguments<typename std::remove_cv<T>::type, IndexVectorScaled,
(need_explicit_scaling ? 1 : Scale::num / Scale::den)>
gatherArguments() &&
{
static_assert(std::is_arithmetic<ScalarType>::value,
"Incorrect type for a SIMD vector gather. Must be an arithmetic type.");
return {applyScale<typename std::conditional<need_explicit_scaling, Scale,
std::ratio<1, 1>>::type>(
convertIndexVector(m_indexes)),
m_address};
}
Vc_ALWAYS_INLINE ScatterArguments<T, IndexVectorScaled> scatterArguments() &&
{
static_assert(std::is_arithmetic<ScalarType>::value,
"Incorrect type for a SIMD vector scatter. Must be an arithmetic type.");
return {applyScale<Scale>(convertIndexVector(m_indexes)), m_address};
}
template <typename V,
typename = enable_if<(std::is_arithmetic<ScalarType>::value &&Traits::is_simd_vector<
V>::value &&IndexVectorSizeMatches<V::Size, IndexVector>::value)>>
Vc_INTRINSIC operator V() &&
{
return V(static_cast<SubscriptOperation &&>(*this).gatherArguments());
}
template <typename V,
typename = enable_if<(std::is_arithmetic<ScalarType>::value &&Traits::is_simd_vector<
V>::value &&IndexVectorSizeMatches<V::Size, IndexVector>::value)>>
Vc_ALWAYS_INLINE SubscriptOperation &operator=(const V &rhs) &&
{
static_assert(std::is_arithmetic<ScalarType>::value,
"Incorrect type for a SIMD vector scatter. Must be an arithmetic type.");
const auto indexes = applyScale<Scale>(convertIndexVector(m_indexes));
rhs.scatter(m_address, indexes);
return *this;
}
template <
typename U,
typename S,
typename = enable_if<std::is_same<S, typename std::remove_cv<T>::type>::value &&(
std::is_class<T>::value || std::is_union<T>::value)>>
Vc_ALWAYS_INLINE auto operator[](U S::*member) &&
-> SubscriptOperation<
typename std::conditional<std::is_const<T>::value,
const typename std::remove_reference<U>::type,
typename std::remove_reference<U>::type>::type,
IndexVector,
std::ratio_multiply<Scale, std::ratio<sizeof(S), sizeof(U)>>>
{
static_assert(std::is_same<Traits::decay<decltype(m_address->*member)>,
Traits::decay<U>>::value,
"Type mismatch that should be impossible.");
return {&(m_address->*member), m_indexes};
}
private:
template <intmax_t N, intmax_t D> struct make_ratio {
using type = std::ratio<N, D == 0 ? 1 : D>;
};
public:
template <typename U>
Vc_ALWAYS_INLINE auto operator[](U index) && -> typename std::enable_if<
#ifndef Vc_IMPROVE_ERROR_MESSAGES
Traits::has_no_allocated_data<T>::value &&
#endif
std::is_convertible<U, size_t>::value,
SubscriptOperation<
typename std::remove_reference<decltype(m_address[0][index])>::type,
IndexVector,
std::ratio_multiply<
Scale,
typename make_ratio<sizeof(T), sizeof(m_address[0][index])>::type>>>::type
{
static_assert(Traits::has_subscript_operator<T>::value,
"The subscript operator was called on a type that does not implement it.\n");
static_assert(Traits::has_no_allocated_data<T>::value,
"Invalid container type in gather/scatter operation.\nYou may only use "
"nested containers that store the data inside the object (such as builtin "
"arrays or std::array) but not containers that store data in allocated "
"memory (such as std::vector).\nSince this feature cannot be queried "
"generically at compile time you need to spezialize the "
"Vc::Traits::has_no_allocated_data_impl<T> type-trait for custom types that "
"meet the requirements.\n");
static_assert(std::is_lvalue_reference<decltype(m_address[0][index])>::value,
"The container does not return an lvalue reference to the data at "
"the requested offset. This makes it impossible to execute a "
"gather operation.\n");
return {&(m_address[0][index]), m_indexes};
}
template <typename IT>
Vc_ALWAYS_INLINE typename std::enable_if<
#ifndef Vc_IMPROVE_ERROR_MESSAGES
Traits::has_no_allocated_data<T>::value &&
Traits::has_subscript_operator<T>::value &&
#endif
Traits::has_subscript_operator<IT>::value,
SubscriptOperation<typename std::remove_reference<decltype(
m_address[0][std::declval<
const IT &>()[0]]
)>::type,
IndexVectorScaled,
std::ratio<1, 1>
>>::type
operator[](const IT &index) &&
{
static_assert(Traits::has_subscript_operator<T>::value,
"The subscript operator was called on a type that does not implement it.\n");
static_assert(Traits::has_no_allocated_data<T>::value,
"Invalid container type in gather/scatter operation.\nYou may only use "
"nested containers that store the data inside the object (such as builtin "
"arrays or std::array) but not containers that store data in allocated "
"memory (such as std::vector).\nSince this feature cannot be queried "
"generically at compile time you need to spezialize the "
"Vc::Traits::has_no_allocated_data_impl<T> type-trait for custom types that "
"meet the requirements.\n");
return {&(m_address[0][0]),
applyScaleAndAdd<std::ratio_multiply<
Scale, std::ratio<sizeof(T), sizeof(m_address[0][0])>>>(
convertIndexVector(m_indexes), index)};
}
};
template <typename T, typename IndexVector, typename Scale>
class SubscriptOperation<T, IndexVector, Scale, false>;
template <
typename Container,
typename IndexVector,
typename = enable_if<
Traits::has_subscript_operator<IndexVector>::value
&&Traits::has_contiguous_storage<Container>::value
&&std::is_lvalue_reference<decltype(*begin(std::declval<
Container>()))>::value
>>
Vc_ALWAYS_INLINE SubscriptOperation<
typename std::remove_reference<decltype(*begin(std::declval<Container>()))>::
type,
typename std::remove_const<typename std::remove_reference<
IndexVector>::type>::type
> subscript_operator(Container &&c, IndexVector &&indexes)
{
Vc_ASSERT(std::addressof(*begin(c)) + 1 ==
std::addressof(*(begin(c) + 1)));
return {std::addressof(*begin(c)), std::forward<IndexVector>(indexes)};
}
template <typename Container, typename I>
Vc_ALWAYS_INLINE Vc::Common::SubscriptOperation<
typename std::remove_reference<decltype(std::declval<Container>()[0])>::type,
const std::initializer_list<I> &> subscript_operator(Container &&vec,
const std::initializer_list<I> &indexes)
{
return {&vec[0], indexes};
}
}
using Common::subscript_operator;
}
#endif
namespace Vc_VERSIONED_NAMESPACE
{
template <class T, size_t Size> struct array {
typedef array self_;
typedef T value_type;
typedef value_type& reference;
typedef const value_type& const_reference;
typedef value_type* iterator;
typedef const value_type* const_iterator;
typedef value_type* pointer;
typedef const value_type* const_pointer;
typedef size_t size_type;
typedef ptrdiff_t difference_type;
typedef std::reverse_iterator<iterator> reverse_iterator;
typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
value_type elems_[Size > 0 ? Size : 1];
void fill(const value_type& u_) { std::fill_n(elems_, Size, u_); }
void swap(array& a_) noexcept(std::swap(std::declval<T &>(), std::declval<T &>()))
{
std::swap_ranges(elems_, elems_ + Size, a_.elems_);
}
iterator begin() noexcept { return iterator(elems_); }
const_iterator begin() const noexcept { return const_iterator(elems_); }
iterator end() noexcept { return iterator(elems_ + Size); }
const_iterator end() const noexcept { return const_iterator(elems_ + Size); }
reverse_iterator rbegin() noexcept { return reverse_iterator(end()); }
const_reverse_iterator rbegin() const noexcept
{
return const_reverse_iterator(end());
}
reverse_iterator rend() noexcept { return reverse_iterator(begin()); }
const_reverse_iterator rend() const noexcept
{
return const_reverse_iterator(begin());
}
const_iterator cbegin() const noexcept { return begin(); }
const_iterator cend() const noexcept { return end(); }
const_reverse_iterator crbegin() const noexcept { return rbegin(); }
const_reverse_iterator crend() const noexcept { return rend(); }
constexpr size_type size() const noexcept { return Size; }
constexpr size_type max_size() const noexcept { return Size; }
constexpr bool empty() const noexcept { return Size == 0; }
reference operator[](size_type n_) { return elems_[n_]; }
constexpr const_reference operator[](size_type n_) const { return elems_[n_]; }
template <typename I>
Vc_ALWAYS_INLINE auto operator[](I&& arg_)
-> decltype(subscript_operator(*this, std::forward<I>(arg_)))
{
return subscript_operator(*this, std::forward<I>(arg_));
}
template <typename I>
Vc_ALWAYS_INLINE auto operator[](I&& arg_) const
-> decltype(subscript_operator(*this, std::forward<I>(arg_)))
{
return subscript_operator(*this, std::forward<I>(arg_));
}
reference at(size_type n_);
constexpr const_reference at(size_type n_) const;
reference front() { return elems_[0]; }
constexpr const_reference front() const { return elems_[0]; }
reference back() { return elems_[Size > 0 ? Size - 1 : 0]; }
constexpr const_reference back() const { return elems_[Size > 0 ? Size - 1 : 0]; }
value_type* data() noexcept { return elems_; }
const value_type* data() const noexcept { return elems_; }
};
template <class T, size_t Size>
typename array<T, Size>::reference array<T, Size>::at(size_type n_)
{
if (n_ >= Size) {
throw std::out_of_range("array::at");
}
return elems_[n_];
}
template <class T, size_t Size>
constexpr typename array<T, Size>::const_reference array<T, Size>::at(size_type n_) const
{
return n_ >= Size ? (throw std::out_of_range("array::at"), elems_[0]) : elems_[n_];
}
template <class T, size_t Size>
inline bool operator==(const array<T, Size>& x_, const array<T, Size>& y_)
{
return std::equal(x_.elems_, x_.elems_ + Size, y_.elems_);
}
template <class T, size_t Size>
inline bool operator!=(const array<T, Size>& x_, const array<T, Size>& y_)
{
return !(x_ == y_);
}
template <class T, size_t Size>
inline bool operator<(const array<T, Size>& x_, const array<T, Size>& y_)
{
return std::lexicographical_compare(x_.elems_, x_.elems_ + Size, y_.elems_,
y_.elems_ + Size);
}
template <class T, size_t Size>
inline bool operator>(const array<T, Size>& x_, const array<T, Size>& y_)
{
return y_ < x_;
}
template <class T, size_t Size>
inline bool operator<=(const array<T, Size>& x_, const array<T, Size>& y_)
{
return !(y_ < x_);
}
template <class T, size_t Size>
inline bool operator>=(const array<T, Size>& x_, const array<T, Size>& y_)
{
return !(x_ < y_);
}
template <typename T, std::size_t N>
inline auto begin(array<T, N>& arr) -> decltype(arr.begin())
{
return arr.begin();
}
template <typename T, std::size_t N>
inline auto begin(const array<T, N>& arr) -> decltype(arr.begin())
{
return arr.begin();
}
template <typename T, std::size_t N>
inline auto end(array<T, N>& arr) -> decltype(arr.end())
{
return arr.end();
}
template <typename T, std::size_t N>
inline auto end(const array<T, N>& arr) -> decltype(arr.end())
{
return arr.end();
}
namespace Traits
{
template <typename T, std::size_t N>
struct has_no_allocated_data_impl<Vc::array<T, N>> : public std::true_type
{
};
template <typename T, std::size_t N>
struct has_contiguous_storage_impl<Vc::array<T, N>> : public std::true_type
{
};
}
}
namespace std
{
template <class T, size_t Size>
inline
#ifdef Vc_MSVC
void
#else
typename enable_if<is_same<void, decltype(swap(declval<T&>(), declval<T&>()))>::value,
void>::type
#endif
swap(const Vc::array<T, Size>& x_,
const Vc::array<T, Size>& y_) noexcept(swap(declval<T&>(), declval<T&>()))
{
x_.swap(y_);
}
template <class T, size_t Size>
class tuple_size<Vc::array<T, Size>> : public integral_constant<size_t, Size>
{
};
template <size_t I, class T, size_t Size> class tuple_element<I, Vc::array<T, Size>>
{
public:
typedef T type;
};
template <size_t I, class T, size_t Size>
inline constexpr typename std::enable_if<(I < Size), T&>::type get(
Vc::array<T, Size>& a_) noexcept
{
return a_.elems_[I];
}
template <size_t I, class T, size_t Size>
inline constexpr typename std::enable_if<(I < Size), const T&>::type get(
const Vc::array<T, Size>& a_) noexcept
{
return a_.elems_[I];
}
template <size_t I, class T, size_t Size>
inline constexpr typename std::enable_if<(I < Size), T&&>::type get(
Vc::array<T, Size>&& a_) noexcept
{
return std::move(a_.elems_[I]);
}
}
#endif
#ifndef VC_COMMON_SPAN_H_
#define VC_COMMON_SPAN_H_
#include <array>
#include <cstddef>
#include <cstddef>
#include <iterator>
#include <type_traits>
namespace Vc_VERSIONED_NAMESPACE
{
#ifdef __cpp_inline_variables
inline
#endif
constexpr ptrdiff_t dynamic_extent = -1;
namespace Common
{
template <typename T, ptrdiff_t Extent = dynamic_extent> class span;
template <typename T, ptrdiff_t Extent>
constexpr auto begin(const span<T, Extent>& s) noexcept -> decltype(s.begin())
{
return s.begin();
}
template <typename T, ptrdiff_t Extent>
constexpr auto end(const span<T, Extent>& s) noexcept -> decltype(s.end())
{
return s.end();
}
template <class T> struct _is_span_impl : public std::false_type {
};
template <class T, ptrdiff_t Extent>
struct _is_span_impl<span<T, Extent>> : public std::true_type {
};
template <class T>
struct _is_span : public _is_span_impl<typename std::remove_cv<T>::type> {
};
template <class T> struct _is_std_array_impl : public std::false_type {
};
template <class T, size_t Sz>
struct _is_std_array_impl<array<T, Sz>> : public std::true_type {
};
template <class T>
struct _is_std_array : public _is_std_array_impl<typename std::remove_cv<T>::type> {
};
template <class T, class ElementType, class = void>
struct _is_span_compatible_container : public std::false_type {
};
template <class... Ts> using _void_t = void;
template <class C> constexpr auto _std_data(C& c) -> decltype(c.data())
{
return c.data();
}
template <class C> constexpr auto _std_data(const C& c) -> decltype(c.data())
{
return c.data();
}
template <class T, std::size_t N> constexpr T* _std_data(T (&array)[N]) noexcept
{
return array;
}
template <class E> constexpr const E* _std_data(std::initializer_list<E> il) noexcept
{
return il.begin();
}
template <class C> constexpr auto _std_size(const C& c) -> decltype(c.size())
{
return c.size();
}
template <class T, std::size_t N>
constexpr std::size_t _std_size(const T (&array)[N]) noexcept
{
return N;
}
template <class T, class ElementType>
struct _is_span_compatible_container<
T, ElementType,
_void_t<
typename std::enable_if<!_is_span<T>::value, std::nullptr_t>::type,
typename std::enable_if<!_is_std_array<T>::value, std::nullptr_t>::type,
typename std::enable_if<!std::is_array<T>::value, std::nullptr_t>::type,
decltype(data(std::declval<T>())), decltype(size(std::declval<T>())),
typename std::enable_if<
std::is_convertible<typename std::remove_pointer<decltype(
data(std::declval<T&>()))>::type (*)[],
ElementType (*)[]>::value,
std::nullptr_t>::type>> : public std::true_type {
};
#if defined Vc_MSVC || (defined Vc_GCC && Vc_GCC < 0x50100) || defined Vc_ICC || !defined __cpp_constexpr || __cpp_constexpr < 201304
#define Vc_CONSTEXPR
#else
#define Vc_CONSTEXPR constexpr
#endif
template <typename T, ptrdiff_t Extent> class span
{
public:
using element_type = T;
using value_type = typename std::remove_cv<T>::type;
using index_type = ptrdiff_t;
using difference_type = ptrdiff_t;
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>;
static constexpr index_type extent = Extent;
static_assert(Extent >= 0, "Can't have a span with an extent < 0");
Vc_CONSTEXPR span() noexcept : data_{nullptr}
{
static_assert(Extent == 0,
"Can't default construct a statically sized span with size > 0");
}
Vc_CONSTEXPR span(const span&) noexcept = default;
Vc_CONSTEXPR span& operator=(const span&) noexcept = default;
Vc_CONSTEXPR span(pointer _ptr, index_type _count) : data_{_ptr}
{
(void)_count;
Vc_ASSERT(((void)"size mismatch in span's constructor (ptr, len)", Extent == _count));
}
Vc_CONSTEXPR span(pointer _f, pointer _l) : data_{_f}
{
(void)_l;
Vc_ASSERT(((void)"size mismatch in span's constructor (ptr, ptr)",
Extent == distance(_f, _l)));
}
Vc_CONSTEXPR span(element_type (&_arr)[Extent]) noexcept : data_{_arr} {}
Vc_CONSTEXPR span(array<value_type, Extent>& _arr) noexcept : data_{_arr.data()} {}
Vc_CONSTEXPR span(const array<value_type, Extent>& _arr) noexcept : data_{_arr.data()} {}
template <class Container>
inline Vc_CONSTEXPR span(
Container& _c,
typename std::enable_if<_is_span_compatible_container<Container, T>::value,
std::nullptr_t>::type = nullptr)
: data_{_std_data(_c)}
{
Vc_ASSERT(("size mismatch in span's constructor (container))",
Extent == _std_size(_c)));
}
template <class Container>
inline Vc_CONSTEXPR span(
const Container& _c,
typename std::enable_if<_is_span_compatible_container<const Container, T>::value,
std::nullptr_t>::type = nullptr)
: data_{_std_data(_c)}
{
Vc_ASSERT(("size mismatch in span's constructor (const container)",
Extent == _std_size(_c)));
}
template <class OtherElementType>
inline Vc_CONSTEXPR span(
const span<OtherElementType, Extent>& _other,
typename std::enable_if<
std::is_convertible<OtherElementType (*)[], element_type (*)[]>::value,
std::nullptr_t>::type = nullptr)
: data_{_other.data()}
{
}
template <class OtherElementType>
inline Vc_CONSTEXPR span(
const span<OtherElementType, dynamic_extent>& _other,
typename std::enable_if<
std::is_convertible<OtherElementType (*)[], element_type (*)[]>::value,
std::nullptr_t>::type = nullptr) noexcept
: data_{_other.data()}
{
Vc_ASSERT(("size mismatch in span's constructor (other span)",
Extent == _other.size()));
}
template <ptrdiff_t Count>
inline Vc_CONSTEXPR span<element_type, Count> first() const noexcept
{
static_assert(Count >= 0, "Count must be >= 0 in span::first()");
static_assert(Count <= Extent, "Count out of range in span::first()");
return {data(), Count};
}
template <ptrdiff_t Count>
inline Vc_CONSTEXPR span<element_type, Count> last() const noexcept
{
static_assert(Count >= 0, "Count must be >= 0 in span::last()");
static_assert(Count <= Extent, "Count out of range in span::last()");
return {data() + size() - Count, Count};
}
Vc_CONSTEXPR span<element_type, dynamic_extent> first(index_type _count) const noexcept
{
Vc_ASSERT(("Count out of range in span::first(count)",
_count >= 0 && _count <= size()));
return {data(), _count};
}
Vc_CONSTEXPR span<element_type, dynamic_extent> last(index_type _count) const noexcept
{
Vc_ASSERT(
("Count out of range in span::last(count)", _count >= 0 && _count <= size()));
return {data() + size() - _count, _count};
}
#ifndef Vc_MSVC
template <ptrdiff_t Offset, ptrdiff_t Count = dynamic_extent>
inline Vc_CONSTEXPR auto subspan() const noexcept
-> span<element_type, Count != dynamic_extent ? Count : Extent - Offset>
{
Vc_ASSERT(
("Offset out of range in span::subspan()", Offset >= 0 && Offset <= size()));
return {data() + Offset, Count == dynamic_extent ? size() - Offset : Count};
}
inline Vc_CONSTEXPR span<element_type, dynamic_extent> subspan(
index_type offset, index_type count = dynamic_extent) const noexcept
{
Vc_ASSERT(("Offset out of range in span::subspan(offset, count)",
offset >= 0 && offset <= size()));
Vc_ASSERT(("Count out of range in span::subspan(offset, count)",
(count >= 0 && count <= size()) || count == dynamic_extent));
if (count == dynamic_extent) {
return {data() + offset, size() - offset};
}
Vc_ASSERT(("count + offset out of range in span::subspan(offset, count)",
offset + count <= size()));
return {data() + offset, count};
}
#endif
Vc_CONSTEXPR index_type size() const noexcept { return Extent; }
Vc_CONSTEXPR index_type size_bytes() const noexcept
{
return Extent * sizeof(element_type);
}
Vc_CONSTEXPR bool empty() const noexcept { return Extent == 0; }
Vc_CONSTEXPR reference operator[](index_type _idx) const noexcept
{
Vc_ASSERT(("span<T,N>[] index out of bounds", _idx >= 0 && _idx < size()));
return data_[_idx];
}
Vc_CONSTEXPR reference operator()(index_type _idx) const noexcept
{
Vc_ASSERT(("span<T,N>() index out of bounds", _idx >= 0 && _idx < size()));
return data_[_idx];
}
Vc_CONSTEXPR pointer data() const noexcept { return data_; }
Vc_CONSTEXPR iterator begin() const noexcept { return iterator(data()); }
Vc_CONSTEXPR iterator end() const noexcept { return iterator(data() + size()); }
Vc_CONSTEXPR const_iterator cbegin() const noexcept { return const_iterator(data()); }
Vc_CONSTEXPR const_iterator cend() const noexcept
{
return const_iterator(data() + size());
}
Vc_CONSTEXPR reverse_iterator rbegin() const noexcept { return reverse_iterator(end()); }
Vc_CONSTEXPR reverse_iterator rend() const noexcept { return reverse_iterator(begin()); }
Vc_CONSTEXPR const_reverse_iterator crbegin() const noexcept
{
return const_reverse_iterator(cend());
}
Vc_CONSTEXPR const_reverse_iterator crend() const noexcept
{
return const_reverse_iterator(cbegin());
}
Vc_CONSTEXPR void swap(span& _other) noexcept
{
pointer _p = data_;
data_ = _other.data_;
_other.data_ = _p;
}
#ifdef __cpp_lib_byte
span<const std::byte, Extent * sizeof(element_type)> _as_bytes() const noexcept
{
return {reinterpret_cast<const std::byte*>(data()), size_bytes()};
}
span<std::byte, Extent * sizeof(element_type)> _as_writeable_bytes() const noexcept
{
return {reinterpret_cast<std::byte*>(data()), size_bytes()};
}
#endif
private:
pointer data_;
};
template <typename T> class span<T, dynamic_extent>
{
private:
public:
using element_type = T;
using value_type = typename std::remove_cv<T>::type;
using index_type = ptrdiff_t;
using difference_type = ptrdiff_t;
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>;
static constexpr index_type extent = dynamic_extent;
Vc_CONSTEXPR span() noexcept : data_{nullptr}, size_{0} {}
Vc_CONSTEXPR span(const span&) noexcept = default;
Vc_CONSTEXPR span& operator=(const span&) noexcept = default;
Vc_CONSTEXPR span(pointer _ptr, index_type _count) : data_{_ptr}, size_{_count} {}
Vc_CONSTEXPR span(pointer _f, pointer _l) : data_{_f}, size_{distance(_f, _l)} {}
template <size_t Sz>
inline Vc_CONSTEXPR span(element_type (&_arr)[Sz]) noexcept : data_{_arr}, size_{Sz}
{
}
template <size_t Sz>
inline Vc_CONSTEXPR span(array<value_type, Sz>& _arr) noexcept
: data_{_arr.data()}, size_{Sz}
{
}
template <size_t Sz>
inline Vc_CONSTEXPR span(const array<value_type, Sz>& _arr) noexcept
: data_{_arr.data()}, size_{Sz}
{
}
template <class Container>
inline Vc_CONSTEXPR span(
Container& _c,
typename std::enable_if<_is_span_compatible_container<Container, T>::value,
std::nullptr_t>::type = nullptr)
: data_{_std_data(_c)}, size_{index_type(_std_size(_c))}
{
}
template <class Container>
inline Vc_CONSTEXPR span(
const Container& _c,
typename std::enable_if<_is_span_compatible_container<const Container, T>::value,
std::nullptr_t>::type = nullptr)
: data_{_std_data(_c)}, size_{index_type(_std_size(_c))}
{
}
template <class OtherElementType, ptrdiff_t OtherExtent>
inline Vc_CONSTEXPR span(
const span<OtherElementType, OtherExtent>& _other,
typename std::enable_if<
std::is_convertible<OtherElementType (*)[], element_type (*)[]>::value,
std::nullptr_t>::type = nullptr) noexcept
: data_{_other.data()}, size_{_other.size()}
{
}
template <ptrdiff_t Count>
inline Vc_CONSTEXPR span<element_type, Count> first() const noexcept
{
static_assert(Count >= 0, "");
Vc_ASSERT(("Count out of range in span::first()", Count <= size()));
return {data(), Count};
}
template <ptrdiff_t Count>
inline Vc_CONSTEXPR span<element_type, Count> last() const noexcept
{
static_assert(Count >= 0, "");
Vc_ASSERT(("Count out of range in span::last()", Count <= size()));
return {data() + size() - Count, Count};
}
Vc_CONSTEXPR span<element_type, dynamic_extent> first(index_type _count) const noexcept
{
Vc_ASSERT(("Count out of range in span::first(count)",
_count >= 0 && _count <= size()));
return {data(), _count};
}
Vc_CONSTEXPR span<element_type, dynamic_extent> last(index_type _count) const noexcept
{
Vc_ASSERT(
("Count out of range in span::last(count)", _count >= 0 && _count <= size()));
return {data() + size() - _count, _count};
}
template <ptrdiff_t Offset, ptrdiff_t Count = dynamic_extent>
inline Vc_CONSTEXPR span<T, dynamic_extent> subspan() const noexcept
{
Vc_ASSERT(
("Offset out of range in span::subspan()", Offset >= 0 && Offset <= size()));
Vc_ASSERT(("Count out of range in span::subspan()",
Count == dynamic_extent || Offset + Count <= size()));
return {data() + Offset, Count == dynamic_extent ? size() - Offset : Count};
}
Vc_CONSTEXPR span<element_type, dynamic_extent> inline subspan(
index_type _offset, index_type _count = dynamic_extent) const noexcept
{
Vc_ASSERT(("Offset out of range in span::subspan(offset, count)",
_offset >= 0 && _offset <= size()));
Vc_ASSERT(("count out of range in span::subspan(offset, count)",
(_count >= 0 && _count <= size()) || _count == dynamic_extent));
if (_count == dynamic_extent)
return {data() + _offset, size() - _offset};
Vc_ASSERT(("Offset + count out of range in span::subspan(offset, count)",
_offset + _count <= size()));
return {data() + _offset, _count};
}
Vc_CONSTEXPR index_type size() const noexcept { return size_; }
Vc_CONSTEXPR index_type size_bytes() const noexcept
{
return size_ * sizeof(element_type);
}
Vc_CONSTEXPR bool empty() const noexcept { return size_ == 0; }
Vc_CONSTEXPR reference operator[](index_type _idx) const noexcept
{
Vc_ASSERT(("span<T>[] index out of bounds", _idx >= 0 && _idx < size()));
return data_[_idx];
}
Vc_CONSTEXPR reference operator()(index_type _idx) const noexcept
{
Vc_ASSERT(("span<T>() index out of bounds", _idx >= 0 && _idx < size()));
return data_[_idx];
}
Vc_CONSTEXPR pointer data() const noexcept { return data_; }
Vc_CONSTEXPR iterator begin() const noexcept { return iterator(data()); }
Vc_CONSTEXPR iterator end() const noexcept { return iterator(data() + size()); }
Vc_CONSTEXPR const_iterator cbegin() const noexcept { return const_iterator(data()); }
Vc_CONSTEXPR const_iterator cend() const noexcept
{
return const_iterator(data() + size());
}
Vc_CONSTEXPR reverse_iterator rbegin() const noexcept { return reverse_iterator(end()); }
Vc_CONSTEXPR reverse_iterator rend() const noexcept { return reverse_iterator(begin()); }
Vc_CONSTEXPR const_reverse_iterator crbegin() const noexcept
{
return const_reverse_iterator(cend());
}
Vc_CONSTEXPR const_reverse_iterator crend() const noexcept
{
return const_reverse_iterator(cbegin());
}
Vc_CONSTEXPR void swap(span& _other) noexcept
{
pointer _p = data_;
data_ = _other.data_;
_other.data_ = _p;
index_type _sz = size_;
size_ = _other.size_;
_other.size_ = _sz;
}
#ifdef __cpp_lib_byte
#if _MSC_VER > 1928
span<const std::byte, dynamic_extent> _as_bytes() const noexcept
{
return {reinterpret_cast<const std::byte*>(data()), size_bytes()};
}
span<std::byte, dynamic_extent> _as_writeable_bytes() const noexcept
{
return {reinterpret_cast<std::byte*>(data()), size_bytes()};
}
#endif
#endif
private:
pointer data_;
index_type size_;
};
template <class T1, ptrdiff_t Extent1, class T2, ptrdiff_t Extent2>
Vc_CONSTEXPR bool operator==(const span<T1, Extent1>& lhs, const span<T2, Extent2>& rhs)
{
return equal(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
}
template <class T1, ptrdiff_t Extent1, class T2, ptrdiff_t Extent2>
Vc_CONSTEXPR bool operator!=(const span<T1, Extent1>& lhs, const span<T2, Extent2>& rhs)
{
return !(rhs == lhs);
}
template <class T1, ptrdiff_t Extent1, class T2, ptrdiff_t Extent2>
Vc_CONSTEXPR bool operator<(const span<T1, Extent1>& lhs, const span<T2, Extent2>& rhs)
{
return lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
}
template <class T1, ptrdiff_t Extent1, class T2, ptrdiff_t Extent2>
Vc_CONSTEXPR bool operator<=(const span<T1, Extent1>& lhs, const span<T2, Extent2>& rhs)
{
return !(rhs < lhs);
}
template <class T1, ptrdiff_t Extent1, class T2, ptrdiff_t Extent2>
Vc_CONSTEXPR bool operator>(const span<T1, Extent1>& lhs, const span<T2, Extent2>& rhs)
{
return rhs < lhs;
}
template <class T1, ptrdiff_t Extent1, class T2, ptrdiff_t Extent2>
Vc_CONSTEXPR bool operator>=(const span<T1, Extent1>& lhs, const span<T2, Extent2>& rhs)
{
return !(lhs < rhs);
}
template <class T, ptrdiff_t Extent>
auto as_bytes(span<T, Extent> _s) noexcept -> decltype(_s._as_bytes())
{
return _s._as_bytes();
}
template <class T, ptrdiff_t Extent>
auto as_writeable_bytes(span<T, Extent> _s) noexcept ->
typename std::enable_if<!std::is_const<T>::value,
decltype(_s._as_writeable_bytes())>::type
{
return _s._as_writeable_bytes();
}
template <class T, ptrdiff_t Extent>
Vc_CONSTEXPR void swap(span<T, Extent>& lhs, span<T, Extent>& rhs) noexcept
{
lhs.swap(rhs);
}
#undef Vc_CONSTEXPR
#ifdef __cpp_deduction_guides
template <class T, size_t Sz> span(T (&)[Sz])->span<T, Sz>;
template <class T, size_t Sz> span(array<T, Sz>&)->span<T, Sz>;
template <class T, size_t Sz> span(const array<T, Sz>&)->span<const T, Sz>;
template <class Container> span(Container&)->span<typename Container::value_type>;
template <class Container>
span(const Container&)->span<const typename Container::value_type>;
#endif
}
template <typename T, ptrdiff_t Extent = dynamic_extent>
using span = Common::AdaptSubscriptOperator<Common::span<T, Extent>>;
namespace Traits
{
template <typename T, ptrdiff_t Extent>
struct has_contiguous_storage_impl<Vc::span<T, Extent>> : public std::true_type {
};
template <typename T, ptrdiff_t Extent>
struct has_contiguous_storage_impl<Vc::Common::span<T, Extent>> : public std::true_type {
};
}
}
#endif
#ifndef VC_VECTOR_
#define VC_VECTOR_
#include <vector>
namespace Vc_VERSIONED_NAMESPACE
{
template <typename T, typename Allocator = std::allocator<T>>
using vector = Common::AdaptSubscriptOperator<std::vector<T, Allocator>>;
namespace Traits
{
template <typename T, typename A>
struct has_contiguous_storage_impl<Vc::vector<T, A>> : public std::true_type {};
}
}
#endif
#endif