Created
April 7, 2016 23:45
-
-
Save insertinterestingnamehere/c4d7e440b754b190be1e97d02dba2c85 to your computer and use it in GitHub Desktop.
Demonstrates a bug in MSVC 2015 Update 2
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <map> | |
#include <memory> | |
#include <vector> | |
#include <limits> | |
#include <cstdint> | |
#include <iostream> | |
#include <atomic> | |
#include <sstream> | |
#include <algorithm> | |
#include <array> | |
#include <complex> | |
#include <unordered_set> | |
#include <list> | |
#include <bitset> | |
class disable_invalid_parameter_handler { | |
_invalid_parameter_handler m_saved; | |
disable_invalid_parameter_handler(const disable_invalid_parameter_handler &); | |
disable_invalid_parameter_handler &operator=(const disable_invalid_parameter_handler &); | |
static void nop_parameter_handler(const wchar_t *, const wchar_t *, const wchar_t *, unsigned int, uintptr_t) {} | |
public: | |
disable_invalid_parameter_handler() { m_saved = _set_invalid_parameter_handler(&nop_parameter_handler); } | |
~disable_invalid_parameter_handler() { _set_invalid_parameter_handler(m_saved); } | |
}; | |
namespace dynd { | |
template <typename T> | |
struct front; | |
template <typename T> | |
struct back; | |
template <typename T> | |
struct second_back; | |
template <typename I, size_t J> | |
struct at; | |
template <typename I, size_t J> | |
struct from; | |
template <typename I, size_t J> | |
struct to; | |
template <typename I, typename J> | |
struct join; | |
template <typename I, typename J> | |
struct take; | |
template <typename T, T... I> | |
struct integer_sequence { | |
enum { size = sizeof...(I) }; | |
typedef T value_type; | |
static constexpr size_t size2() { return sizeof...(I); } | |
}; | |
namespace detail { | |
template <typename SequenceType> | |
struct i2a; | |
template <typename T, T... I> | |
struct i2a<integer_sequence<T, I...>> { | |
static const std::array<T, sizeof...(I)> value; | |
}; | |
template <typename T, T... I> | |
const std::array<T, sizeof...(I)> i2a<integer_sequence<T, I...>>::value = {{I...}}; | |
} | |
template <typename SequenceType> | |
const std::array<typename SequenceType::value_type, SequenceType::size> &i2a() { | |
return detail::i2a<SequenceType>::value; | |
} | |
template <typename T> | |
struct is_integer_sequence { | |
static const bool value = false; | |
}; | |
template <typename T, T... I> | |
struct is_integer_sequence<integer_sequence<T, I...>> { | |
static const bool value = true; | |
}; | |
template <std::size_t... I> | |
using index_sequence = integer_sequence<size_t, I...>; | |
template <typename T> | |
struct is_index_sequence { | |
static const bool value = false; | |
}; | |
template <std::size_t... I> | |
struct is_index_sequence<index_sequence<I...>> { | |
static const bool value = true; | |
}; | |
template <typename T, T I0, T... I> | |
struct at<integer_sequence<T, I0, I...>, 0> { | |
enum { value = I0 }; | |
}; | |
template <typename T, T I0, T... I, size_t J> | |
struct at<integer_sequence<T, I0, I...>, J> { | |
enum { value = at<integer_sequence<T, I...>, J - 1>::value }; | |
}; | |
template <typename T, T... I, T... J> | |
struct join<integer_sequence<T, I...>, integer_sequence<T, J...>> { | |
typedef integer_sequence<T, I..., J...> type; | |
}; | |
namespace detail { | |
template <int flags, typename T, T...> | |
struct make_integer_sequence; | |
template <int flags, typename T, T stop> | |
struct make_integer_sequence<flags, T, stop> : make_integer_sequence<flags, T, 0, stop> {}; | |
template <int flags, typename T, T start, T stop> | |
struct make_integer_sequence<flags, T, start, stop> : make_integer_sequence<flags, T, start, stop, 1> {}; | |
template <typename T, T start, T stop, T step> | |
struct make_integer_sequence<-1, T, start, stop, step> : make_integer_sequence<(start < stop), T, start, stop, step> { | |
}; | |
template <typename T, T start, T stop, T step> | |
struct make_integer_sequence<0, T, start, stop, step> { | |
typedef integer_sequence<T> type; | |
}; | |
template <typename T, T start, T stop, T step> | |
struct make_integer_sequence<1, T, start, stop, step> { | |
enum { next = start + step }; | |
typedef typename join < integer_sequence<T, start>, | |
typename make_integer_sequence<next<stop, T, next, stop, step>::type>::type type; | |
}; | |
} | |
template <typename T, T... I> | |
using make_integer_sequence = typename detail::make_integer_sequence<-1, T, I...>::type; | |
template <size_t... I> | |
using make_index_sequence = typename detail::make_integer_sequence<-1, size_t, I...>::type; | |
template <typename T, T I0, T... I> | |
struct front<integer_sequence<T, I0, I...>> { | |
static const T value = I0; | |
}; | |
template <typename T, T I0> | |
struct back<integer_sequence<T, I0>> { | |
static const T value = I0; | |
}; | |
template <typename T, T I0, T... I> | |
struct back<integer_sequence<T, I0, I...>> { | |
static const T value = back<integer_sequence<T, I...>>::value; | |
}; | |
template <typename T, T I0, T... I> | |
struct from<integer_sequence<T, I0, I...>, 0> { | |
typedef integer_sequence<T, I0, I...> type; | |
}; | |
template <typename T> | |
struct from<integer_sequence<T>, 0> { | |
typedef integer_sequence<T> type; | |
}; | |
template <typename T, T I0, T... I> | |
struct from<integer_sequence<T, I0, I...>, 1> { | |
typedef integer_sequence<T, I...> type; | |
}; | |
template <typename T, T I0, T... I, size_t J> | |
struct from<integer_sequence<T, I0, I...>, J> { | |
typedef typename from<integer_sequence<T, I...>, J - 1>::type type; | |
}; | |
template <typename T, T I0, T... I> | |
struct to<integer_sequence<T, I0, I...>, 0> { | |
typedef integer_sequence<T> type; | |
}; | |
template <typename T> | |
struct to<integer_sequence<T>, 0> { | |
typedef integer_sequence<T> type; | |
}; | |
template <typename T, T I0, T... I> | |
struct to<integer_sequence<T, I0, I...>, 1> { | |
typedef integer_sequence<T, I0> type; | |
}; | |
template <typename T, T I0, T... I, size_t J> | |
struct to<integer_sequence<T, I0, I...>, J> { | |
typedef typename join<integer_sequence<T, I0>, typename to<integer_sequence<T, I...>, J - 1>::type>::type type; | |
}; | |
template <typename... T> | |
struct type_sequence { | |
enum { size = sizeof...(T) }; | |
static constexpr size_t size2() { return sizeof...(T); } | |
}; | |
template <typename T> | |
struct is_type_sequence { | |
static const bool value = false; | |
}; | |
template <typename... T> | |
struct is_type_sequence<type_sequence<T...>> { | |
static const bool value = true; | |
}; | |
template <typename T> | |
struct back<type_sequence<T>> { | |
typedef T type; | |
}; | |
template <typename T0, typename... T> | |
struct back<type_sequence<T0, T...>> { | |
typedef typename back<type_sequence<T...>>::type type; | |
}; | |
template <typename S, typename T> | |
struct second_back<type_sequence<S, T>> { | |
typedef S type; | |
}; | |
template <typename T0, typename T1, typename... T> | |
struct second_back<type_sequence<T0, T1, T...>> { | |
typedef typename second_back<type_sequence<T1, T...>>::type type; | |
}; | |
template <typename T0, typename... T> | |
struct front<type_sequence<T0, T...>> { | |
typedef T0 type; | |
}; | |
template <typename T0, typename... T> | |
struct at<type_sequence<T0, T...>, 0> { | |
typedef T0 type; | |
}; | |
template <size_t I, typename T0, typename... T> | |
struct at<type_sequence<T0, T...>, I> { | |
typedef typename at<type_sequence<T...>, I - 1>::type type; | |
}; | |
template <typename T0, typename... T> | |
struct from<type_sequence<T0, T...>, 0> { | |
typedef type_sequence<T0, T...> type; | |
}; | |
template <> | |
struct from<type_sequence<>, 0> { | |
typedef type_sequence<> type; | |
}; | |
template <typename T0, typename... T> | |
struct from<type_sequence<T0, T...>, 1> { | |
typedef type_sequence<T...> type; | |
}; | |
template <typename T0, typename... T, size_t I> | |
struct from<type_sequence<T0, T...>, I> { | |
typedef typename from<type_sequence<T...>, I - 1>::type type; | |
}; | |
template <typename T0, typename... T> | |
struct to<type_sequence<T0, T...>, 0> { | |
typedef type_sequence<> type; | |
}; | |
template <> | |
struct to<type_sequence<>, 0> { | |
typedef type_sequence<> type; | |
}; | |
template <typename T0, typename... T> | |
struct to<type_sequence<T0, T...>, 1> { | |
typedef type_sequence<T0> type; | |
}; | |
template <typename T0, typename... T, size_t I> | |
struct to<type_sequence<T0, T...>, I> { | |
typedef typename join<type_sequence<T0>, typename to<type_sequence<T...>, I - 1>::type>::type type; | |
}; | |
template <typename... T, typename... U> | |
struct join<type_sequence<T...>, type_sequence<U...>> { | |
typedef type_sequence<T..., U...> type; | |
}; | |
template <typename... T, size_t... I> | |
struct take<type_sequence<T...>, index_sequence<I...>> { | |
typedef type_sequence<typename at<type_sequence<T...>, I>::type...> type; | |
}; | |
template <typename T> | |
struct pop_front { | |
typedef typename from<T, 1>::type type; | |
}; | |
template <typename... S> | |
struct outer; | |
template <typename T0, T0 I0, typename T1, T1 I1> | |
struct outer<integer_sequence<T0, I0>, integer_sequence<T1, I1>> { | |
typedef type_sequence<integer_sequence<typename std::common_type<T0, T1>::type, I0, I1>> type; | |
}; | |
template <typename T0, T0 I0, typename T1, T1 I, T1... I1> | |
struct outer<integer_sequence<T0, I0>, integer_sequence<T1, I, I1...>> { | |
typedef typename join<type_sequence<integer_sequence<typename std::common_type<T0, T1>::type, I0, I>>, | |
typename outer<integer_sequence<T0, I0>, integer_sequence<T1, I1...>>::type>::type type; | |
}; | |
template <typename T0, T0... I0, typename T1, T1 I1> | |
struct outer<type_sequence<integer_sequence<T0, I0...>>, integer_sequence<T1, I1>> { | |
typedef type_sequence<integer_sequence<typename std::common_type<T0, T1>::type, I0..., I1>> type; | |
}; | |
template <typename T0, T0... I0, typename T1, T1 I, T1... I1> | |
struct outer<type_sequence<integer_sequence<T0, I0...>>, integer_sequence<T1, I, I1...>> { | |
typedef | |
typename join<type_sequence<integer_sequence<typename std::common_type<T0, T1>::type, I0..., I>>, | |
typename outer<type_sequence<integer_sequence<T0, I0...>>, integer_sequence<T1, I1...>>::type>::type | |
type; | |
}; | |
template <typename T0, typename... T1> | |
struct outer<type_sequence<T0>, type_sequence<T1...>> { | |
typedef type_sequence<type_sequence<T0, T1>...> type; | |
}; | |
template <typename... T0, typename... T1> | |
struct outer<type_sequence<type_sequence<T0...>>, type_sequence<T1...>> { | |
typedef type_sequence<type_sequence<T0..., T1>...> type; | |
}; | |
template <typename S0, typename S1> | |
struct outer<S0, S1> { | |
typedef typename join<typename outer<typename to<S0, 1>::type, S1>::type, | |
typename outer<typename pop_front<S0>::type, S1>::type>::type type; | |
}; | |
template <typename S0, typename S1, typename... S> | |
struct outer<S0, S1, S...> { | |
typedef typename outer<typename outer<S0, S1>::type, S...>::type type; | |
}; | |
template <typename S, typename A0, typename... A> | |
typename std::enable_if<S::size == 1 && is_integer_sequence<S>::value, void>::type for_each(A0 &&a0, A &&... a) { | |
a0.template on_each<front<S>::value>(std::forward<A>(a)...); | |
} | |
template <typename S, typename A0, typename... A> | |
typename std::enable_if<S::size == 1 && is_type_sequence<S>::value, void>::type for_each(A0 &&a0, A &&... a) { | |
a0.template on_each<typename front<S>::type>(std::forward<A>(a)...); | |
} | |
template <typename S, typename... A> | |
typename std::enable_if<(S::size2() > 1), void>::type for_each(A &&... a) { | |
for_each<typename to<S, 1>::type>(std::forward<A>(a)...); | |
for_each<typename pop_front<S>::type>(std::forward<A>(a)...); | |
} | |
} | |
namespace dynd { | |
template <typename T, typename U, typename V> | |
struct is_common_type_of : std::conditional<std::is_same<T, typename std::common_type<U, V>::type>::value, | |
std::true_type, std::false_type>::type { | |
}; | |
template <bool Value, template <typename...> class T, template <typename...> class U, typename... As> | |
struct conditional_make; | |
template <template <typename...> class T, template <typename...> class U, typename... As> | |
struct conditional_make<true, T, U, As...> { | |
typedef T<As...> type; | |
}; | |
template <template <typename...> class T, template <typename...> class U, typename... As> | |
struct conditional_make<false, T, U, As...> { | |
typedef U<As...> type; | |
}; | |
template <typename T> | |
struct is_function_pointer { | |
static const bool value = | |
std::is_pointer<T>::value ? std::is_function<typename std::remove_pointer<T>::type>::value : false; | |
}; | |
template <typename T> | |
struct is_vector : std::false_type { | |
}; | |
template <typename T> | |
struct is_vector<std::vector<T>> : std::true_type { | |
}; | |
template <typename T> | |
long intrusive_ptr_use_count(T *ptr); | |
template <typename T> | |
void intrusive_ptr_retain(T *ptr); | |
template <typename T> | |
void intrusive_ptr_release(T *ptr); | |
template <typename T> | |
class intrusive_ptr { | |
protected: | |
T *m_ptr; | |
public: | |
intrusive_ptr() : m_ptr(0) {} | |
explicit intrusive_ptr(T *ptr, bool add_ref = true) : m_ptr(ptr) | |
{ | |
if (m_ptr != 0 && add_ref) { | |
intrusive_ptr_retain(m_ptr); | |
} | |
} | |
intrusive_ptr(const intrusive_ptr &other) : m_ptr(other.m_ptr) | |
{ | |
if (m_ptr != 0) { | |
intrusive_ptr_retain(m_ptr); | |
} | |
} | |
intrusive_ptr(intrusive_ptr &&other) : m_ptr(other.m_ptr) { other.m_ptr = 0; } | |
~intrusive_ptr() | |
{ | |
if (m_ptr != 0) { | |
intrusive_ptr_release(m_ptr); | |
} | |
} | |
intptr_t use_count() const { return intrusive_ptr_use_count(m_ptr); } | |
explicit operator bool() const { return m_ptr != 0; } | |
T *operator->() const { return m_ptr; } | |
intrusive_ptr &operator=(const intrusive_ptr &rhs) | |
{ | |
if (m_ptr != 0) { | |
intrusive_ptr_release(m_ptr); | |
} | |
if (rhs.m_ptr != 0) { | |
m_ptr = rhs.m_ptr; | |
intrusive_ptr_retain(m_ptr); | |
} | |
else { | |
m_ptr = 0; | |
} | |
return *this; | |
} | |
intrusive_ptr &operator=(intrusive_ptr &&rhs) | |
{ | |
if (m_ptr != 0) { | |
intrusive_ptr_release(m_ptr); | |
} | |
m_ptr = rhs.m_ptr; | |
rhs.m_ptr = 0; | |
return *this; | |
} | |
intrusive_ptr &operator=(T *rhs) | |
{ | |
if (m_ptr != nullptr) { | |
intrusive_ptr_release(m_ptr); | |
} | |
m_ptr = rhs; | |
if (m_ptr != nullptr) { | |
intrusive_ptr_retain(m_ptr); | |
} | |
return *this; | |
} | |
bool unique() const { return intrusive_ptr_use_count(m_ptr) <= 1; } | |
T *get() const { return m_ptr; } | |
T *release() | |
{ | |
T *result = m_ptr; | |
m_ptr = 0; | |
return result; | |
} | |
void swap(intrusive_ptr &rhs) | |
{ | |
T *tmp = m_ptr; | |
m_ptr = rhs.m_ptr; | |
rhs.m_ptr = tmp; | |
} | |
}; | |
template <typename T> | |
bool operator==(const intrusive_ptr<T> &lhs, const intrusive_ptr<T> &rhs) | |
{ | |
return lhs.get() == rhs.get(); | |
} | |
template <typename T> | |
bool operator!=(const intrusive_ptr<T> &lhs, const intrusive_ptr<T> &rhs) | |
{ | |
return lhs.get() == rhs.get(); | |
} | |
template <template <typename...> class T, typename U> | |
struct is_instance { | |
static const bool value = false; | |
}; | |
template <template <typename...> class T, typename... A> | |
struct is_instance<T, T<A...>> { | |
static const bool value = true; | |
}; | |
template <typename T, typename U> | |
T alias_cast(U value) | |
{ | |
union { | |
U tmp; | |
T res; | |
}; | |
tmp = value; | |
return res; | |
} | |
template <typename T> | |
struct is_char_string_param { | |
static const bool value = false; | |
}; | |
template <> | |
struct is_char_string_param<const char *> { | |
static const bool value = true; | |
}; | |
template <> | |
struct is_char_string_param<char *> { | |
static const bool value = true; | |
}; | |
template <int N> | |
struct is_char_string_param<const char(&)[N]> { | |
static const bool value = true; | |
}; | |
template <int N> | |
struct is_char_string_param<const char(&&)[N]> { | |
static const bool value = true; | |
}; | |
template <typename... T> | |
struct all_char_string_params { | |
static const bool value = false; | |
}; | |
template <> | |
struct all_char_string_params<> { | |
static const bool value = true; | |
}; | |
template <typename T0> | |
struct all_char_string_params<T0> { | |
static const bool value = is_char_string_param<T0>::value; | |
}; | |
template <typename... T, typename T0> | |
struct all_char_string_params<T0, T...> { | |
static const bool value = is_char_string_param<T0>::value && all_char_string_params<T...>::value; | |
}; | |
template <typename T> | |
struct remove_all_pointers { | |
typedef T type; | |
}; | |
template <typename T> | |
struct remove_reference_then_cv { | |
typedef typename std::remove_cv<typename std::remove_reference<T>::type>::type type; | |
}; | |
template <typename T> | |
struct remove_all_pointers<T *> { | |
typedef typename remove_all_pointers<typename std::remove_cv<T>::type>::type type; | |
}; | |
namespace detail { | |
template <typename func_type, typename... B> | |
struct funcproto { | |
typedef typename funcproto<decltype(&func_type::operator()), B...>::type type; | |
}; | |
template <typename R, typename... A, typename... B> | |
struct funcproto<R(A...), B...> { | |
typedef R(type)(A..., B...); | |
}; | |
template <typename R, typename... A, typename... B> | |
struct funcproto<R (*)(A...), B...> { | |
typedef typename funcproto<R(A...), B...>::type type; | |
}; | |
template <typename T, typename R, typename... A, typename... B> | |
struct funcproto<R (T::*)(A...), B...> { | |
typedef typename funcproto<R(A...), B...>::type type; | |
}; | |
template <typename T, typename R, typename... A, typename... B> | |
struct funcproto<R (T::*)(A...) const, B...> { | |
typedef typename funcproto<R(A...), B...>::type type; | |
}; | |
} | |
template <typename func_type, typename... B> | |
struct funcproto_of { | |
typedef typename detail::funcproto<func_type, B...>::type type; | |
}; | |
template <typename func_type, typename... B> | |
struct funcproto_of<func_type *, B...> { | |
typedef typename funcproto_of<func_type, B...>::type type; | |
}; | |
template <typename func_type> | |
struct return_of { | |
typedef typename return_of<typename funcproto_of<func_type>::type>::type type; | |
}; | |
template <typename R, typename... A> | |
struct return_of<R(A...)> { | |
typedef R type; | |
}; | |
template <typename func_type> | |
struct args_of { | |
typedef typename args_of<typename funcproto_of<func_type>::type>::type type; | |
}; | |
template <typename R, typename... A> | |
struct args_of<R(A...)> { | |
typedef type_sequence<A...> type; | |
}; | |
template <typename func_type> | |
struct arity_of { | |
static const size_t value = arity_of<typename funcproto_of<func_type>::type>::value; | |
}; | |
template <typename R, typename... A> | |
struct arity_of<R(A...)> { | |
static const size_t value = sizeof...(A); | |
}; | |
template <typename func_type, int I> | |
struct arg_at { | |
typedef typename at<typename args_of<func_type>::type, I>::type type; | |
}; | |
} | |
namespace dynd { | |
inline int libdynd_init() { return 0; } | |
inline void libdynd_cleanup() {} | |
bool built_with_cuda(); | |
} | |
namespace dynd { | |
class bool1; | |
typedef std::int8_t int8; | |
typedef std::int16_t int16; | |
typedef std::int32_t int32; | |
typedef std::int64_t int64; | |
class int128; | |
typedef std::uint8_t uint8; | |
typedef std::uint16_t uint16; | |
typedef std::uint32_t uint32; | |
typedef std::uint64_t uint64; | |
class uint128; | |
class float16; | |
typedef float float32; | |
typedef double float64; | |
class float128; | |
template <typename T> | |
struct is_boolean { | |
static const bool value = false; | |
}; | |
template <> | |
struct is_boolean<bool> { | |
static const bool value = true; | |
}; | |
template <> | |
struct is_boolean<bool1> { | |
static const bool value = true; | |
}; | |
template <typename T> | |
struct is_integral : std::is_integral<T> { | |
}; | |
template <typename T> | |
struct is_floating_point : std::is_floating_point<T> { | |
}; | |
template <typename T> | |
struct is_complex : std::false_type { | |
}; | |
template <typename T> | |
struct is_arithmetic : std::integral_constant<bool, is_integral<T>::value || is_floating_point<T>::value> { | |
}; | |
template <typename T> | |
struct is_numeric : std::integral_constant<bool, is_arithmetic<T>::value || is_complex<T>::value> { | |
}; | |
template <typename T, typename U> | |
struct is_mixed_arithmetic : std::integral_constant<bool, is_arithmetic<T>::value && is_arithmetic<U>::value> { | |
}; | |
template <typename T> | |
struct is_mixed_arithmetic<T, T> : std::false_type { | |
}; | |
template <typename... Ts> | |
using true_t = std::true_type; | |
template <typename... Ts> | |
using false_t = std::false_type; | |
template <typename T> | |
using not_t = std::integral_constant<bool, !T::value>; | |
template <typename T, typename U> | |
struct is_lcast_arithmetic : not_t<typename conditional_make<is_arithmetic<T>::value && is_arithmetic<U>::value, | |
is_common_type_of, true_t, T, T, U>::type> { | |
}; | |
template <typename T, typename U> | |
struct is_rcast_arithmetic : not_t<typename conditional_make<is_arithmetic<T>::value && is_arithmetic<U>::value, | |
is_common_type_of, true_t, U, T, U>::type> { | |
}; | |
template <typename T> | |
struct is_signed { | |
static const bool value = std::is_signed<T>::value || std::is_same<T, int128>::value; | |
}; | |
template <typename T> | |
struct is_unsigned { | |
static const bool value = std::is_unsigned<T>::value || std::is_same<T, uint128>::value; | |
}; | |
template <typename T> | |
T strto(const char *begin, char **end); | |
template <> | |
inline float strto(const char *begin, char **end) | |
{ | |
return std::strtof(begin, end); | |
} | |
template <> | |
inline double strto(const char *begin, char **end) | |
{ | |
return std::strtod(begin, end); | |
} | |
template <typename T> | |
T floor(T value) | |
{ | |
return std::floor(value); | |
} | |
enum assign_error_mode { | |
assign_error_nocheck, | |
assign_error_overflow, | |
assign_error_fractional, | |
assign_error_inexact, | |
assign_error_default | |
}; | |
struct overflow_check_t { | |
}; | |
inline std::ostream &operator<<(std::ostream &o, assign_error_mode errmode) | |
{ | |
switch (errmode) { | |
case assign_error_nocheck: | |
o << "nocheck"; | |
break; | |
case assign_error_overflow: | |
o << "overflow"; | |
break; | |
case assign_error_fractional: | |
o << "fractional"; | |
break; | |
case assign_error_inexact: | |
o << "inexact"; | |
break; | |
case assign_error_default: | |
o << "default"; | |
break; | |
default: | |
o << "invalid error mode(" << (int)errmode << ")"; | |
break; | |
} | |
return o; | |
} | |
namespace detail { | |
template <typename T, typename... Types> | |
struct TypeSetCheckInternal : std::is_same<T, Types>... { | |
}; | |
template <typename T, typename... Types> | |
struct TypeSetCheck : std::is_base_of<std::true_type, TypeSetCheckInternal<T, Types...>>::type { | |
}; | |
template <typename T, typename... Types> | |
struct enable_for : std::enable_if<TypeSetCheck<T, Types...>::value, int> { | |
}; | |
} | |
} | |
namespace dynd { | |
class __declspec(dllexport) bool1 { | |
char m_value; | |
public: | |
bool1() = default; | |
explicit bool1(bool value) : m_value(value) {} | |
operator bool() const { return m_value != 0; } | |
bool1 &operator=(bool rhs) | |
{ | |
m_value = rhs; | |
return *this; | |
} | |
bool1 operator+() const { return *this; } | |
bool1 operator-() const { return *this; } | |
bool1 operator!() const { return bool1(m_value == 0); } | |
bool1 operator~() const { return bool1(m_value == 0); } | |
bool1 operator&&(bool1 &rhs) { return bool1(m_value && rhs.m_value); } | |
bool1 operator||(bool1 &rhs) { return bool1(m_value || rhs.m_value); } | |
bool1 &operator+=(bool1 rhs) | |
{ | |
m_value += rhs.m_value; | |
return *this; | |
} | |
bool1 &operator-=(bool1 rhs) | |
{ | |
m_value -= rhs.m_value; | |
return *this; | |
} | |
bool1 &operator*=(bool1 rhs) | |
{ | |
m_value *= rhs.m_value; | |
return *this; | |
} | |
bool1 &operator/=(bool1 rhs) | |
{ | |
m_value /= rhs.m_value; | |
return *this; | |
} | |
friend int operator+(bool1 lhs, bool1 rhs); | |
friend int operator-(bool1 lhs, bool1 rhs); | |
friend int operator*(bool1 lhs, bool1 rhs); | |
friend int operator/(bool1 lhs, bool1 rhs); | |
}; | |
template <> | |
struct is_integral<bool1> : std::true_type { | |
}; | |
inline int operator+(bool1 lhs, bool1 rhs) { return lhs.m_value + rhs.m_value; } | |
inline int operator-(bool1 lhs, bool1 rhs) { return lhs.m_value - rhs.m_value; } | |
inline int operator*(bool1 lhs, bool1 rhs) { return lhs.m_value * rhs.m_value; } | |
inline int operator/(bool1 lhs, bool1 rhs) { return lhs.m_value / rhs.m_value; } | |
} | |
namespace std { | |
template <> | |
struct common_type<dynd::bool1, bool> : common_type<char, bool> { | |
}; | |
template <> | |
struct common_type<dynd::bool1, dynd::bool1> { | |
typedef dynd::bool1 type; | |
}; | |
template <> | |
struct common_type<dynd::bool1, char> : common_type<char, char> { | |
}; | |
template <> | |
struct common_type<dynd::bool1, signed char> : common_type<char, signed char> { | |
}; | |
template <> | |
struct common_type<dynd::bool1, unsigned char> : common_type<char, unsigned char> { | |
}; | |
template <> | |
struct common_type<dynd::bool1, short> : common_type<char, short> { | |
}; | |
template <> | |
struct common_type<dynd::bool1, unsigned short> : common_type<char, unsigned short> { | |
}; | |
template <> | |
struct common_type<dynd::bool1, int> : common_type<char, int> { | |
}; | |
template <> | |
struct common_type<dynd::bool1, unsigned int> : common_type<char, unsigned int> { | |
}; | |
template <> | |
struct common_type<dynd::bool1, long> : common_type<char, long> { | |
}; | |
template <> | |
struct common_type<dynd::bool1, unsigned long> : common_type<char, unsigned long> { | |
}; | |
template <> | |
struct common_type<dynd::bool1, long long> : common_type<char, long long> { | |
}; | |
template <> | |
struct common_type<dynd::bool1, unsigned long long> : common_type<char, unsigned long long> { | |
}; | |
template <> | |
struct common_type<dynd::bool1, float> : common_type<char, float> { | |
}; | |
template <> | |
struct common_type<dynd::bool1, double> : common_type<char, double> { | |
}; | |
template <typename T> | |
struct common_type<T, dynd::bool1> : common_type<dynd::bool1, T> { | |
}; | |
} | |
namespace dynd { | |
inline bool operator<(bool1 lhs, bool1 rhs) { return static_cast<bool>(lhs) < static_cast<bool>(rhs); } | |
template <typename T> | |
typename std::enable_if<std::is_arithmetic<T>::value, bool>::type operator<(bool1 lhs, T rhs) | |
{ | |
return static_cast<T>(lhs) < rhs; | |
} | |
template <typename T> | |
typename std::enable_if<std::is_arithmetic<T>::value, bool>::type operator<(T lhs, bool1 rhs) | |
{ | |
return lhs < static_cast<T>(rhs); | |
} | |
inline bool operator<=(bool1 lhs, bool1 rhs) { return static_cast<bool>(lhs) <= static_cast<bool>(rhs); } | |
template <typename T> | |
typename std::enable_if<std::is_arithmetic<T>::value, bool>::type operator<=(bool1 lhs, T rhs) | |
{ | |
return static_cast<T>(lhs) <= rhs; | |
} | |
template <typename T> | |
typename std::enable_if<std::is_arithmetic<T>::value, bool>::type operator<=(T lhs, bool1 rhs) | |
{ | |
return lhs <= static_cast<T>(rhs); | |
} | |
inline bool operator==(bool1 lhs, bool1 rhs) { return static_cast<bool>(lhs) == static_cast<bool>(rhs); } | |
template <typename T> | |
typename std::enable_if<std::is_arithmetic<T>::value, bool>::type operator==(bool1 lhs, T rhs) | |
{ | |
return static_cast<T>(lhs) == rhs; | |
} | |
template <typename T> | |
typename std::enable_if<std::is_arithmetic<T>::value, bool>::type operator==(T lhs, bool1 rhs) | |
{ | |
return lhs == static_cast<T>(rhs); | |
} | |
inline bool operator!=(bool1 lhs, bool1 rhs) { return static_cast<bool>(lhs) != static_cast<bool>(rhs); } | |
template <typename T> | |
typename std::enable_if<std::is_arithmetic<T>::value, bool>::type operator!=(bool1 lhs, T rhs) | |
{ | |
return static_cast<T>(lhs) != rhs; | |
} | |
template <typename T> | |
typename std::enable_if<std::is_arithmetic<T>::value, bool>::type operator!=(T lhs, bool1 rhs) | |
{ | |
return lhs != static_cast<T>(rhs); | |
} | |
inline bool operator>=(bool1 lhs, bool1 rhs) { return static_cast<bool>(lhs) >= static_cast<bool>(rhs); } | |
template <typename T> | |
typename std::enable_if<std::is_arithmetic<T>::value, bool>::type operator>=(bool1 lhs, T rhs) | |
{ | |
return static_cast<T>(lhs) >= rhs; | |
} | |
template <typename T> | |
typename std::enable_if<std::is_arithmetic<T>::value, bool>::type operator>=(T lhs, bool1 rhs) | |
{ | |
return lhs >= static_cast<T>(rhs); | |
} | |
inline bool operator>(bool1 lhs, bool1 rhs) { return static_cast<bool>(lhs) > static_cast<bool>(rhs); } | |
template <typename T> | |
typename std::enable_if<std::is_arithmetic<T>::value, bool>::type operator>(bool1 lhs, T rhs) | |
{ | |
return static_cast<T>(lhs) > rhs; | |
} | |
template <typename T> | |
typename std::enable_if<std::is_arithmetic<T>::value, bool>::type operator>(T lhs, bool1 rhs) | |
{ | |
return lhs > static_cast<T>(rhs); | |
} | |
inline std::ostream &operator<<(std::ostream &o, const bool1 &rhs) { return o << static_cast<bool>(rhs); } | |
} | |
namespace dynd { | |
class __declspec(dllimport) int128 { | |
public: | |
uint64_t m_lo, m_hi; | |
int128() {} | |
int128(uint64_t hi, uint64_t lo) : m_lo(lo), m_hi(hi) {} | |
int128(bool1) { throw std::runtime_error("int128(bool1) is not implemented"); } | |
int128(char value) : m_lo((int64_t)value), m_hi(value < 0 ? 0xffffffffffffffffULL : 0ULL) {} | |
int128(signed char value) : m_lo((int64_t)value), m_hi(value < 0 ? 0xffffffffffffffffULL : 0ULL) {} | |
int128(unsigned char value) : m_lo(value), m_hi(0ULL) {} | |
int128(short value) : m_lo((int64_t)value), m_hi(value < 0 ? 0xffffffffffffffffULL : 0ULL) {} | |
int128(unsigned short value) : m_lo(value), m_hi(0ULL) {} | |
int128(int value) : m_lo((int64_t)value), m_hi(value < 0 ? 0xffffffffffffffffULL : 0ULL) {} | |
int128(unsigned int value) : m_lo(value), m_hi(0ULL) {} | |
int128(long value) : m_lo((int64_t)value), m_hi(value < 0 ? 0xffffffffffffffffULL : 0ULL) {} | |
int128(unsigned long value) : m_lo(value), m_hi(0ULL) {} | |
int128(long long value) : m_lo((int64_t)value), m_hi(value < 0 ? 0xffffffffffffffffULL : 0ULL) {} | |
int128(unsigned long long value) : m_lo(value), m_hi(0ULL) {} | |
int128(float value); | |
int128(double value); | |
int128(const uint128 &value); | |
int128(const float16 &value); | |
int128(const float128 &value); | |
int128 operator+() const { return *this; } | |
bool operator!() const { return !(this->m_hi) && !(this->m_lo); } | |
int128 operator~() const { return int128(~m_hi, ~m_lo); } | |
bool operator==(const int128 &rhs) const { return m_lo == rhs.m_lo && m_hi == rhs.m_hi; } | |
bool operator==(int rhs) const | |
{ | |
return static_cast<int64_t>(m_lo) == static_cast<int64_t>(rhs) && m_hi == (rhs >= 0 ? 0ULL : 0xffffffffffffffffULL); | |
} | |
bool operator!=(const int128 &rhs) const { return m_lo != rhs.m_lo || m_hi != rhs.m_hi; } | |
bool operator!=(int rhs) const | |
{ | |
return static_cast<int64_t>(m_lo) != static_cast<int64_t>(rhs) || m_hi != (rhs >= 0 ? 0ULL : 0xffffffffffffffffULL); | |
} | |
bool operator<(float rhs) const { return double(*this) < rhs; } | |
bool operator<(double rhs) const { return double(*this) < rhs; } | |
bool operator<(const int128 &rhs) const | |
{ | |
return (int64_t)m_hi < (int64_t)rhs.m_hi || (m_hi == rhs.m_hi && m_lo < rhs.m_lo); | |
} | |
bool operator<=(const int128 &rhs) const | |
{ | |
return (int64_t)m_hi < (int64_t)rhs.m_hi || (m_hi == rhs.m_hi && m_lo <= rhs.m_lo); | |
} | |
bool operator>(const int128 &rhs) const { return rhs.operator<(*this); } | |
bool operator>=(const int128 &rhs) const { return rhs.operator<=(*this); } | |
bool is_negative() const { return (m_hi & 0x8000000000000000ULL) != 0; } | |
void negate() | |
{ | |
uint64_t lo = ~m_lo, hi = ~m_hi; | |
uint64_t lo_p1 = lo + 1; | |
m_hi = hi + (lo_p1 < lo); | |
m_lo = lo_p1; | |
} | |
int128 &operator+=(const int128 &rhs) | |
{ | |
uint64_t lo = m_lo + rhs.m_lo; | |
*this = int128(m_hi + ~rhs.m_hi + (lo < m_lo), lo); | |
return *this; | |
} | |
int128 operator-() const | |
{ | |
uint64_t lo = ~m_lo, hi = ~m_hi; | |
uint64_t lo_p1 = lo + 1; | |
return int128(hi + (lo_p1 < lo), lo_p1); | |
} | |
int128 operator+(const int128 &rhs) const | |
{ | |
uint64_t lo = m_lo + rhs.m_lo; | |
return int128(m_hi + rhs.m_hi + (lo < m_lo), lo); | |
} | |
int128 operator-(const int128 &rhs) const | |
{ | |
uint64_t lo = m_lo + ~rhs.m_lo + 1; | |
return int128(m_hi + ~rhs.m_hi + (lo < m_lo), lo); | |
} | |
int128 operator*(uint32_t rhs) const; | |
int128 &operator/=(int128 ) { throw std::runtime_error("operator/= is not implemented for int128"); } | |
operator float() const | |
{ | |
if (*this < int128(0)) { | |
int128 tmp = -(*this); | |
return tmp.m_lo + tmp.m_hi * 18446744073709551616.f; | |
} | |
else { | |
return m_lo + m_hi * 18446744073709551616.f; | |
} | |
} | |
operator double() const | |
{ | |
if (*this < int128(0)) { | |
int128 tmp = -(*this); | |
return tmp.m_lo + tmp.m_hi * 18446744073709551616.0; | |
} | |
else { | |
return m_lo + m_hi * 18446744073709551616.0; | |
} | |
} | |
explicit operator bool() const { return m_lo || m_hi; } | |
explicit operator char() const { return (char)m_lo; } | |
explicit operator signed char() const { return (signed char)m_lo; } | |
explicit operator unsigned char() const { return (unsigned char)m_lo; } | |
explicit operator short() const { return (short)m_lo; } | |
explicit operator unsigned short() const { return (unsigned short)m_lo; } | |
explicit operator int() const { return (int)m_lo; } | |
explicit operator unsigned int() const { return (unsigned int)m_lo; } | |
explicit operator long() const { return (long)m_lo; } | |
explicit operator unsigned long() const { return (unsigned long)m_lo; } | |
explicit operator long long() const { return (long long)m_lo; } | |
explicit operator unsigned long long() const { return (unsigned long long)m_lo; } | |
}; | |
template <> | |
struct is_integral<int128> : std::true_type { | |
}; | |
} | |
namespace std { | |
template <> | |
struct common_type<dynd::int128, bool> { | |
typedef dynd::int128 type; | |
}; | |
template <> | |
struct common_type<dynd::int128, dynd::bool1> { | |
typedef dynd::int128 type; | |
}; | |
template <> | |
struct common_type<dynd::int128, char> { | |
typedef dynd::int128 type; | |
}; | |
template <> | |
struct common_type<dynd::int128, signed char> { | |
typedef dynd::int128 type; | |
}; | |
template <> | |
struct common_type<dynd::int128, unsigned char> { | |
typedef dynd::int128 type; | |
}; | |
template <> | |
struct common_type<dynd::int128, short> { | |
typedef dynd::int128 type; | |
}; | |
template <> | |
struct common_type<dynd::int128, unsigned short> { | |
typedef dynd::int128 type; | |
}; | |
template <> | |
struct common_type<dynd::int128, int> { | |
typedef dynd::int128 type; | |
}; | |
template <> | |
struct common_type<dynd::int128, unsigned int> { | |
typedef dynd::int128 type; | |
}; | |
template <> | |
struct common_type<dynd::int128, long> { | |
typedef dynd::int128 type; | |
}; | |
template <> | |
struct common_type<dynd::int128, unsigned long> { | |
typedef dynd::int128 type; | |
}; | |
template <> | |
struct common_type<dynd::int128, long long> { | |
typedef dynd::int128 type; | |
}; | |
template <> | |
struct common_type<dynd::int128, unsigned long long> { | |
typedef dynd::int128 type; | |
}; | |
template <> | |
struct common_type<dynd::int128, dynd::int128> { | |
typedef dynd::int128 type; | |
}; | |
template <> | |
struct common_type<dynd::int128, float> { | |
typedef float type; | |
}; | |
template <> | |
struct common_type<dynd::int128, double> { | |
typedef double type; | |
}; | |
template <typename T> | |
struct common_type<T, dynd::int128> : common_type<dynd::int128, T> { | |
}; | |
} | |
namespace dynd { | |
inline int128 operator/(int128 , int128 ) | |
{ | |
throw std::runtime_error("operator/ is not implemented for int128"); | |
} | |
inline bool operator==(int lhs, const int128 &rhs) { return rhs == lhs; } | |
inline bool operator!=(int lhs, const int128 &rhs) { return rhs != lhs; } | |
inline bool operator<(const int128 &lhs, int rhs) { return lhs < int128(rhs); } | |
inline bool operator>(const int128 &lhs, int rhs) { return lhs > int128(rhs); } | |
inline bool operator<(float lhs, const int128 &rhs) { return lhs < double(rhs); } | |
inline bool operator<(double lhs, const int128 &rhs) { return lhs < double(rhs); } | |
inline bool operator<(signed char lhs, const int128 &rhs) { return int128(lhs) < rhs; } | |
inline bool operator<(unsigned char lhs, const int128 &rhs) { return int128(lhs) < rhs; } | |
inline bool operator<(short lhs, const int128 &rhs) { return int128(lhs) < rhs; } | |
inline bool operator<(unsigned short lhs, const int128 &rhs) { return int128(lhs) < rhs; } | |
inline bool operator<(int lhs, const int128 &rhs) { return int128(lhs) < rhs; } | |
inline bool operator<(unsigned int lhs, const int128 &rhs) { return int128(lhs) < rhs; } | |
inline bool operator<(long long lhs, const int128 &rhs) { return int128(lhs) < rhs; } | |
inline bool operator<(unsigned long long lhs, const int128 &rhs) { return int128(lhs) < rhs; } | |
inline bool operator>(float lhs, const int128 &rhs) { return lhs > double(rhs); } | |
inline bool operator>(double lhs, const int128 &rhs) { return lhs > double(rhs); } | |
inline bool operator>(signed char lhs, const int128 &rhs) { return int128(lhs) > rhs; } | |
inline bool operator>(unsigned char lhs, const int128 &rhs) { return int128(lhs) > rhs; } | |
inline bool operator>(short lhs, const int128 &rhs) { return int128(lhs) > rhs; } | |
inline bool operator>(unsigned short lhs, const int128 &rhs) { return int128(lhs) > rhs; } | |
inline bool operator>(int lhs, const int128 &rhs) { return int128(lhs) > rhs; } | |
inline bool operator>(unsigned int lhs, const int128 &rhs) { return int128(lhs) > rhs; } | |
inline bool operator>(long long lhs, const int128 &rhs) { return int128(lhs) > rhs; } | |
inline bool operator>(unsigned long long lhs, const int128 &rhs) { return int128(lhs) > rhs; } | |
__declspec(dllimport) std::ostream &operator<<(std::ostream &out, const int128 &val); | |
} | |
namespace std { | |
template <> | |
class numeric_limits<dynd::int128> { | |
public: | |
static const bool is_specialized = true; | |
static dynd::int128(min)() throw() { return dynd::int128(0x8000000000000000ULL, 0ULL); } | |
static dynd::int128(max)() throw() { return dynd::int128(0x7fffffffffffffffULL, 0xffffffffffffffffULL); } | |
static const int digits = 0; | |
static const int digits10 = 0; | |
static const bool is_signed = true; | |
static const bool is_integer = true; | |
static const bool is_exact = true; | |
static const int radix = 2; | |
static dynd::int128 epsilon() throw() { return dynd::int128(0ULL, 1ULL); } | |
static dynd::int128 round_error() throw() { return dynd::int128(0ULL, 1ULL); } | |
static const int min_exponent = 0; | |
static const int min_exponent10 = 0; | |
static const int max_exponent = 0; | |
static const int max_exponent10 = 0; | |
static const bool has_infinity = false; | |
static const bool has_quiet_NaN = false; | |
static const bool has_signaling_NaN = false; | |
static const float_denorm_style has_denorm = denorm_absent; | |
static const bool has_denorm_loss = false; | |
static dynd::int128 infinity() throw(); | |
static dynd::int128 quiet_NaN() throw(); | |
static dynd::int128 signaling_NaN() throw(); | |
static dynd::int128 denorm_min() throw(); | |
static const bool is_iec559 = false; | |
static const bool is_bounded = false; | |
static const bool is_modulo = false; | |
static const bool traps = false; | |
static const bool tinyness_before = false; | |
static const float_round_style round_style = round_toward_zero; | |
}; | |
} | |
namespace dynd { | |
class int128; | |
class __declspec(dllimport) uint128 { | |
public: | |
uint64_t m_lo, m_hi; | |
uint128() {} | |
uint128(uint64_t hi, uint64_t lo) : m_lo(lo), m_hi(hi) {} | |
uint128(bool1) { throw std::runtime_error("uint128(bool1) is not implemented"); } | |
uint128(char value) : m_lo(value), m_hi(0ULL) {} | |
uint128(signed char value) : m_lo(value), m_hi(0ULL) {} | |
uint128(unsigned char value) : m_lo(value), m_hi(0ULL) {} | |
uint128(short value) : m_lo(value), m_hi(0ULL) {} | |
uint128(unsigned short value) : m_lo(value), m_hi(0ULL) {} | |
uint128(int value) : m_lo(value), m_hi(0ULL) {} | |
uint128(unsigned int value) : m_lo(value), m_hi(0ULL) {} | |
uint128(long value) : m_lo(value), m_hi(0ULL) {} | |
uint128(unsigned long value) : m_lo(value), m_hi(0ULL) {} | |
uint128(long long value) : m_lo(value), m_hi(0ULL) {} | |
uint128(unsigned long long value) : m_lo(value), m_hi(0ULL) {} | |
uint128(float value); | |
uint128(double value); | |
uint128(const int128 &value); | |
uint128(const float16 &value); | |
uint128(const float128 &value); | |
bool operator==(const uint128 &rhs) const { return m_hi == rhs.m_hi && m_lo == rhs.m_lo; } | |
bool operator==(uint64_t rhs) const { return m_hi == 0 && m_lo == rhs; } | |
bool operator==(int rhs) const { return rhs >= 0 && m_hi == 0u && m_lo == static_cast<unsigned int>(rhs); } | |
bool operator==(unsigned int rhs) const { return m_hi == 0u && m_lo == rhs; } | |
uint128 operator+() const { return *this; } | |
uint128 operator-() const | |
{ | |
__pragma(warning(push)) __pragma(warning(disable : 4146)) | |
if (this->m_lo != 0) { | |
return uint128(!this->m_hi, -this->m_lo); | |
} | |
else { | |
return uint128(-this->m_hi, 0); | |
} | |
__pragma(warning(pop)) | |
} | |
bool operator!() const { return (m_hi != 0) && (m_lo != 0); } | |
uint128 operator~() const { return uint128(~m_hi, ~m_lo); } | |
bool operator!=(const uint128 &rhs) const { return m_hi != rhs.m_hi || m_lo != rhs.m_lo; } | |
bool operator!=(uint64_t rhs) const { return m_hi != 0 || m_lo != rhs; } | |
bool operator!=(int rhs) const { return rhs < 0 || m_hi != 0u || m_lo != static_cast<unsigned int>(rhs); } | |
bool operator!=(unsigned int rhs) const { return m_hi != 0u || m_lo != rhs; } | |
bool operator<(float rhs) const { return double(*this) < rhs; } | |
bool operator<(double rhs) const { return double(*this) < rhs; } | |
bool operator<(const uint128 &rhs) const { return m_hi < rhs.m_hi || (m_hi == rhs.m_hi && m_lo < rhs.m_lo); } | |
bool operator<=(const uint128 &rhs) const { return m_hi < rhs.m_hi || (m_hi == rhs.m_hi && m_lo <= rhs.m_lo); } | |
bool operator>(const uint128 &rhs) const { return rhs.operator<(*this); } | |
bool operator>=(const uint128 &rhs) const { return rhs.operator<=(*this); } | |
uint128 operator+(const uint128 &rhs) const | |
{ | |
uint64_t lo = m_lo + rhs.m_lo; | |
return uint128(m_hi + rhs.m_hi + (lo < m_lo), lo); | |
} | |
uint128 operator+(uint64_t rhs) const | |
{ | |
uint64_t lo = m_lo + rhs; | |
return uint128(m_hi + (lo < m_lo), lo); | |
} | |
uint128 operator+(uint32_t rhs) const | |
{ | |
uint64_t lo = m_lo + static_cast<uint64_t>(rhs); | |
return uint128(m_hi + (lo < m_lo), lo); | |
} | |
uint128 operator-(const uint128 &rhs) const | |
{ | |
uint64_t lo = m_lo + ~rhs.m_lo + 1; | |
return uint128(m_hi + ~rhs.m_hi + (lo < m_lo), lo); | |
} | |
uint128 operator-(uint64_t rhs) const | |
{ | |
uint64_t lo = m_lo + ~rhs + 1; | |
return uint128(m_hi + 0xffffffffffffffffULL + (lo < m_lo), lo); | |
} | |
uint128 operator*(uint32_t rhs) const; | |
uint128 operator/(uint32_t rhs) const; | |
void divrem(uint32_t rhs, uint32_t &out_rem); | |
uint128 &operator/=(uint128 ) | |
{ | |
throw std::runtime_error("operator/= is not implemented for uint128"); | |
} | |
explicit operator bool() const { return m_lo || m_hi; } | |
operator float() const { return m_lo + m_hi * 18446744073709551616.f; } | |
operator double() const { return m_lo + m_hi * 18446744073709551616.0; } | |
operator char() const { return static_cast<char>(m_lo); } | |
operator signed char() const { return static_cast<signed char>(m_lo); } | |
operator unsigned char() const { return static_cast<unsigned char>(m_lo); } | |
operator short() const { return static_cast<short>(m_lo); } | |
operator unsigned short() const { return static_cast<unsigned short>(m_lo); } | |
operator int() const { return static_cast<int>(m_lo); } | |
operator unsigned int() const { return static_cast<unsigned int>(m_lo); } | |
operator long() const { return static_cast<long>(m_lo); } | |
operator unsigned long() const { return static_cast<unsigned long>(m_lo); } | |
operator long long() const { return static_cast<long long>(m_lo); } | |
operator unsigned long long() const { return static_cast<unsigned long long>(m_lo); } | |
}; | |
template <> | |
struct is_integral<uint128> : std::true_type { | |
}; | |
inline uint128 operator/(uint128 , uint128 ) | |
{ | |
throw std::runtime_error("operator/ is not implemented for int128"); | |
} | |
} | |
namespace std { | |
template <> | |
struct common_type<dynd::uint128, bool> { | |
typedef dynd::uint128 type; | |
}; | |
template <> | |
struct common_type<dynd::uint128, dynd::bool1> { | |
typedef dynd::uint128 type; | |
}; | |
template <> | |
struct common_type<dynd::uint128, char> { | |
typedef dynd::uint128 type; | |
}; | |
template <> | |
struct common_type<dynd::uint128, signed char> { | |
typedef dynd::uint128 type; | |
}; | |
template <> | |
struct common_type<dynd::uint128, unsigned char> { | |
typedef dynd::uint128 type; | |
}; | |
template <> | |
struct common_type<dynd::uint128, short> { | |
typedef dynd::uint128 type; | |
}; | |
template <> | |
struct common_type<dynd::uint128, unsigned short> { | |
typedef dynd::uint128 type; | |
}; | |
template <> | |
struct common_type<dynd::uint128, int> { | |
typedef dynd::uint128 type; | |
}; | |
template <> | |
struct common_type<dynd::uint128, unsigned int> { | |
typedef dynd::uint128 type; | |
}; | |
template <> | |
struct common_type<dynd::uint128, long> { | |
typedef dynd::uint128 type; | |
}; | |
template <> | |
struct common_type<dynd::uint128, unsigned long> { | |
typedef dynd::uint128 type; | |
}; | |
template <> | |
struct common_type<dynd::uint128, long long> { | |
typedef dynd::uint128 type; | |
}; | |
template <> | |
struct common_type<dynd::uint128, unsigned long long> { | |
typedef dynd::uint128 type; | |
}; | |
template <> | |
struct common_type<dynd::uint128, dynd::int128> { | |
typedef dynd::uint128 type; | |
}; | |
template <> | |
struct common_type<dynd::uint128, dynd::uint128> { | |
typedef dynd::uint128 type; | |
}; | |
template <> | |
struct common_type<dynd::uint128, float> { | |
typedef float type; | |
}; | |
template <> | |
struct common_type<dynd::uint128, double> { | |
typedef double type; | |
}; | |
template <typename T> | |
struct common_type<T, dynd::uint128> : common_type<dynd::uint128, T> { | |
}; | |
} | |
namespace dynd { | |
inline bool operator==(unsigned int lhs, const uint128 &rhs) { return rhs.m_hi == 0u && lhs == rhs.m_lo; } | |
inline bool operator!=(unsigned int lhs, const uint128 &rhs) { return rhs.m_hi != 0u || lhs != rhs.m_lo; } | |
inline bool operator<(float lhs, const uint128 &rhs) { return lhs < double(rhs); } | |
inline bool operator<(double lhs, const uint128 &rhs) { return lhs < double(rhs); } | |
inline bool operator<(signed char lhs, const uint128 &rhs) { return lhs < 0 || uint128(lhs) < rhs; } | |
inline bool operator<(unsigned char lhs, const uint128 &rhs) { return uint128(lhs) < rhs; } | |
inline bool operator<(short lhs, const uint128 &rhs) { return lhs < 0 || uint128(lhs) < rhs; } | |
inline bool operator<(unsigned short lhs, const uint128 &rhs) { return uint128(lhs) < rhs; } | |
inline bool operator<(int lhs, const uint128 &rhs) { return lhs < 0 || uint128(lhs) < rhs; } | |
inline bool operator<(unsigned int lhs, const uint128 &rhs) { return uint128(lhs) < rhs; } | |
inline bool operator<(long lhs, const uint128 &rhs) { return lhs < 0 || uint128(lhs) < rhs; } | |
inline bool operator<(unsigned long lhs, const uint128 &rhs) { return uint128(lhs) < rhs; } | |
inline bool operator<(long long lhs, const uint128 &rhs) { return lhs < 0 || uint128(lhs) < rhs; } | |
inline bool operator<(unsigned long long lhs, const uint128 &rhs) { return uint128(lhs) < rhs; } | |
template <typename T, typename dynd::detail::enable_for<T, unsigned char, unsigned short, unsigned int, unsigned long, | |
unsigned long long>::type = 0> | |
inline void operator+=(uint128 , T ) | |
{ | |
throw std::runtime_error("operator += is not implemented for uint128"); | |
} | |
__declspec(dllimport) std::ostream &operator<<(std::ostream &out, const uint128 &val); | |
} | |
namespace std { | |
template <> | |
class numeric_limits<dynd::uint128> { | |
public: | |
static const bool is_specialized = true; | |
static dynd::uint128(min)() throw() { return dynd::uint128(0ULL, 0ULL); } | |
static dynd::uint128(max)() throw() { return dynd::uint128(0xffffffffffffffffULL, 0xffffffffffffffffULL); } | |
static const int digits = 0; | |
static const int digits10 = 0; | |
static const bool is_signed = true; | |
static const bool is_integer = true; | |
static const bool is_exact = true; | |
static const int radix = 2; | |
static dynd::uint128 epsilon() throw() { return dynd::uint128(0ULL, 1ULL); } | |
static dynd::uint128 round_error() throw() { return dynd::uint128(0ULL, 1ULL); } | |
static const int min_exponent = 0; | |
static const int min_exponent10 = 0; | |
static const int max_exponent = 0; | |
static const int max_exponent10 = 0; | |
static const bool has_infinity = false; | |
static const bool has_quiet_NaN = false; | |
static const bool has_signaling_NaN = false; | |
static const float_denorm_style has_denorm = denorm_absent; | |
static const bool has_denorm_loss = false; | |
static dynd::uint128 infinity() throw(); | |
static dynd::uint128 quiet_NaN() throw(); | |
static dynd::uint128 signaling_NaN() throw(); | |
static dynd::uint128 denorm_min() throw(); | |
static const bool is_iec559 = false; | |
static const bool is_bounded = false; | |
static const bool is_modulo = false; | |
static const bool traps = false; | |
static const bool tinyness_before = false; | |
static const float_round_style round_style = round_toward_zero; | |
}; | |
} | |
namespace dynd { | |
__declspec(dllimport) uint16_t float_to_halfbits(float value); | |
__declspec(dllimport) uint16_t double_to_halfbits(double value); | |
__declspec(dllimport) float halfbits_to_float(uint16_t value); | |
__declspec(dllimport) double halfbits_to_double(uint16_t value); | |
class __declspec(dllimport) float16 { | |
uint16_t m_bits; | |
public: | |
class raw_bits_tag { | |
}; | |
explicit float16(uint16_t bits, raw_bits_tag) : m_bits(bits) {} | |
float16() {} | |
explicit float16(bool1 rhs) : m_bits(rhs ? (0x3c00u) : (0x0000u)) {} | |
explicit float16(bool rhs) : m_bits(rhs ? (0x3c00u) : (0x0000u)) {} | |
explicit float16(int8 value) : float16(static_cast<float32>(value)) {} | |
explicit float16(int16 value) : float16(static_cast<float32>(value)) {} | |
explicit float16(int32 value) : float16(static_cast<float32>(value)) {} | |
explicit float16(int64 value) : float16(static_cast<float32>(value)) {} | |
explicit float16(int128 value); | |
explicit float16(uint16 value) : float16(static_cast<float32>(value)) {} | |
explicit float16(uint32 value) : float16(static_cast<float32>(value)) {} | |
explicit float16(uint64 value) : float16(static_cast<float32>(value)) {} | |
explicit float16(uint128 value); | |
explicit float16(float f) : m_bits(float_to_halfbits(f)) {} | |
explicit float16(double d) : m_bits(double_to_halfbits(d)) {} | |
explicit float16(const float128 &value); | |
float16(const float16 &rhs) : m_bits(rhs.m_bits) {} | |
explicit operator int8() const { return static_cast<int8>(halfbits_to_float(m_bits)); } | |
explicit operator int16() const | |
{ | |
return static_cast<int16>(halfbits_to_float(m_bits)); | |
} | |
explicit operator int32() const { return static_cast<int32>(halfbits_to_float(m_bits)); } | |
explicit operator int64() const { return static_cast<int64>(halfbits_to_float(m_bits)); } | |
explicit operator int128() const; | |
explicit operator uint8() const { return static_cast<uint8>(halfbits_to_float(m_bits)); } | |
explicit operator uint16() const { return static_cast<uint16>(halfbits_to_float(m_bits)); } | |
explicit operator uint32() const { return static_cast<uint32>(halfbits_to_float(m_bits)); } | |
explicit operator uint64() const { return static_cast<uint64>(halfbits_to_float(m_bits)); } | |
explicit operator uint128() const; | |
operator float32() const | |
{ | |
return halfbits_to_float(m_bits); | |
} | |
explicit operator float64() const { return halfbits_to_double(m_bits); } | |
explicit operator float128() const; | |
uint16_t bits() const { return m_bits; } | |
bool iszero() const { return (m_bits & 0x7fff) == 0; } | |
bool signbit_() const { return (m_bits & 0x8000u) != 0; } | |
bool isnan_() const { return ((m_bits & 0x7c00u) == 0x7c00u) && ((m_bits & 0x03ffu) != 0x0000u); } | |
bool isinf_() const { return ((m_bits & 0x7fffu) == 0x7c00u); } | |
bool isfinite_() const { return ((m_bits & 0x7c00u) != 0x7c00u); } | |
bool less_nonan(const float16 &rhs) const | |
{ | |
if (signbit_()) { | |
if (rhs.signbit_()) { | |
return m_bits > rhs.m_bits; | |
} | |
else { | |
return (m_bits != 0x8000u) || (rhs.m_bits != 0x0000u); | |
} | |
} | |
else { | |
if (rhs.signbit_()) { | |
return false; | |
} | |
else { | |
return m_bits < rhs.m_bits; | |
} | |
} | |
} | |
bool less_equal_nonan(const float16 &rhs) const | |
{ | |
if (signbit_()) { | |
if (rhs.signbit_()) { | |
return m_bits >= rhs.m_bits; | |
} | |
else { | |
return true; | |
} | |
} | |
else { | |
if (rhs.signbit_()) { | |
return (m_bits == 0x0000u) && (rhs.m_bits == 0x8000u); | |
} | |
else { | |
return m_bits <= rhs.m_bits; | |
} | |
} | |
} | |
friend float16 float16_from_bits(uint16_t bits); | |
float16 operator+() const { return *this; } | |
float16 operator-() const { return float16(-static_cast<float>(*this)); } | |
bool operator!() const { return (0x7fffu | m_bits) == 0; } | |
explicit operator bool() const { return (0x7ffu | m_bits) != 0; } | |
}; | |
inline float16 operator+(const float16 &, const float16 &) | |
{ | |
throw std::runtime_error("+ is not implemented for float16"); | |
} | |
inline bool operator<(const float16 &lhs, const float16 &rhs) | |
{ | |
return static_cast<double>(lhs) < static_cast<double>(rhs); | |
} | |
template <typename T> | |
typename std::enable_if<is_arithmetic<T>::value && !std::is_same<T, float128>::value, bool>::type | |
operator<(const float16 &lhs, const T &rhs) | |
{ | |
return static_cast<double>(lhs) < static_cast<double>(rhs); | |
} | |
template <typename T> | |
typename std::enable_if<is_arithmetic<T>::value && !std::is_same<T, float128>::value, bool>::type | |
operator<(const T &lhs, const float16 &rhs) | |
{ | |
return static_cast<double>(lhs) < static_cast<double>(rhs); | |
} | |
inline bool operator<=(const float16 &lhs, const float16 &rhs) | |
{ | |
return static_cast<double>(lhs) <= static_cast<double>(rhs); | |
} | |
template <typename T> | |
typename std::enable_if<is_arithmetic<T>::value, bool>::type operator<=(const float16 &lhs, const T &rhs) | |
{ | |
return static_cast<double>(lhs) <= static_cast<double>(rhs); | |
} | |
template <typename T> | |
typename std::enable_if<is_arithmetic<T>::value, bool>::type operator<=(const T &lhs, const float16 &rhs) | |
{ | |
return static_cast<double>(lhs) <= static_cast<double>(rhs); | |
} | |
inline bool operator==(const float16 &lhs, const float16 &rhs) | |
{ | |
return static_cast<double>(lhs) == static_cast<double>(rhs); | |
} | |
template <typename T> | |
typename std::enable_if<is_arithmetic<T>::value && !std::is_same<T, float128>::value, bool>::type | |
operator==(const float16 &lhs, const T &rhs) | |
{ | |
return static_cast<double>(lhs) == static_cast<double>(rhs); | |
} | |
template <typename T> | |
typename std::enable_if<is_arithmetic<T>::value && !std::is_same<T, float128>::value, bool>::type | |
operator==(const T &lhs, const float16 &rhs) | |
{ | |
return static_cast<double>(lhs) == static_cast<double>(rhs); | |
} | |
inline bool operator!=(const float16 &lhs, const float16 &rhs) | |
{ | |
return static_cast<double>(lhs) != static_cast<double>(rhs); | |
} | |
template <typename T> | |
typename std::enable_if<is_arithmetic<T>::value && !std::is_same<T, float128>::value, bool>::type | |
operator!=(const float16 &lhs, const T &rhs) | |
{ | |
return static_cast<double>(lhs) != static_cast<double>(rhs); | |
} | |
template <typename T> | |
typename std::enable_if<is_arithmetic<T>::value && !std::is_same<T, float128>::value, bool>::type | |
operator!=(const T &lhs, const float16 &rhs) | |
{ | |
return static_cast<double>(lhs) != static_cast<double>(rhs); | |
} | |
inline bool operator>=(const float16 &lhs, const float16 &rhs) | |
{ | |
return static_cast<double>(lhs) >= static_cast<double>(rhs); | |
} | |
template <typename T> | |
typename std::enable_if<is_arithmetic<T>::value, bool>::type operator>=(const float16 &lhs, const T &rhs) | |
{ | |
return static_cast<double>(lhs) >= static_cast<double>(rhs); | |
} | |
template <typename T> | |
typename std::enable_if<is_arithmetic<T>::value, bool>::type operator>=(const T &lhs, const float16 &rhs) | |
{ | |
return static_cast<double>(lhs) >= static_cast<double>(rhs); | |
} | |
inline bool operator>(const float16 &lhs, const float16 &rhs) | |
{ | |
return static_cast<double>(lhs) > static_cast<double>(rhs); | |
} | |
template <typename T> | |
typename std::enable_if<is_arithmetic<T>::value && !std::is_same<T, float128>::value, bool>::type | |
operator>(const float16 &lhs, const T &rhs) | |
{ | |
return static_cast<double>(lhs) > static_cast<double>(rhs); | |
} | |
template <typename T> | |
typename std::enable_if<is_arithmetic<T>::value && !std::is_same<T, float128>::value, bool>::type | |
operator>(const T &lhs, const float16 &rhs) | |
{ | |
return static_cast<double>(lhs) > static_cast<double>(rhs); | |
} | |
inline float16 float16_from_bits(uint16_t bits) { return float16(bits, float16::raw_bits_tag()); } | |
inline float16 floor(float16 value) { return float16(std::floor(static_cast<float>(value))); } | |
inline std::ostream &operator<<(std::ostream &o, const float16 &) | |
{ | |
return (o << "<float16 printing unimplemented>"); | |
} | |
} | |
namespace dynd { | |
class __declspec(dllimport) float128 { | |
public: | |
uint64_t m_lo, m_hi; | |
float128() {} | |
float128(uint64_t hi, uint64_t lo) : m_lo(lo), m_hi(hi) {} | |
float128(bool1) {} | |
float128(signed char value); | |
float128(unsigned char value); | |
float128(short value); | |
float128(unsigned short value); | |
float128(int value); | |
float128(unsigned int value); | |
float128(long value) { *this = float128((long long)value); } | |
float128(unsigned long value) { *this = float128((unsigned long long)value); } | |
float128(long long value); | |
float128(unsigned long long value); | |
float128(double value); | |
float128(const int128 &value); | |
float128(const uint128 &value); | |
float128(const float16 &value); | |
float128 &operator/=(float128 ) | |
{ | |
throw std::runtime_error("operator/= is not implemented for float128"); | |
} | |
operator signed char() const | |
{ | |
throw std::runtime_error("float128 conversions are not completed"); | |
} | |
operator unsigned char() const | |
{ | |
throw std::runtime_error("float128 conversions are not completed"); | |
} | |
operator short() const | |
{ | |
throw std::runtime_error("float128 conversions are not completed"); | |
} | |
operator unsigned short() const | |
{ | |
throw std::runtime_error("float128 conversions are not completed"); | |
} | |
operator int() const | |
{ | |
throw std::runtime_error("float128 conversions are not completed"); | |
} | |
operator unsigned int() const | |
{ | |
throw std::runtime_error("float128 conversions are not completed"); | |
} | |
operator long() const | |
{ | |
throw std::runtime_error("float128 conversions are not completed"); | |
} | |
operator unsigned long() const | |
{ | |
throw std::runtime_error("float128 conversions are not completed"); | |
} | |
operator long long() const | |
{ | |
throw std::runtime_error("float128 conversions are not completed"); | |
} | |
operator unsigned long long() const | |
{ | |
throw std::runtime_error("float128 conversions are not completed"); | |
} | |
operator float() const | |
{ | |
throw std::runtime_error("float128 conversions are not completed"); | |
} | |
operator double() const | |
{ | |
throw std::runtime_error("float128 conversions are not completed"); | |
} | |
explicit float128(const bool &rhs) : m_lo(0ULL), m_hi(rhs ? 0x3fff000000000000ULL : 0ULL) {} | |
bool iszero() const { return (m_hi & 0x7fffffffffffffffULL) == 0 && m_lo == 0; } | |
bool signbit_() const { return (m_hi & 0x8000000000000000ULL) != 0; } | |
bool isnan_() const | |
{ | |
return (m_hi & 0x7fff000000000000ULL) == 0x7fff000000000000ULL && | |
((m_hi & 0x0000ffffffffffffULL) != 0ULL || m_lo != 0ULL); | |
} | |
bool isinf_() const { return (m_hi & 0x7fffffffffffffffULL) == 0x7fff000000000000ULL && (m_lo == 0ULL); } | |
bool isfinite_() const { return (m_hi & 0x7fff000000000000ULL) != 0x7fff000000000000ULL; } | |
bool less_nonan(const float128 &rhs) const | |
{ | |
if (signbit_()) { | |
if (rhs.signbit_()) { | |
return m_hi > rhs.m_hi || (m_hi == rhs.m_hi && m_lo > rhs.m_lo); | |
} | |
else { | |
return (m_hi != 0x8000000000000000ULL) || (m_lo != 0LL) || (rhs.m_hi != 0LL) || rhs.m_lo != 0LL; | |
} | |
} | |
else { | |
if (rhs.signbit_()) { | |
return false; | |
} | |
else { | |
return m_hi < rhs.m_hi || (m_hi == rhs.m_hi && m_lo < rhs.m_lo); | |
} | |
} | |
} | |
bool less_equal_nonan(const float128 &rhs) const | |
{ | |
if (signbit_()) { | |
if (rhs.signbit_()) { | |
return m_hi > rhs.m_hi || (m_hi == rhs.m_hi && m_lo >= rhs.m_lo); | |
} | |
else { | |
return true; | |
} | |
} | |
else { | |
if (rhs.signbit_()) { | |
return (m_hi == 0x8000000000000000ULL) && (m_lo == 0LL) && (rhs.m_hi == 0LL) && rhs.m_lo == 0LL; | |
} | |
else { | |
return m_hi < rhs.m_hi || (m_hi == rhs.m_hi && m_lo <= rhs.m_lo); | |
} | |
} | |
} | |
float128 operator+() const { return *this; } | |
float128 operator-() const { return float128(-static_cast<double>(*this)); } | |
bool operator!() const { return ((0x7fffffffffffffffULL | m_hi) == 0) && (m_lo == 0); } | |
explicit operator bool() const { return (m_lo != 0) || ((0x7fffffffffffffffULL | m_hi) != 0); } | |
}; | |
template <> | |
struct is_floating_point<float128> : std::true_type { | |
}; | |
inline float128 operator+(const float128 &, const float128 &) | |
{ | |
throw std::runtime_error("addition for float128 is not implemented"); | |
} | |
inline float128 operator*(float128 , float128 ) | |
{ | |
throw std::runtime_error("operator* for float128 is not implemented"); | |
} | |
inline float128 operator/(float128 , float128 ) | |
{ | |
throw std::runtime_error("operator/ for float128 is not implemented"); | |
} | |
inline bool operator<(const float128 &lhs, const float128 &rhs) | |
{ | |
return static_cast<double>(lhs) < static_cast<double>(rhs); | |
} | |
template <typename T> | |
typename std::enable_if<is_arithmetic<T>::value, bool>::type operator<(const float128 &lhs, const T &rhs) | |
{ | |
return static_cast<double>(lhs) < static_cast<double>(rhs); | |
} | |
template <typename T> | |
typename std::enable_if<is_arithmetic<T>::value, bool>::type operator<(const T &lhs, const float128 &rhs) | |
{ | |
return static_cast<double>(lhs) < static_cast<double>(rhs); | |
} | |
inline bool operator<=(const float128 &lhs, const float128 &rhs) | |
{ | |
return static_cast<double>(lhs) <= static_cast<double>(rhs); | |
} | |
template <typename T> | |
typename std::enable_if<is_arithmetic<T>::value, bool>::type operator<=(const float128 &lhs, const T &rhs) | |
{ | |
return static_cast<double>(lhs) <= static_cast<double>(rhs); | |
} | |
template <typename T> | |
typename std::enable_if<is_arithmetic<T>::value, bool>::type operator<=(const T &lhs, const float128 &rhs) | |
{ | |
return static_cast<double>(lhs) <= static_cast<double>(rhs); | |
} | |
inline bool operator==(const float128 &lhs, const float128 &rhs) | |
{ | |
return static_cast<double>(lhs) == static_cast<double>(rhs); | |
} | |
template <typename T> | |
typename std::enable_if<is_arithmetic<T>::value, bool>::type operator==(const float128 &lhs, const T &rhs) | |
{ | |
return static_cast<double>(lhs) == static_cast<double>(rhs); | |
} | |
template <typename T> | |
typename std::enable_if<is_arithmetic<T>::value, bool>::type operator==(const T &lhs, const float128 &rhs) | |
{ | |
return static_cast<double>(lhs) == static_cast<double>(rhs); | |
} | |
inline bool operator!=(const float128 &lhs, const float128 &rhs) | |
{ | |
return static_cast<double>(lhs) != static_cast<double>(rhs); | |
} | |
template <typename T> | |
typename std::enable_if<is_arithmetic<T>::value, bool>::type operator!=(const float128 &lhs, const T &rhs) | |
{ | |
return static_cast<double>(lhs) != static_cast<double>(rhs); | |
} | |
template <typename T> | |
typename std::enable_if<is_arithmetic<T>::value, bool>::type operator!=(const T &lhs, const float128 &rhs) | |
{ | |
return static_cast<double>(lhs) != static_cast<double>(rhs); | |
} | |
inline bool operator>=(const float128 &lhs, const float128 &rhs) | |
{ | |
return static_cast<double>(lhs) >= static_cast<double>(rhs); | |
} | |
template <typename T> | |
typename std::enable_if<is_arithmetic<T>::value, bool>::type operator>=(const float128 &lhs, const T &rhs) | |
{ | |
return static_cast<double>(lhs) >= static_cast<double>(rhs); | |
} | |
template <typename T> | |
typename std::enable_if<is_arithmetic<T>::value, bool>::type operator>=(const T &lhs, const float128 &rhs) | |
{ | |
return static_cast<double>(lhs) >= static_cast<double>(rhs); | |
} | |
inline bool operator>(const float128 &lhs, const float128 &rhs) | |
{ | |
return static_cast<double>(lhs) > static_cast<double>(rhs); | |
} | |
template <typename T> | |
typename std::enable_if<is_arithmetic<T>::value, bool>::type operator>(const float128 &lhs, const T &rhs) | |
{ | |
return static_cast<double>(lhs) > static_cast<double>(rhs); | |
} | |
template <typename T> | |
typename std::enable_if<is_arithmetic<T>::value, bool>::type operator>(const T &lhs, const float128 &rhs) | |
{ | |
return static_cast<double>(lhs) > static_cast<double>(rhs); | |
} | |
inline std::ostream &operator<<(std::ostream &o, const float128 &) | |
{ | |
return (o << "<float128 printing unimplemented>"); | |
} | |
inline float128 floor(float128 value) { return static_cast<double>(value); } | |
} | |
namespace std { | |
template <> | |
struct common_type<dynd::float128, bool> { | |
typedef dynd::float128 type; | |
}; | |
template <> | |
struct common_type<dynd::float128, dynd::bool1> { | |
typedef dynd::float128 type; | |
}; | |
template <> | |
struct common_type<dynd::float128, char> { | |
typedef dynd::float128 type; | |
}; | |
template <> | |
struct common_type<dynd::float128, signed char> { | |
typedef dynd::float128 type; | |
}; | |
template <> | |
struct common_type<dynd::float128, unsigned char> { | |
typedef dynd::float128 type; | |
}; | |
template <> | |
struct common_type<dynd::float128, short> { | |
typedef dynd::float128 type; | |
}; | |
template <> | |
struct common_type<dynd::float128, unsigned short> { | |
typedef dynd::float128 type; | |
}; | |
template <> | |
struct common_type<dynd::float128, int> { | |
typedef dynd::float128 type; | |
}; | |
template <> | |
struct common_type<dynd::float128, unsigned int> { | |
typedef dynd::float128 type; | |
}; | |
template <> | |
struct common_type<dynd::float128, long> { | |
typedef dynd::float128 type; | |
}; | |
template <> | |
struct common_type<dynd::float128, unsigned long> { | |
typedef dynd::float128 type; | |
}; | |
template <> | |
struct common_type<dynd::float128, long long> { | |
typedef dynd::float128 type; | |
}; | |
template <> | |
struct common_type<dynd::float128, unsigned long long> { | |
typedef dynd::float128 type; | |
}; | |
template <> | |
struct common_type<dynd::float128, dynd::int128> { | |
typedef dynd::float128 type; | |
}; | |
template <> | |
struct common_type<dynd::float128, dynd::uint128> { | |
typedef dynd::float128 type; | |
}; | |
template <> | |
struct common_type<dynd::float128, float> { | |
typedef dynd::float128 type; | |
}; | |
template <> | |
struct common_type<dynd::float128, double> { | |
typedef dynd::float128 type; | |
}; | |
template <> | |
struct common_type<dynd::float128, dynd::float128> { | |
typedef dynd::float128 type; | |
}; | |
template <typename T> | |
struct common_type<T, dynd::float128> : common_type<dynd::float128, T> { | |
}; | |
} | |
namespace dynd { | |
template <typename T> | |
class complex { | |
public: | |
T m_real, m_imag; | |
typedef T value_type; | |
complex(const T &re = 0.0, const T &im = 0.0) : m_real(re), m_imag(im) {} | |
template <typename U> | |
complex(const complex<U> &rhs) | |
: m_real(static_cast<T>(rhs.m_real)), m_imag(static_cast<T>(rhs.m_imag)) | |
{ | |
} | |
complex(const std::complex<T> &rhs) : m_real(rhs.real()), m_imag(rhs.imag()) {} | |
T real() const { return m_real; } | |
T imag() const { return m_imag; } | |
complex<T> &operator=(const complex<T> &rhs) | |
{ | |
m_real = rhs.m_real; | |
m_imag = rhs.m_imag; | |
return *this; | |
} | |
complex<T> &operator+=(const complex<T> &rhs) | |
{ | |
m_real += rhs.m_real; | |
m_imag += rhs.m_imag; | |
return *this; | |
} | |
complex<T> &operator+=(const T &rhs) | |
{ | |
m_real += rhs; | |
return *this; | |
} | |
complex<T> &operator-=(const complex<T> &rhs) | |
{ | |
m_real -= rhs.m_real; | |
m_imag -= rhs.m_imag; | |
return *this; | |
} | |
complex<T> &operator-=(const T &rhs) | |
{ | |
m_real -= rhs; | |
return *this; | |
} | |
complex<T> operator*=(const complex<T> &rhs) | |
{ | |
new (this) complex<T>(m_real * rhs.m_real - m_imag * rhs.m_imag, m_real * rhs.m_imag + rhs.m_real * m_imag); | |
return *this; | |
} | |
complex<T> operator*=(const T &rhs) | |
{ | |
m_real *= rhs; | |
m_imag *= rhs; | |
return *this; | |
} | |
complex<T> &operator/=(const complex<T> &rhs) | |
{ | |
T denom = rhs.m_real * rhs.m_real + rhs.m_imag * rhs.m_imag; | |
new (this) complex<T>((m_real * rhs.m_real + m_imag * rhs.m_imag) / denom, | |
(rhs.m_real * m_imag - m_real * rhs.m_imag) / denom); | |
return *this; | |
} | |
complex<T> &operator/=(const T &rhs) | |
{ | |
m_real /= rhs; | |
m_imag /= rhs; | |
return *this; | |
} | |
explicit operator bool() const { return m_real || m_imag; } | |
explicit operator T() const { return m_real; } | |
template <typename U, | |
typename = typename std::enable_if<is_mixed_arithmetic<T, U>::value && !std::is_same<U, bool>::value>::type> | |
explicit operator U() const | |
{ | |
return static_cast<U>(m_real); | |
} | |
operator std::complex<T>() const { return std::complex<T>(m_real, m_imag); } | |
}; | |
template <typename T> | |
struct is_complex<complex<T>> : std::true_type { | |
}; | |
} | |
namespace std { | |
template <typename T> | |
struct common_type<dynd::complex<T>, bool> { | |
typedef dynd::complex<T> type; | |
}; | |
template <typename T> | |
struct common_type<dynd::complex<T>, dynd::bool1> { | |
typedef dynd::complex<T> type; | |
}; | |
template <typename T> | |
struct common_type<dynd::complex<T>, char> { | |
typedef char type; | |
}; | |
template <typename T> | |
struct common_type<dynd::complex<T>, signed char> { | |
typedef dynd::complex<T> type; | |
}; | |
template <typename T> | |
struct common_type<dynd::complex<T>, unsigned char> { | |
typedef dynd::complex<T> type; | |
}; | |
template <typename T> | |
struct common_type<dynd::complex<T>, short> { | |
typedef dynd::complex<T> type; | |
}; | |
template <typename T> | |
struct common_type<dynd::complex<T>, unsigned short> { | |
typedef dynd::complex<T> type; | |
}; | |
template <typename T> | |
struct common_type<dynd::complex<T>, int> { | |
typedef dynd::complex<T> type; | |
}; | |
template <typename T> | |
struct common_type<dynd::complex<T>, unsigned int> { | |
typedef dynd::int128 type; | |
}; | |
template <typename T> | |
struct common_type<dynd::complex<T>, long> { | |
typedef dynd::complex<T> type; | |
}; | |
template <typename T> | |
struct common_type<dynd::complex<T>, unsigned long> { | |
typedef dynd::complex<T> type; | |
}; | |
template <typename T> | |
struct common_type<dynd::complex<T>, long long> { | |
typedef dynd::complex<T> type; | |
}; | |
template <typename T> | |
struct common_type<dynd::complex<T>, unsigned long long> { | |
typedef dynd::complex<T> type; | |
}; | |
template <typename T> | |
struct common_type<dynd::complex<T>, dynd::int128> { | |
typedef dynd::complex<T> type; | |
}; | |
template <typename T> | |
struct common_type<dynd::complex<T>, dynd::uint128> { | |
typedef dynd::complex<T> type; | |
}; | |
template <typename T> | |
struct common_type<dynd::complex<T>, float> { | |
typedef dynd::complex<typename common_type<T, float>::type> type; | |
}; | |
template <typename T> | |
struct common_type<dynd::complex<T>, double> { | |
typedef dynd::complex<typename common_type<T, double>::type> type; | |
}; | |
template <typename T> | |
struct common_type<dynd::complex<T>, dynd::float128> { | |
typedef dynd::complex<typename common_type<T, dynd::float128>::type> type; | |
}; | |
template <typename T, typename U> | |
struct common_type<dynd::complex<T>, dynd::complex<U>> { | |
typedef dynd::complex<typename common_type<T, U>::type> type; | |
}; | |
template <typename T, typename U> | |
struct common_type<T, dynd::complex<U>> : common_type<dynd::complex<U>, T> { | |
}; | |
} | |
namespace dynd { | |
typedef complex<float32> complex64; | |
typedef complex<float64> complex128; | |
template <typename T, typename U> | |
bool operator==(complex<T> lhs, complex<U> rhs) | |
{ | |
return (lhs.m_real == rhs.m_real) && (lhs.m_imag == rhs.m_imag); | |
} | |
template <typename T, typename U> | |
typename std::enable_if<std::is_integral<U>::value || std::is_floating_point<U>::value, bool>::type | |
operator==(complex<T> lhs, U rhs) | |
{ | |
return (lhs.m_real == rhs) && !lhs.m_imag; | |
} | |
template <typename T, typename U> | |
typename std::enable_if<std::is_integral<T>::value || std::is_floating_point<T>::value, bool>::type | |
operator==(T lhs, complex<U> rhs) | |
{ | |
return rhs == lhs; | |
} | |
template <typename T> | |
bool operator==(complex<T> lhs, std::complex<T> rhs) | |
{ | |
return (lhs.m_real == rhs.real()) && (lhs.m_imag == rhs.imag()); | |
} | |
template <typename T> | |
bool operator==(std::complex<T> lhs, complex<T> rhs) | |
{ | |
return rhs == lhs; | |
} | |
template <typename T, typename U> | |
bool operator!=(complex<T> lhs, complex<U> rhs) | |
{ | |
return !(lhs == rhs); | |
} | |
template <typename T, typename U> | |
bool operator!=(complex<T> lhs, U rhs) | |
{ | |
return lhs.m_real == rhs && !lhs.m_imag; | |
} | |
template <typename T> | |
complex<T> operator+(const complex<T> &rhs) | |
{ | |
return complex<T>(+rhs.m_real, +rhs.m_imag); | |
} | |
template <typename T> | |
complex<T> operator-(const complex<T> &rhs) | |
{ | |
return complex<T>(-rhs.m_real, -rhs.m_imag); | |
} | |
template <typename T> | |
complex<T> operator!(const complex<T> &rhs) | |
{ | |
return (!rhs.m_real && !rhs.m_imag); | |
} | |
template <typename T> | |
complex<T> operator+(complex<T> lhs, complex<T> rhs) | |
{ | |
return lhs += rhs; | |
} | |
template <typename T, typename U> | |
complex<typename std::common_type<T, U>::type> operator+(complex<T> lhs, complex<U> rhs) | |
{ | |
return static_cast<complex<typename std::common_type<T, U>::type>>(lhs) + | |
static_cast<complex<typename std::common_type<T, U>::type>>(rhs); | |
} | |
template <typename T> | |
complex<T> operator+(complex<T> lhs, T rhs) | |
{ | |
return lhs += rhs; | |
} | |
template <typename T, typename U> | |
typename std::enable_if<std::is_integral<U>::value || std::is_floating_point<U>::value, | |
complex<typename std::common_type<T, U>::type>>::type | |
operator+(complex<T> lhs, U rhs) | |
{ | |
return static_cast<complex<typename std::common_type<T, U>::type>>(lhs) + | |
static_cast<typename std::common_type<T, U>::type>(rhs); | |
} | |
template <typename T> | |
complex<T> operator+(T lhs, complex<T> rhs) | |
{ | |
return complex<T>(lhs + rhs.m_real, rhs.m_imag); | |
} | |
template <typename T, typename U> | |
typename std::enable_if<std::is_integral<T>::value || std::is_floating_point<T>::value, | |
complex<typename std::common_type<T, U>::type>>::type | |
operator+(T lhs, complex<U> rhs) | |
{ | |
return static_cast<typename std::common_type<T, U>::type>(lhs) + | |
static_cast<complex<typename std::common_type<T, U>::type>>(rhs); | |
} | |
template <typename T> | |
complex<T> operator-(complex<T> lhs, complex<T> rhs) | |
{ | |
return lhs -= rhs; | |
} | |
template <typename T, typename U> | |
complex<typename std::common_type<T, U>::type> operator-(complex<T> lhs, complex<U> rhs) | |
{ | |
return static_cast<complex<typename std::common_type<T, U>::type>>(lhs) - | |
static_cast<complex<typename std::common_type<T, U>::type>>(rhs); | |
} | |
template <typename T> | |
complex<T> operator-(complex<T> lhs, T rhs) | |
{ | |
return lhs -= rhs; | |
} | |
template <typename T, typename U> | |
typename std::enable_if<std::is_integral<U>::value || std::is_floating_point<U>::value, | |
complex<typename std::common_type<T, U>::type>>::type | |
operator-(complex<T> lhs, U rhs) | |
{ | |
return static_cast<complex<typename std::common_type<T, U>::type>>(lhs) - | |
static_cast<typename std::common_type<T, U>::type>(rhs); | |
} | |
template <typename T> | |
complex<T> operator-(T lhs, complex<T> rhs) | |
{ | |
return complex<T>(lhs - rhs.m_real, -rhs.m_imag); | |
} | |
template <typename T, typename U> | |
typename std::enable_if<std::is_integral<T>::value || std::is_floating_point<T>::value, | |
complex<typename std::common_type<T, U>::type>>::type | |
operator-(T lhs, complex<U> rhs) | |
{ | |
return static_cast<typename std::common_type<T, U>::type>(lhs) - | |
static_cast<complex<typename std::common_type<T, U>::type>>(rhs); | |
} | |
template <typename T> | |
complex<T> operator*(complex<T> lhs, complex<T> rhs) | |
{ | |
return lhs *= rhs; | |
} | |
template <typename T, typename U> | |
complex<typename std::common_type<T, U>::type> operator*(complex<T> lhs, complex<U> rhs) | |
{ | |
return static_cast<complex<typename std::common_type<T, U>::type>>(lhs) * | |
static_cast<complex<typename std::common_type<T, U>::type>>(rhs); | |
} | |
template <typename T> | |
complex<T> operator*(complex<T> lhs, T rhs) | |
{ | |
return lhs *= rhs; | |
} | |
template <typename T, typename U> | |
typename std::enable_if<std::is_integral<U>::value || std::is_floating_point<U>::value, | |
complex<typename std::common_type<T, U>::type>>::type | |
operator*(complex<T> lhs, U rhs) | |
{ | |
return static_cast<complex<typename std::common_type<T, U>::type>>(lhs) * | |
static_cast<typename std::common_type<T, U>::type>(rhs); | |
} | |
template <typename T> | |
complex<T> operator*(T lhs, complex<T> rhs) | |
{ | |
return complex<T>(lhs * rhs.m_real, lhs * rhs.m_imag); | |
} | |
template <typename T, typename U> | |
typename std::enable_if<std::is_integral<T>::value || std::is_floating_point<T>::value, | |
complex<typename std::common_type<T, U>::type>>::type | |
operator*(T lhs, complex<U> rhs) | |
{ | |
return static_cast<typename std::common_type<T, U>::type>(lhs) * | |
static_cast<complex<typename std::common_type<T, U>::type>>(rhs); | |
} | |
template <typename T> | |
complex<T> operator/(complex<T> lhs, complex<T> rhs) | |
{ | |
return lhs /= rhs; | |
} | |
template <typename T, typename U> | |
complex<typename std::common_type<T, U>::type> operator/(complex<T> lhs, complex<U> rhs) | |
{ | |
return static_cast<complex<typename std::common_type<T, U>::type>>(lhs) / | |
static_cast<complex<typename std::common_type<T, U>::type>>(rhs); | |
} | |
template <typename T> | |
complex<T> operator/(complex<T> lhs, T rhs) | |
{ | |
return lhs /= rhs; | |
} | |
template <typename T> | |
complex<T> operator/(T lhs, complex<T> rhs) | |
{ | |
T denom = rhs.m_real * rhs.m_real + rhs.m_imag * rhs.m_imag; | |
return complex<T>(lhs * rhs.m_real / denom, -lhs * rhs.m_imag / denom); | |
} | |
template <typename T> | |
std::ostream &operator<<(std::ostream &out, const complex<T> &val) | |
{ | |
return (out << "(" << val.m_real << " + " << val.m_imag << "j)"); | |
} | |
template <typename T> | |
complex<T> _i(); | |
template <> | |
inline complex<float> _i<float>() | |
{ | |
return complex<float>(0.0f, 1.0f); | |
} | |
template <> | |
inline complex<double> _i<double>() | |
{ | |
return complex<double>(0.0, 1.0); | |
} | |
template <typename T> | |
complex<T> conj(const complex<T> &z) | |
{ | |
return complex<T>(z.real(), -z.imag()); | |
} | |
} | |
namespace dynd { | |
template <typename T, typename U> | |
struct operator_if_only_lcast_arithmetic | |
: std::enable_if<!std::is_same<T, U>::value && !(std::is_arithmetic<T>::value && std::is_arithmetic<U>::value) && | |
is_lcast_arithmetic<T, U>::value && !is_rcast_arithmetic<T, U>::value, | |
U> { | |
}; | |
template <typename T, typename U> | |
struct operator_if_only_rcast_arithmetic | |
: std::enable_if<!std::is_same<T, U>::value && !(std::is_arithmetic<T>::value && std::is_arithmetic<U>::value) && | |
!is_lcast_arithmetic<T, U>::value && is_rcast_arithmetic<T, U>::value, | |
T> { | |
}; | |
template <typename... T> | |
struct make_void { | |
typedef void type; | |
}; | |
template <typename T, typename U> | |
struct operator_if_lrcast_arithmetic | |
: std::enable_if<!std::is_same<T, U>::value && !(std::is_arithmetic<T>::value && std::is_arithmetic<U>::value) && | |
is_lcast_arithmetic<T, U>::value && is_rcast_arithmetic<T, U>::value, | |
typename conditional_make<is_arithmetic<T>::value && is_arithmetic<U>::value, std::common_type, | |
make_void, T, U>::type::type> { | |
}; | |
template <typename T, typename U> | |
typename operator_if_only_rcast_arithmetic<T, U>::type operator+(T lhs, U rhs) | |
{ | |
return lhs + static_cast<T>(rhs); | |
} | |
template <typename T, typename U> | |
typename operator_if_only_lcast_arithmetic<T, U>::type operator+(T lhs, U rhs) | |
{ | |
return static_cast<U>(lhs) + rhs; | |
} | |
template <typename T, typename U> | |
typename operator_if_lrcast_arithmetic<T, U>::type operator+(T lhs, U rhs) | |
{ | |
return static_cast<typename std::common_type<T, U>::type>(lhs) + | |
static_cast<typename std::common_type<T, U>::type>(rhs); | |
} | |
template <typename T, typename U> | |
typename operator_if_only_rcast_arithmetic<T, U>::type operator/(T lhs, U rhs) | |
{ | |
return lhs / static_cast<T>(rhs); | |
} | |
template <typename T, typename U> | |
typename operator_if_only_lcast_arithmetic<T, U>::type operator/(T lhs, U rhs) | |
{ | |
return static_cast<U>(lhs) / rhs; | |
} | |
template <typename T, typename U> | |
typename operator_if_lrcast_arithmetic<T, U>::type operator/(T lhs, U rhs) | |
{ | |
return static_cast<typename std::common_type<T, U>::type>(lhs) / | |
static_cast<typename std::common_type<T, U>::type>(rhs); | |
} | |
template <typename T, typename U> | |
typename std::enable_if<is_mixed_arithmetic<T, U>::value, complex<typename std::common_type<T, U>::type>>::type | |
operator/(complex<T> lhs, U rhs) | |
{ | |
return static_cast<complex<typename std::common_type<T, U>::type>>(lhs) / | |
static_cast<typename std::common_type<T, U>::type>(rhs); | |
} | |
template <typename T, typename U> | |
typename std::enable_if<is_mixed_arithmetic<T, U>::value, complex<typename std::common_type<T, U>::type>>::type | |
operator/(T lhs, complex<U> rhs) | |
{ | |
return static_cast<typename std::common_type<T, U>::type>(lhs) / | |
static_cast<complex<typename std::common_type<T, U>::type>>(rhs); | |
} | |
template <typename T, typename U> | |
typename std::enable_if<std::is_floating_point<T>::value && is_integral<U>::value, T &>::type operator/=(T &lhs, U rhs) | |
{ | |
return lhs /= static_cast<T>(rhs); | |
} | |
} | |
namespace dynd { | |
using std::cos; | |
using std::sin; | |
using std::tan; | |
using std::atan2; | |
using std::cosh; | |
using std::sinh; | |
using std::exp; | |
using std::log; | |
using std::pow; | |
using std::sqrt; | |
using std::cbrt; | |
using std::hypot; | |
using std::abs; | |
using std::isfinite; | |
using std::isinf; | |
using std::isnan; | |
namespace ndt { | |
class type; | |
} | |
namespace nd { | |
class array; | |
class callable; | |
} | |
} | |
namespace dynd { | |
inline bool any_diagnostics_enabled() | |
{ | |
return ((0 != 0) || (0 != 0)); | |
} | |
inline std::string which_diagnostics_enabled() | |
{ | |
return ""; | |
} | |
} | |
namespace dynd { | |
template <typename T, typename DerivedType> | |
class storagebuf { | |
protected: | |
char *m_data; | |
intptr_t m_capacity; | |
intptr_t m_size; | |
char m_static_data[16 * 8]; | |
bool using_static_data() const { return m_data == &m_static_data[0]; } | |
public: | |
storagebuf() : m_data(m_static_data), m_capacity(sizeof(m_static_data)), m_size(0) { | |
set(m_static_data, 0, sizeof(m_static_data)); | |
} | |
~storagebuf() { | |
if (!using_static_data() && m_data != 0) { | |
free(m_data); | |
} | |
} | |
size_t size() const { return m_size; } | |
size_t capacity() const { return m_capacity; } | |
void reserve(intptr_t requested_capacity) { | |
if (m_capacity < requested_capacity) { | |
intptr_t grown_capacity = m_capacity * 3 / 2; | |
if (requested_capacity < grown_capacity) { | |
requested_capacity = grown_capacity; | |
} | |
char *new_data = reinterpret_cast<char *>(realloc(m_data, m_capacity, requested_capacity)); | |
if (new_data == 0) { | |
reinterpret_cast<DerivedType *>(this)->destroy(); | |
m_data = 0; | |
throw std::bad_alloc(); | |
} | |
set(reinterpret_cast<char *>(new_data) + m_capacity, 0, requested_capacity - m_capacity); | |
m_data = new_data; | |
m_capacity = requested_capacity; | |
} | |
} | |
void *alloc(size_t size) { return std::malloc(size); } | |
void *realloc(void *ptr, size_t old_size, size_t new_size) { | |
if (using_static_data()) { | |
void *new_data = alloc(new_size); | |
if (new_data != 0) { | |
copy(new_data, ptr, old_size); | |
} | |
return new_data; | |
} else { | |
return std::realloc(ptr, new_size); | |
} | |
} | |
void free(void *ptr) { | |
if (!using_static_data()) { | |
std::free(ptr); | |
} | |
} | |
void *copy(void *dst, const void *src, size_t size) { return std::memcpy(dst, src, size); } | |
void *set(void *dst, int value, size_t size) { return std::memset(dst, value, size); } | |
T *get() const { return reinterpret_cast<T *>(m_data); } | |
template <typename U> | |
U *get_at(size_t offset) { | |
return reinterpret_cast<U *>(m_data + offset); | |
} | |
static constexpr size_t aligned_size(size_t size) { | |
return (size + static_cast<size_t>(7)) & ~static_cast<size_t>(7); | |
} | |
template <typename KernelType, typename... ArgTypes> | |
void emplace_back(ArgTypes &&... args) { | |
static_assert(alignof(KernelType) <= 8, "kernel types require alignment to be at most 8 bytes"); | |
size_t offset = m_size; | |
m_size += aligned_size(sizeof(KernelType)); | |
reserve(m_size); | |
KernelType::init(this->get_at<KernelType>(offset), std::forward<ArgTypes>(args)...); | |
} | |
void emplace_back(size_t size) { | |
m_size += aligned_size(size); | |
reserve(m_size); | |
} | |
}; | |
} | |
namespace dynd { | |
static constexpr size_t aligned_size(size_t size) { return (size + static_cast<size_t>(7)) & ~static_cast<size_t>(7); } | |
typedef uint32_t kernel_request_t; | |
namespace nd { | |
class kernel_builder; | |
struct call_node { | |
typedef void (*instantiate_type_t)(call_node *node, kernel_builder *ckb, kernel_request_t kernreq, | |
const char *dst_arrmeta, size_t nsrc, const char *const *src_arrmeta); | |
typedef void (*destroy_type_t)(call_node *node); | |
destroy_type_t destroy; | |
instantiate_type_t instantiate; | |
size_t aligned_size; | |
call_node(instantiate_type_t instantiate) | |
: instantiate(instantiate), aligned_size(dynd::aligned_size(sizeof(call_node))) {} | |
call_node(instantiate_type_t instantiate, destroy_type_t destroy, size_t data_size) | |
: destroy(destroy), instantiate(instantiate), aligned_size(dynd::aligned_size(data_size)) {} | |
template <typename... ArgTypes> | |
static void init(call_node *self, ArgTypes &&... args) { | |
new (self) call_node(std::forward<ArgTypes>(args)...); | |
} | |
}; | |
} | |
} | |
namespace dynd { | |
namespace nd { | |
struct kernel_prefix; | |
class kernel_builder : public storagebuf<kernel_prefix, kernel_builder> { | |
call_node *m_call; | |
public: | |
kernel_builder(call_node *call = nullptr) : m_call(call) {} | |
__declspec(dllexport) void destroy(); | |
~kernel_builder() { destroy(); } | |
template <typename KernelType, typename... ArgTypes> | |
void emplace_back(ArgTypes &&... args) { | |
storagebuf<kernel_prefix, kernel_builder>::emplace_back<KernelType>(std::forward<ArgTypes>(args)...); | |
m_call = reinterpret_cast<call_node *>(reinterpret_cast<char *>(m_call) + m_call->aligned_size); | |
} | |
void emplace_back(size_t size) { storagebuf<kernel_prefix, kernel_builder>::emplace_back(size); } | |
void operator()(kernel_request_t kr, const char *res_metadata, size_t narg, const char *const *arg_metadata) { | |
m_call->instantiate(m_call, this, kr, res_metadata, narg, arg_metadata); | |
} | |
}; | |
} | |
} | |
namespace dynd { | |
typedef void (*kernel_call_t)(nd::kernel_prefix *self, const nd::array *dst, const nd::array *src); | |
typedef void (*kernel_single_t)(nd::kernel_prefix *self, char *dst, char *const *src); | |
typedef void (*kernel_strided_t)(nd::kernel_prefix *self, char *dst, intptr_t dst_stride, char *const *src, | |
const intptr_t *src_stride, size_t count); | |
enum { | |
kernel_request_host = 0x00000000, | |
kernel_request_call = 0x00000000, | |
kernel_request_single = 0x00000001, | |
kernel_request_strided = 0x00000003, | |
kernel_request_data_only = 0x00000001 | |
}; | |
typedef uint32_t kernel_request_t; | |
namespace nd { | |
struct __declspec(dllexport) kernel_prefix { | |
typedef void (*destructor_fn_t)(kernel_prefix *); | |
void (*destructor)(kernel_prefix *self); | |
void *function; | |
template <typename T> | |
T get_function() const | |
{ | |
return reinterpret_cast<T>(function); | |
} | |
void destroy() | |
{ | |
if (destructor != 0) { | |
destructor(this); | |
} | |
} | |
void single(char *dst, char *const *src) { (*reinterpret_cast<kernel_single_t>(function))(this, dst, src); } | |
void strided(char *dst, intptr_t dst_stride, char *const *src, const intptr_t *src_stride, size_t count) | |
{ | |
(*reinterpret_cast<kernel_strided_t>(function))(this, dst, dst_stride, src, src_stride, count); | |
} | |
kernel_prefix *get_child(intptr_t offset) | |
{ | |
return reinterpret_cast<kernel_prefix *>(reinterpret_cast<char *>(this) + kernel_builder::aligned_size(offset)); | |
} | |
size_t *get_offsets() { return reinterpret_cast<size_t *>(this + 1); } | |
static kernel_prefix *init(kernel_prefix *self, void *func) | |
{ | |
self->function = func; | |
self->destructor = 0; | |
return self; | |
} | |
}; | |
} | |
} | |
namespace dynd { | |
class __declspec(dllimport) bytes { | |
protected: | |
char *m_data; | |
size_t m_size; | |
public: | |
bytes() : m_data(0), m_size(0) {} | |
bytes(const char *data, size_t size) : m_data(new char[size]), m_size(size) { memcpy(m_data, data, size); } | |
template <size_t N> | |
bytes(const char (&data)[N]) : bytes(data, N - 1) | |
{ | |
} | |
bytes(const bytes &other) : m_data(new char[other.m_size]), m_size(other.m_size) | |
{ | |
memcpy(m_data, other.m_data, other.m_size); | |
} | |
~bytes() { delete[] m_data; } | |
bool empty() const { return m_size == 0; } | |
char *data() { return m_data; } | |
const char *data() const { return m_data; } | |
size_t size() const { return m_size; } | |
bytes &append(const char *data, size_t size) | |
{ | |
char *old_data = m_data; | |
size_t old_size = m_size; | |
m_data = new char[m_size + size]; | |
m_size += size; | |
memcpy(m_data, old_data, old_size); | |
memcpy(m_data + old_size, data, size); | |
delete[] old_data; | |
return *this; | |
} | |
bytes &assign(const char *data, size_t size) | |
{ | |
if (size != m_size) { | |
delete[] m_data; | |
m_data = new char[size]; | |
m_size = size; | |
} | |
memcpy(m_data, data, m_size); | |
return *this; | |
} | |
void clear() | |
{ | |
if (m_size != 0) { | |
delete[] m_data; | |
m_data = nullptr; | |
m_size = 0; | |
} | |
} | |
void resize(size_t size) | |
{ | |
if (size != m_size) { | |
char *data = new char[size]; | |
memcpy(data, m_data, std::min(size, m_size)); | |
delete[] m_data; | |
m_data = data; | |
m_size = size; | |
} | |
} | |
char *begin() { return m_data; } | |
const char *begin() const { return m_data; } | |
char *end() { return m_data + m_size; } | |
const char *end() const { return m_data + m_size; } | |
bytes &operator=(const bytes &rhs) { return assign(rhs.m_data, rhs.m_size); } | |
bool operator==(const bytes &rhs) const | |
{ | |
return m_size == rhs.m_size && std::memcmp(m_data, rhs.m_data, m_size) == 0; | |
} | |
bool operator!=(const bytes &rhs) const | |
{ | |
return m_size != rhs.m_size || std::memcmp(m_data, rhs.m_data, m_size) != 0; | |
} | |
const bytes operator+(const bytes &rhs) | |
{ | |
bytes result; | |
result.resize(size() + rhs.size()); | |
std::memcpy(result.begin(), begin(), size()); | |
std::memcpy(result.begin() + size(), rhs.begin(), rhs.size()); | |
return result; | |
} | |
bytes &operator+=(const bytes &rhs) | |
{ | |
size_t orig_size = size(); | |
resize(size() + rhs.size()); | |
std::memcpy(begin() + orig_size, rhs.begin(), rhs.size()); | |
return *this; | |
} | |
}; | |
namespace detail { | |
class value_bytes { | |
protected: | |
char *m_data; | |
size_t m_size; | |
value_bytes(char *data, size_t size) : m_data(data), m_size(size) {} | |
public: | |
value_bytes() : m_data(0), m_size(0) {} | |
value_bytes(const value_bytes &other) : m_data(new char[other.m_size]), m_size(other.m_size) | |
{ | |
memcpy(m_data, other.m_data, m_size); | |
} | |
~value_bytes() { delete[] m_data; } | |
operator char *() { return m_data; } | |
operator const char *() const { return m_data; } | |
value_bytes &operator=(const value_bytes &rhs) | |
{ | |
memcpy(m_data, rhs.m_data, m_size); | |
return *this; | |
} | |
}; | |
} | |
class strided_iterator : public detail::value_bytes, | |
public std::iterator<std::random_access_iterator_tag, detail::value_bytes> { | |
intptr_t m_stride; | |
public: | |
strided_iterator() : m_stride(0){}; | |
strided_iterator(char *data, size_t size, intptr_t stride) : value_bytes(data, size), m_stride(stride) {} | |
strided_iterator(const strided_iterator &other) : value_bytes(other.m_data, other.m_size), m_stride(other.m_stride) {} | |
~strided_iterator() | |
{ | |
m_data = 0; | |
m_size = 0; | |
} | |
intptr_t stride() const { return m_stride; } | |
value_bytes &operator*() { return *this; } | |
strided_iterator &operator++() | |
{ | |
m_data += m_stride; | |
return *this; | |
} | |
strided_iterator operator++(int) | |
{ | |
strided_iterator tmp(*this); | |
operator++(); | |
return tmp; | |
} | |
strided_iterator &operator+=(std::ptrdiff_t i) | |
{ | |
m_data += i * m_stride; | |
return *this; | |
} | |
strided_iterator &operator--() | |
{ | |
m_data -= m_stride; | |
return *this; | |
} | |
strided_iterator operator--(int) | |
{ | |
strided_iterator tmp(*this); | |
operator--(); | |
return tmp; | |
} | |
strided_iterator &operator-=(std::ptrdiff_t i) | |
{ | |
m_data -= i * m_stride; | |
return *this; | |
} | |
bool operator<(const strided_iterator &rhs) const { return m_data < rhs.m_data; } | |
bool operator<=(const strided_iterator &rhs) const { return m_data <= rhs.m_data; } | |
bool operator==(const strided_iterator &rhs) const { return m_data == rhs.m_data; } | |
bool operator!=(const strided_iterator &rhs) const { return m_data != rhs.m_data; } | |
bool operator>=(const strided_iterator &rhs) const { return m_data >= rhs.m_data; } | |
bool operator>(const strided_iterator &rhs) const { return m_data > rhs.m_data; } | |
std::ptrdiff_t operator-(strided_iterator rhs) { return (m_data - rhs.m_data) / m_stride; } | |
strided_iterator &operator=(const strided_iterator &other) | |
{ | |
m_data = other.m_data; | |
m_size = other.m_size; | |
return *this; | |
} | |
friend strided_iterator operator+(strided_iterator lhs, std::ptrdiff_t rhs); | |
friend strided_iterator operator-(strided_iterator lhs, std::ptrdiff_t rhs); | |
}; | |
inline strided_iterator operator+(strided_iterator lhs, std::ptrdiff_t rhs) | |
{ | |
return strided_iterator(lhs.m_data + rhs * lhs.m_stride, lhs.m_size, lhs.m_stride); | |
} | |
inline strided_iterator operator-(strided_iterator lhs, std::ptrdiff_t rhs) | |
{ | |
return strided_iterator(lhs.m_data - rhs * lhs.m_stride, lhs.m_size, lhs.m_stride); | |
} | |
} | |
namespace dynd { | |
class irange { | |
intptr_t m_start, m_finish, m_step; | |
public: | |
inline irange() | |
: m_start(std::numeric_limits<intptr_t>::min()), m_finish(std::numeric_limits<intptr_t>::max()), m_step(1) | |
{ | |
} | |
inline irange(intptr_t idx) : m_start(idx), m_finish(idx), m_step(0) {} | |
inline irange(intptr_t start, intptr_t finish, intptr_t step = 1) | |
: m_start(start), m_finish(finish), m_step(step) | |
{ | |
} | |
inline const intptr_t &start() const { return m_start; } | |
inline const intptr_t &finish() const { return m_finish; } | |
inline const intptr_t &step() const { return m_step; } | |
inline void set_start(intptr_t value) { m_start = value; } | |
inline void set_finish(intptr_t value) { m_finish = value; } | |
inline void set_step(intptr_t value) { m_step = value; } | |
inline bool is_nop() const | |
{ | |
return m_start == std::numeric_limits<intptr_t>::min() && m_finish == std::numeric_limits<intptr_t>::max() && | |
m_step == 1; | |
} | |
irange by(intptr_t step) const { return irange(m_start, m_finish, step); } | |
irange operator<(intptr_t finish) const { return irange(m_start, finish, m_step); } | |
irange operator<=(intptr_t last) const | |
{ | |
return irange(m_start, (last != -1) ? (last + 1) : std::numeric_limits<intptr_t>::max(), m_step); | |
} | |
irange operator>(intptr_t finish) const { return irange(m_start, finish, m_step); } | |
irange operator>=(intptr_t last) const | |
{ | |
return irange(m_start, (last != 0) ? (last - 1) : std::numeric_limits<intptr_t>::max(), m_step); | |
} | |
friend irange operator<(intptr_t start_minus_one, const irange &i); | |
friend irange operator<=(intptr_t start, const irange &i); | |
friend irange operator>(intptr_t start_plus_one, const irange &i); | |
friend irange operator>=(intptr_t start, const irange &i); | |
}; | |
inline irange operator<(intptr_t start_minus_one, const irange &i) | |
{ | |
return irange(start_minus_one + 1, i.m_finish, i.m_step); | |
} | |
inline irange operator<=(intptr_t start, const irange &i) { return irange(start, i.m_finish, i.m_step); } | |
inline irange operator>(intptr_t start_plus_one, const irange &i) | |
{ | |
return irange(start_plus_one - 1, i.m_finish, i.m_step); | |
} | |
inline irange operator>=(intptr_t start, const irange &i) { return irange(start, i.m_finish, i.m_step); } | |
} | |
namespace dynd { | |
namespace eval { | |
struct __declspec(dllimport) eval_context { | |
assign_error_mode errmode; | |
eval_context() : errmode(assign_error_fractional) {} | |
}; | |
extern __declspec(dllimport) eval_context default_eval_context; | |
} | |
} | |
namespace dynd { | |
enum memory_block_type_t { | |
array_memory_block_type, | |
external_memory_block_type, | |
fixed_size_pod_memory_block_type, | |
pod_memory_block_type, | |
zeroinit_memory_block_type, | |
objectarray_memory_block_type, | |
memmap_memory_block_type | |
}; | |
__declspec(dllimport) std::ostream &operator<<(std::ostream &o, memory_block_type_t mbt); | |
struct __declspec(dllimport) memory_block_data { | |
struct __declspec(dllimport) api { | |
char *(*allocate)(memory_block_data *self, size_t count); | |
char *(*resize)(memory_block_data *self, char *previous_allocated, size_t count); | |
void (*finalize)(memory_block_data *self); | |
void (*reset)(memory_block_data *self); | |
}; | |
std::atomic_long m_use_count; | |
uint32_t m_type; | |
explicit memory_block_data(long use_count, memory_block_type_t type) : m_use_count(use_count), m_type(type) | |
{ | |
} | |
char *alloc(size_t count) { return get_api()->allocate(this, count); } | |
char *resize(char *previous_allocated, size_t count) { return get_api()->resize(this, previous_allocated, count); } | |
void finalize() { get_api()->finalize(this); } | |
void reset() { get_api()->reset(this); } | |
private: | |
api *get_api(); | |
}; | |
namespace detail { | |
__declspec(dllimport) void memory_block_free(memory_block_data *memblock); | |
} | |
inline long intrusive_ptr_use_count(memory_block_data *ptr) { return ptr->m_use_count; } | |
inline void intrusive_ptr_retain(memory_block_data *ptr) { ++ptr->m_use_count; } | |
inline void intrusive_ptr_release(memory_block_data *ptr) | |
{ | |
if (--ptr->m_use_count == 0) { | |
detail::memory_block_free(ptr); | |
} | |
} | |
__declspec(dllimport) void memory_block_debug_print(const memory_block_data *memblock, std::ostream &o, | |
const std::string &indent = ""); | |
} | |
namespace dynd { | |
class bytes; | |
class string; | |
enum type_id_t { | |
uninitialized_id, | |
any_kind_id, | |
scalar_kind_id, | |
bool_kind_id, | |
bool_id, | |
int_kind_id, | |
int8_id, | |
int16_id, | |
int32_id, | |
int64_id, | |
int128_id, | |
uint_kind_id, | |
uint8_id, | |
uint16_id, | |
uint32_id, | |
uint64_id, | |
uint128_id, | |
float_kind_id, | |
float16_id, | |
float32_id, | |
float64_id, | |
float128_id, | |
complex_kind_id, | |
complex_float32_id, | |
complex_float64_id, | |
void_id, | |
dim_kind_id, | |
bytes_kind_id, | |
fixed_bytes_id, | |
bytes_id, | |
string_kind_id, | |
fixed_string_id, | |
char_id, | |
string_id, | |
tuple_id, | |
struct_id, | |
fixed_dim_kind_id, | |
fixed_dim_id, | |
var_dim_id, | |
categorical_id, | |
option_id, | |
pointer_id, | |
memory_id, | |
type_id, | |
array_id, | |
callable_id, | |
expr_kind_id, | |
adapt_id, | |
expr_id, | |
cuda_host_id, | |
cuda_device_id, | |
kind_sym_id, | |
int_sym_id, | |
typevar_id, | |
typevar_dim_id, | |
typevar_constructed_id, | |
pow_dimsym_id, | |
ellipsis_dim_id, | |
dim_fragment_id, | |
}; | |
template <type_id_t Value> | |
using id_constant = std::integral_constant<type_id_t, Value>; | |
template <type_id_t... I> | |
using type_id_sequence = integer_sequence<type_id_t, I...>; | |
typedef type_id_sequence<int8_id, int16_id, int32_id, int64_id, int128_id> int_ids; | |
typedef type_id_sequence<bool_id, uint8_id, uint16_id, uint32_id, uint64_id, uint128_id> uint_ids; | |
typedef type_id_sequence<float16_id, float32_id, float64_id, float128_id> float_ids; | |
typedef type_id_sequence<complex_float32_id, complex_float64_id> complex_ids; | |
typedef join<int_ids, uint_ids>::type integral_ids; | |
typedef join<integral_ids, join<float_ids, complex_ids>::type>::type arithmetic_ids; | |
typedef type_id_sequence<fixed_dim_id, var_dim_id> dim_ids; | |
enum type_flags_t { | |
type_flag_none = 0x00000000, | |
type_flag_zeroinit = 0x00000001, | |
type_flag_construct = 0x00000002, | |
type_flag_blockref = 0x00000004, | |
type_flag_destructor = 0x00000008, | |
type_flag_not_host_readable = 0x00000010, | |
type_flag_symbolic = 0x00000020, | |
type_flag_variadic = 0x00000040, | |
type_flag_indexable = 0x00000080, | |
}; | |
enum axis_order_classification_t { | |
axis_order_none, | |
axis_order_neither, | |
axis_order_f, | |
axis_order_c | |
}; | |
enum { | |
type_flags_operand_inherited = type_flag_zeroinit | type_flag_blockref | type_flag_construct | type_flag_destructor | | |
type_flag_not_host_readable | type_flag_symbolic, | |
type_flags_value_inherited = type_flag_symbolic | type_flag_variadic | |
}; | |
__declspec(dllimport) std::ostream &operator<<(std::ostream &o, type_id_t tid); | |
namespace ndt { | |
class base_type; | |
} | |
inline bool is_builtin_type(const ndt::base_type *dt) | |
{ | |
switch (reinterpret_cast<uintptr_t>(dt)) { | |
case uninitialized_id: | |
case bool_id: | |
case int8_id: | |
case int16_id: | |
case int32_id: | |
case int64_id: | |
case int128_id: | |
case uint8_id: | |
case uint16_id: | |
case uint32_id: | |
case uint64_id: | |
case uint128_id: | |
case float16_id: | |
case float32_id: | |
case float64_id: | |
case float128_id: | |
case complex_float32_id: | |
case complex_float64_id: | |
case void_id: | |
return true; | |
default: | |
return false; | |
} | |
} | |
namespace detail { | |
template <int I> | |
struct log2_x; | |
template <> | |
struct log2_x<1> { | |
enum { value = 0 }; | |
}; | |
template <> | |
struct log2_x<2> { | |
enum { value = 1 }; | |
}; | |
template <> | |
struct log2_x<4> { | |
enum { value = 2 }; | |
}; | |
template <> | |
struct log2_x<8> { | |
enum { value = 3 }; | |
}; | |
} | |
template <typename T> | |
struct type_id_of; | |
template <typename T> | |
struct type_id_of<const T> { | |
static const type_id_t value = type_id_of<T>::value; | |
}; | |
template <> | |
struct type_id_of<bool1> { | |
static const type_id_t value = bool_id; | |
}; | |
template <> | |
struct type_id_of<char> { | |
static const type_id_t value = ((char)-1) < 0 ? int8_id : uint8_id; | |
}; | |
template <> | |
struct type_id_of<signed char> { | |
static const type_id_t value = int8_id; | |
}; | |
template <> | |
struct type_id_of<short> { | |
static const type_id_t value = int16_id; | |
}; | |
template <> | |
struct type_id_of<int> { | |
static const type_id_t value = int32_id; | |
}; | |
template <> | |
struct type_id_of<long> { | |
static const type_id_t value = static_cast<type_id_t>(int8_id + detail::log2_x<sizeof(long)>::value); | |
}; | |
template <> | |
struct type_id_of<long long> { | |
static const type_id_t value = int64_id; | |
}; | |
template <> | |
struct type_id_of<int128> { | |
static const type_id_t value = int128_id; | |
}; | |
template <> | |
struct type_id_of<uint8_t> { | |
static const type_id_t value = uint8_id; | |
}; | |
template <> | |
struct type_id_of<uint16_t> { | |
static const type_id_t value = uint16_id; | |
}; | |
template <> | |
struct type_id_of<unsigned int> { | |
static const type_id_t value = uint32_id; | |
}; | |
template <> | |
struct type_id_of<unsigned long> { | |
static const type_id_t value = static_cast<type_id_t>(uint8_id + detail::log2_x<sizeof(unsigned long)>::value); | |
}; | |
template <> | |
struct type_id_of<unsigned long long> { | |
static const type_id_t value = uint64_id; | |
}; | |
template <> | |
struct type_id_of<uint128> { | |
static const type_id_t value = uint128_id; | |
}; | |
template <> | |
struct type_id_of<float16> { | |
static const type_id_t value = float16_id; | |
}; | |
template <> | |
struct type_id_of<float32> { | |
static const type_id_t value = float32_id; | |
}; | |
template <> | |
struct type_id_of<float64> { | |
static const type_id_t value = float64_id; | |
}; | |
template <> | |
struct type_id_of<float128> { | |
static const type_id_t value = float128_id; | |
}; | |
template <> | |
struct type_id_of<complex64> { | |
static const type_id_t value = complex_float32_id; | |
}; | |
template <> | |
struct type_id_of<complex128> { | |
static const type_id_t value = complex_float64_id; | |
}; | |
template <> | |
struct type_id_of<void> { | |
static const type_id_t value = void_id; | |
}; | |
template <> | |
struct type_id_of<ndt::type> { | |
static const type_id_t value = type_id; | |
}; | |
template <> | |
struct type_id_of<std::complex<float>> { | |
static const type_id_t value = complex_float32_id; | |
}; | |
template <> | |
struct type_id_of<std::complex<double>> { | |
static const type_id_t value = complex_float64_id; | |
}; | |
template <type_id_t TypeID> | |
struct type_of; | |
template <> | |
struct type_of<bool_id> { | |
typedef bool1 type; | |
}; | |
template <> | |
struct type_of<int8_id> { | |
typedef int8 type; | |
}; | |
template <> | |
struct type_of<int16_id> { | |
typedef int16 type; | |
}; | |
template <> | |
struct type_of<int32_id> { | |
typedef int32 type; | |
}; | |
template <> | |
struct type_of<int64_id> { | |
typedef int64 type; | |
}; | |
template <> | |
struct type_of<int128_id> { | |
typedef int128 type; | |
}; | |
template <> | |
struct type_of<uint8_id> { | |
typedef uint8 type; | |
}; | |
template <> | |
struct type_of<uint16_id> { | |
typedef uint16 type; | |
}; | |
template <> | |
struct type_of<uint32_id> { | |
typedef uint32 type; | |
}; | |
template <> | |
struct type_of<uint64_id> { | |
typedef uint64 type; | |
}; | |
template <> | |
struct type_of<uint128_id> { | |
typedef uint128 type; | |
}; | |
template <> | |
struct type_of<float16_id> { | |
typedef float16 type; | |
}; | |
template <> | |
struct type_of<float32_id> { | |
typedef float32 type; | |
}; | |
template <> | |
struct type_of<float64_id> { | |
typedef float64 type; | |
}; | |
template <> | |
struct type_of<float128_id> { | |
typedef float128 type; | |
}; | |
template <> | |
struct type_of<complex_float32_id> { | |
typedef complex64 type; | |
}; | |
template <> | |
struct type_of<complex_float64_id> { | |
typedef complex128 type; | |
}; | |
template <> | |
struct type_of<bytes_id> { | |
typedef bytes type; | |
}; | |
template <> | |
struct type_of<string_id> { | |
typedef string type; | |
}; | |
template <> | |
struct type_of<type_id> { | |
typedef ndt::type type; | |
}; | |
template <type_id_t ID> | |
struct base_id_of; | |
template <> | |
struct base_id_of<scalar_kind_id> : id_constant<any_kind_id> { | |
}; | |
template <> | |
struct base_id_of<bool_kind_id> : id_constant<scalar_kind_id> { | |
}; | |
template <> | |
struct base_id_of<bool_id> : id_constant<bool_kind_id> { | |
}; | |
template <> | |
struct base_id_of<int_kind_id> : id_constant<scalar_kind_id> { | |
}; | |
template <> | |
struct base_id_of<int8_id> : id_constant<int_kind_id> { | |
}; | |
template <> | |
struct base_id_of<int16_id> : id_constant<int_kind_id> { | |
}; | |
template <> | |
struct base_id_of<int32_id> : id_constant<int_kind_id> { | |
}; | |
template <> | |
struct base_id_of<int64_id> : id_constant<int_kind_id> { | |
}; | |
template <> | |
struct base_id_of<int128_id> : id_constant<int_kind_id> { | |
}; | |
template <> | |
struct base_id_of<uint_kind_id> : id_constant<scalar_kind_id> { | |
}; | |
template <> | |
struct base_id_of<uint8_id> : id_constant<uint_kind_id> { | |
}; | |
template <> | |
struct base_id_of<uint16_id> : id_constant<uint_kind_id> { | |
}; | |
template <> | |
struct base_id_of<uint32_id> : id_constant<uint_kind_id> { | |
}; | |
template <> | |
struct base_id_of<uint64_id> : id_constant<uint_kind_id> { | |
}; | |
template <> | |
struct base_id_of<uint128_id> : id_constant<uint_kind_id> { | |
}; | |
template <> | |
struct base_id_of<float_kind_id> : id_constant<scalar_kind_id> { | |
}; | |
template <> | |
struct base_id_of<float16_id> : id_constant<float_kind_id> { | |
}; | |
template <> | |
struct base_id_of<float32_id> : id_constant<float_kind_id> { | |
}; | |
template <> | |
struct base_id_of<float64_id> : id_constant<float_kind_id> { | |
}; | |
template <> | |
struct base_id_of<float128_id> : id_constant<float_kind_id> { | |
}; | |
template <> | |
struct base_id_of<complex_kind_id> : id_constant<scalar_kind_id> { | |
}; | |
template <> | |
struct base_id_of<complex_float32_id> : id_constant<complex_kind_id> { | |
}; | |
template <> | |
struct base_id_of<complex_float64_id> : id_constant<complex_kind_id> { | |
}; | |
template <> | |
struct base_id_of<void_id> : id_constant<any_kind_id> { | |
}; | |
template <> | |
struct base_id_of<bytes_kind_id> : id_constant<scalar_kind_id> { | |
}; | |
template <> | |
struct base_id_of<fixed_bytes_id> : id_constant<bytes_kind_id> { | |
}; | |
template <> | |
struct base_id_of<bytes_id> : id_constant<bytes_kind_id> { | |
}; | |
template <> | |
struct base_id_of<string_kind_id> : id_constant<scalar_kind_id> { | |
}; | |
template <> | |
struct base_id_of<char_id> : id_constant<string_kind_id> { | |
}; | |
template <> | |
struct base_id_of<fixed_string_id> : id_constant<string_kind_id> { | |
}; | |
template <> | |
struct base_id_of<string_id> : id_constant<string_kind_id> { | |
}; | |
template <> | |
struct base_id_of<fixed_dim_kind_id> : id_constant<dim_kind_id> { | |
}; | |
template <> | |
struct base_id_of<fixed_dim_id> : id_constant<fixed_dim_kind_id> { | |
}; | |
template <> | |
struct base_id_of<var_dim_id> : id_constant<dim_kind_id> { | |
}; | |
template <> | |
struct base_id_of<pointer_id> : id_constant<any_kind_id> { | |
}; | |
template <> | |
struct base_id_of<memory_id> : id_constant<any_kind_id> { | |
}; | |
template <> | |
struct base_id_of<expr_kind_id> : id_constant<any_kind_id> { | |
}; | |
template <> | |
struct base_id_of<adapt_id> : id_constant<expr_kind_id> { | |
}; | |
template <> | |
struct base_id_of<tuple_id> : id_constant<scalar_kind_id> { | |
}; | |
template <> | |
struct base_id_of<struct_id> : id_constant<tuple_id> { | |
}; | |
template <> | |
struct base_id_of<option_id> : id_constant<any_kind_id> { | |
}; | |
template <> | |
struct base_id_of<categorical_id> : id_constant<any_kind_id> { | |
}; | |
template <> | |
struct base_id_of<expr_id> : id_constant<any_kind_id> { | |
}; | |
template <> | |
struct base_id_of<type_id> : id_constant<scalar_kind_id> { | |
}; | |
template <> | |
struct base_id_of<callable_id> : id_constant<scalar_kind_id> { | |
}; | |
template <> | |
struct base_id_of<array_id> : id_constant<scalar_kind_id> { | |
}; | |
template <> | |
struct base_id_of<dim_kind_id> : id_constant<any_kind_id> { | |
}; | |
template <> | |
struct base_id_of<typevar_id> : id_constant<scalar_kind_id> { | |
}; | |
namespace detail { | |
template <type_id_t DstTypeID, type_id_t DstBaseID, type_id_t SrcTypeID, type_id_t SrcBaseID> | |
struct is_lossless_assignable { | |
static const bool value = false; | |
}; | |
template <type_id_t DstTypeID, type_id_t SrcTypeID> | |
struct is_lossless_assignable<DstTypeID, float_kind_id, SrcTypeID, int_kind_id> { | |
static const bool value = true; | |
}; | |
template <type_id_t DstTypeID, type_id_t SrcTypeID> | |
struct is_lossless_assignable<DstTypeID, float_kind_id, SrcTypeID, uint_kind_id> { | |
static const bool value = true; | |
}; | |
template <type_id_t DstTypeID, type_id_t SrcTypeID> | |
struct is_lossless_assignable<DstTypeID, complex_kind_id, SrcTypeID, bool_kind_id> { | |
static const bool value = true; | |
}; | |
template <type_id_t DstTypeID, type_id_t SrcTypeID> | |
struct is_lossless_assignable<DstTypeID, complex_kind_id, SrcTypeID, int_kind_id> { | |
static const bool value = false; | |
}; | |
template <type_id_t DstTypeID, type_id_t SrcTypeID> | |
struct is_lossless_assignable<DstTypeID, complex_kind_id, SrcTypeID, uint_kind_id> { | |
static const bool value = false; | |
}; | |
template <type_id_t DstTypeID, type_id_t SrcTypeID> | |
struct is_lossless_assignable<DstTypeID, complex_kind_id, SrcTypeID, float_kind_id> { | |
static const bool value = (sizeof(typename type_of<DstTypeID>::type) / 2) > | |
sizeof(typename type_of<SrcTypeID>::type); | |
}; | |
template <type_id_t DstTypeID, type_id_t SrcTypeID, type_id_t BaseTypeID> | |
struct is_lossless_assignable<DstTypeID, BaseTypeID, SrcTypeID, BaseTypeID> { | |
static const bool value = sizeof(typename type_of<DstTypeID>::type) > sizeof(typename type_of<SrcTypeID>::type); | |
}; | |
} | |
template <type_id_t DstTypeID, type_id_t Src0TypeID> | |
struct is_lossless_assignable : detail::is_lossless_assignable<DstTypeID, base_id_of<DstTypeID>::value, Src0TypeID, | |
base_id_of<Src0TypeID>::value> { | |
}; | |
template <typename T> | |
struct is_dynd_scalar { | |
enum { value = false }; | |
}; | |
template <> | |
struct is_dynd_scalar<bool> { | |
enum { value = true }; | |
}; | |
template <> | |
struct is_dynd_scalar<bool1> { | |
enum { value = true }; | |
}; | |
template <> | |
struct is_dynd_scalar<char> { | |
enum { value = true }; | |
}; | |
template <> | |
struct is_dynd_scalar<signed char> { | |
enum { value = true }; | |
}; | |
template <> | |
struct is_dynd_scalar<short> { | |
enum { value = true }; | |
}; | |
template <> | |
struct is_dynd_scalar<int> { | |
enum { value = true }; | |
}; | |
template <> | |
struct is_dynd_scalar<long> { | |
enum { value = true }; | |
}; | |
template <> | |
struct is_dynd_scalar<long long> { | |
enum { value = true }; | |
}; | |
template <> | |
struct is_dynd_scalar<int128> { | |
enum { value = true }; | |
}; | |
template <> | |
struct is_dynd_scalar<unsigned char> { | |
enum { value = true }; | |
}; | |
template <> | |
struct is_dynd_scalar<unsigned short> { | |
enum { value = true }; | |
}; | |
template <> | |
struct is_dynd_scalar<unsigned int> { | |
enum { value = true }; | |
}; | |
template <> | |
struct is_dynd_scalar<unsigned long> { | |
enum { value = true }; | |
}; | |
template <> | |
struct is_dynd_scalar<unsigned long long> { | |
enum { value = true }; | |
}; | |
template <> | |
struct is_dynd_scalar<uint128> { | |
enum { value = true }; | |
}; | |
template <> | |
struct is_dynd_scalar<float16> { | |
enum { value = true }; | |
}; | |
template <> | |
struct is_dynd_scalar<float32> { | |
enum { value = true }; | |
}; | |
template <> | |
struct is_dynd_scalar<float64> { | |
enum { value = true }; | |
}; | |
template <> | |
struct is_dynd_scalar<float128> { | |
enum { value = true }; | |
}; | |
template <> | |
struct is_dynd_scalar<complex64> { | |
enum { value = true }; | |
}; | |
template <> | |
struct is_dynd_scalar<complex128> { | |
enum { value = true }; | |
}; | |
template <> | |
struct is_dynd_scalar<std::complex<float>> { | |
enum { value = true }; | |
}; | |
template <> | |
struct is_dynd_scalar<std::complex<double>> { | |
enum { value = true }; | |
}; | |
template <typename T> | |
struct property_type_id_of { | |
static const type_id_t value = type_id_of<T>::value; | |
}; | |
template <> | |
struct property_type_id_of<std::string> { | |
static const type_id_t value = string_id; | |
}; | |
} | |
namespace dynd { | |
namespace ndt { | |
class type; | |
} | |
struct iterdata_common; | |
typedef void (*foreach_fn_t)(const ndt::type &dt, const char *arrmeta, char *data, void *callback_data); | |
typedef char *(*iterdata_increment_fn_t)(iterdata_common *iterdata, intptr_t level); | |
typedef char *(*iterdata_advance_fn_t)(iterdata_common *iterdata, intptr_t level, intptr_t i); | |
typedef char *(*iterdata_reset_fn_t)(iterdata_common *iterdata, char *data, intptr_t ndim); | |
typedef void (*type_transform_fn_t)(const ndt::type &dt, intptr_t arrmeta_offset, void *extra, | |
ndt::type &out_transformed_type, bool &out_was_transformed); | |
struct __declspec(dllimport) iterdata_common { | |
iterdata_increment_fn_t incr; | |
iterdata_advance_fn_t adv; | |
iterdata_reset_fn_t reset; | |
}; | |
namespace ndt { | |
class __declspec(dllimport) base_type { | |
mutable std::atomic_long m_use_count; | |
protected: | |
type_id_t m_id; | |
size_t m_metadata_size; | |
size_t m_data_size; | |
size_t m_data_alignment; | |
uint32_t flags; | |
intptr_t m_ndim; | |
intptr_t m_fixed_ndim; | |
public: | |
base_type(type_id_t id, size_t data_size, size_t data_alignment, uint32_t flags, size_t arrmeta_size, size_t ndim, | |
size_t strided_ndim) | |
: m_use_count(1), m_id(id), m_metadata_size(arrmeta_size), m_data_size(data_size), | |
m_data_alignment(data_alignment), flags(flags), m_ndim(ndim), m_fixed_ndim(strided_ndim) | |
{ | |
} | |
virtual ~base_type(); | |
int32_t get_use_count() const { return m_use_count; } | |
type_id_t get_id() const { return m_id; } | |
size_t get_arrmeta_size() const { return m_metadata_size; } | |
size_t get_data_size() const { return m_data_size; } | |
size_t get_data_alignment() const { return m_data_alignment; } | |
intptr_t get_ndim() const { return m_ndim; } | |
intptr_t get_strided_ndim() const { return m_fixed_ndim; } | |
uint32_t get_flags() const { return flags; } | |
virtual size_t get_default_data_size() const; | |
virtual void print_type(std::ostream &o) const = 0; | |
virtual void print_data(std::ostream &o, const char *arrmeta, const char *data) const; | |
inline bool is_indexable() const { return (flags & type_flag_indexable) != 0; } | |
bool is_scalar() const { return m_ndim == 0 && (flags & type_flag_variadic) == 0; } | |
virtual bool is_type_subarray(const ndt::type &subarray_tp) const; | |
virtual bool is_expression() const; | |
virtual bool is_unique_data_owner(const char *arrmeta) const; | |
virtual void transform_child_types(type_transform_fn_t transform_fn, intptr_t arrmeta_offset, void *extra, | |
ndt::type &out_transformed_type, bool &out_was_transformed) const; | |
virtual ndt::type get_canonical_type() const; | |
virtual void set_from_utf8_string(const char *arrmeta, char *data, const char *utf8_begin, const char *utf8_end, | |
const eval::eval_context *ectx) const; | |
inline void set_from_utf8_string(const char *arrmeta, char *data, const std::string &utf8_str, | |
const eval::eval_context *ectx) const | |
{ | |
this->set_from_utf8_string(arrmeta, data, utf8_str.data(), utf8_str.data() + utf8_str.size(), ectx); | |
} | |
virtual ndt::type apply_linear_index(intptr_t nindices, const irange *indices, size_t current_i, | |
const ndt::type &root_tp, bool leading_dimension) const; | |
virtual intptr_t apply_linear_index(intptr_t nindices, const irange *indices, const char *arrmeta, | |
const ndt::type &result_type, char *out_arrmeta, | |
const intrusive_ptr<memory_block_data> &embedded_reference, size_t current_i, | |
const ndt::type &root_tp, bool leading_dimension, char **inout_data, | |
intrusive_ptr<memory_block_data> &inout_dataref) const; | |
virtual ndt::type at_single(intptr_t i0, const char **inout_arrmeta, const char **inout_data) const; | |
virtual ndt::type get_type_at_dimension(char **inout_arrmeta, intptr_t i, intptr_t total_ndim = 0) const; | |
virtual void get_shape(intptr_t ndim, intptr_t i, intptr_t *out_shape, const char *arrmeta, const char *data) const; | |
virtual void get_strides(size_t i, intptr_t *out_strides, const char *arrmeta) const; | |
virtual bool is_c_contiguous(const char *arrmeta) const; | |
bool is_symbolic() const { return (flags & type_flag_symbolic) != 0; } | |
virtual axis_order_classification_t classify_axis_order(const char *arrmeta) const; | |
virtual bool is_lossless_assignment(const ndt::type &dst_tp, const ndt::type &src_tp) const; | |
virtual bool operator==(const base_type &rhs) const = 0; | |
virtual void arrmeta_default_construct(char *arrmeta, bool blockref_alloc) const; | |
virtual void arrmeta_copy_construct(char *dst_arrmeta, const char *src_arrmeta, | |
const intrusive_ptr<memory_block_data> &embedded_reference) const; | |
virtual void arrmeta_destruct(char *arrmeta) const; | |
virtual void arrmeta_reset_buffers(char *arrmeta) const; | |
virtual void arrmeta_finalize_buffers(char *arrmeta) const; | |
virtual void arrmeta_debug_print(const char *arrmeta, std::ostream &o, const std::string &indent) const; | |
virtual void data_construct(const char *arrmeta, char *data) const; | |
virtual void data_destruct(const char *arrmeta, char *data) const; | |
virtual void data_destruct_strided(const char *arrmeta, char *data, intptr_t stride, size_t count) const; | |
virtual size_t get_iterdata_size(intptr_t ndim) const; | |
virtual size_t iterdata_construct(iterdata_common *iterdata, const char **inout_arrmeta, intptr_t ndim, | |
const intptr_t *shape, ndt::type &out_uniform_tp) const; | |
virtual size_t iterdata_destruct(iterdata_common *iterdata, intptr_t ndim) const; | |
virtual bool match(const ndt::type &candidate_tp, std::map<std::string, ndt::type> &tp_vars) const; | |
virtual void foreach_leading(const char *arrmeta, char *data, foreach_fn_t callback, void *callback_data) const; | |
virtual void get_vars(std::unordered_set<std::string> &) const {} | |
virtual std::map<std::string, std::pair<ndt::type, const char *>> get_dynamic_type_properties() const; | |
friend void intrusive_ptr_retain(const base_type *ptr); | |
friend void intrusive_ptr_release(const base_type *ptr); | |
friend long intrusive_ptr_use_count(const base_type *ptr); | |
friend type make_dynamic_type(type_id_t tp_id); | |
}; | |
inline void intrusive_ptr_retain(const base_type *ptr) | |
{ | |
if (!is_builtin_type(ptr)) { | |
++ptr->m_use_count; | |
} | |
} | |
inline void intrusive_ptr_release(const base_type *ptr) | |
{ | |
if (!is_builtin_type(ptr)) { | |
if (--ptr->m_use_count == 0) { | |
delete ptr; | |
} | |
} | |
} | |
inline long intrusive_ptr_use_count(const base_type *ptr) { return ptr->m_use_count; } | |
} | |
struct __declspec(dllimport) size_stride_t { | |
intptr_t dim_size; | |
intptr_t stride; | |
}; | |
} | |
namespace dynd { | |
namespace ndt { | |
class __declspec(dllimport) base_expr_type : public base_type { | |
public: | |
base_expr_type(type_id_t type_id, size_t data_size, size_t alignment, uint32_t flags, size_t arrmeta_size, | |
size_t ndim = 0); | |
virtual const type &get_value_type() const = 0; | |
virtual const type &get_operand_type() const = 0; | |
virtual const type &get_storage_type() const | |
{ | |
throw std::runtime_error("get_storage_type is not implemented for this type"); | |
} | |
static inline uint32_t inherited_flags(uint32_t value_flags, uint32_t operand_flags) | |
{ | |
return (value_flags & type_flags_value_inherited) | (operand_flags & type_flags_operand_inherited); | |
} | |
virtual type with_replaced_storage_type(const type &replacement_type) const = 0; | |
bool is_expression() const; | |
type get_canonical_type() const; | |
void arrmeta_default_construct(char *arrmeta, bool blockref_alloc) const; | |
void arrmeta_copy_construct(char *dst_arrmeta, const char *src_arrmeta, | |
const intrusive_ptr<memory_block_data> &embedded_reference) const; | |
void arrmeta_destruct(char *arrmeta) const; | |
void arrmeta_debug_print(const char *arrmeta, std::ostream &o, const std::string &indent) const; | |
size_t get_iterdata_size(intptr_t ndim) const; | |
}; | |
} | |
} | |
namespace dynd { | |
namespace ndt { | |
class type; | |
} | |
enum string_encoding_t : uint32_t { | |
string_encoding_ascii, | |
string_encoding_ucs_2, | |
string_encoding_utf_8, | |
string_encoding_utf_16, | |
string_encoding_utf_32, | |
string_encoding_invalid | |
}; | |
extern __declspec(dllimport) int string_encoding_char_size_table[6]; | |
inline bool is_variable_length_string_encoding(string_encoding_t encoding) | |
{ | |
return encoding == string_encoding_utf_8 || encoding == string_encoding_utf_16; | |
} | |
inline const char *encoding_as_string(string_encoding_t encoding) | |
{ | |
switch (encoding) { | |
case string_encoding_ascii: | |
return "ascii"; | |
case string_encoding_ucs_2: | |
return "ucs2"; | |
case string_encoding_utf_8: | |
return "utf8"; | |
case string_encoding_utf_16: | |
return "utf16"; | |
case string_encoding_utf_32: | |
return "utf32"; | |
default: | |
return "unknown string encoding"; | |
} | |
} | |
inline std::ostream &operator<<(std::ostream &o, string_encoding_t encoding) | |
{ | |
o << encoding_as_string(encoding); | |
return o; | |
} | |
typedef uint32_t (*next_unicode_codepoint_t)(const char *&it, const char *end); | |
typedef void (*append_unicode_codepoint_t)(uint32_t cp, char *&it, char *end); | |
__declspec(dllimport) next_unicode_codepoint_t | |
get_next_unicode_codepoint_function(string_encoding_t encoding, assign_error_mode errmode); | |
__declspec(dllimport) append_unicode_codepoint_t | |
get_append_unicode_codepoint_function(string_encoding_t encoding, assign_error_mode errmode); | |
__declspec(dllimport) std::string string_range_as_utf8_string(string_encoding_t encoding, const char *begin, const char *end, | |
assign_error_mode errmode); | |
__declspec(dllimport) void print_escaped_unicode_codepoint(std::ostream &o, uint32_t cp, bool single_quote); | |
__declspec(dllimport) void print_escaped_utf8_string(std::ostream &o, const char *str_begin, const char *str_end, | |
bool single_quote = false); | |
inline void print_escaped_utf8_string(std::ostream &o, const std::string &str, bool single_quote = false) | |
{ | |
print_escaped_utf8_string(o, str.data(), str.data() + str.size(), single_quote); | |
} | |
__declspec(dllimport) void append_utf8_codepoint(uint32_t cp, std::string &out_str); | |
__declspec(dllimport) ndt::type char_type_of_encoding(string_encoding_t encoding); | |
} | |
namespace dynd { | |
namespace ndt { | |
class __declspec(dllimport) base_string_type : public base_type { | |
private: | |
const string_encoding_t m_encoding{string_encoding_ascii}; | |
const std::string m_encoding_repr{encoding_as_string(string_encoding_ascii)}; | |
public: | |
base_string_type(type_id_t type_id, size_t data_size, size_t alignment, uint32_t flags, size_t arrmeta_size) | |
: base_type(type_id, data_size, alignment, flags, arrmeta_size, 0, 0) | |
{ | |
} | |
virtual string_encoding_t get_encoding() const { return m_encoding; } | |
virtual void get_string_range(const char **out_begin, const char **out_end, const char *arrmeta, | |
const char *data) const = 0; | |
std::string get_utf8_string(const char *arrmeta, const char *data, assign_error_mode errmode) const; | |
size_t get_iterdata_size(intptr_t ndim) const; | |
std::map<std::string, std::pair<ndt::type, const char *>> get_dynamic_type_properties() const; | |
}; | |
} | |
} | |
namespace dynd { | |
namespace ndt { | |
class type; | |
} | |
namespace nd { | |
class array; | |
} | |
class __declspec(dllimport) dynd_exception { | |
protected: | |
std::string m_message, m_what; | |
public: | |
dynd_exception() {} | |
dynd_exception(const char *exception_name, const std::string &msg) | |
: m_message(msg), m_what(std::string() + exception_name + ": " + msg) | |
{ | |
} | |
virtual const char *message() const throw(); | |
virtual const char *what() const throw(); | |
virtual ~dynd_exception() throw(); | |
}; | |
class __declspec(dllimport) too_many_indices : public dynd_exception { | |
public: | |
too_many_indices(const ndt::type &dt, intptr_t nindices, intptr_t ndim); | |
virtual ~too_many_indices() throw(); | |
}; | |
class __declspec(dllimport) index_out_of_bounds : public dynd_exception { | |
public: | |
index_out_of_bounds(intptr_t i, size_t axis, intptr_t ndim, const intptr_t *shape); | |
index_out_of_bounds(intptr_t i, size_t axis, const std::vector<intptr_t> &shape); | |
index_out_of_bounds(intptr_t i, intptr_t dimension_size); | |
virtual ~index_out_of_bounds() throw(); | |
}; | |
class __declspec(dllimport) axis_out_of_bounds : public dynd_exception { | |
public: | |
axis_out_of_bounds(size_t i, intptr_t ndim); | |
virtual ~axis_out_of_bounds() throw(); | |
}; | |
class __declspec(dllimport) irange_out_of_bounds : public dynd_exception { | |
public: | |
irange_out_of_bounds(const irange &i, size_t axis, intptr_t ndim, const intptr_t *shape); | |
irange_out_of_bounds(const irange &i, size_t axis, const std::vector<intptr_t> &shape); | |
irange_out_of_bounds(const irange &i, intptr_t dimension_size); | |
virtual ~irange_out_of_bounds() throw(); | |
}; | |
class __declspec(dllimport) zero_division_error : public dynd_exception { | |
public: | |
zero_division_error(const std::string &msg) : dynd_exception("zero division error", msg) {} | |
virtual ~zero_division_error() throw(); | |
}; | |
class __declspec(dllimport) type_error : public dynd_exception { | |
public: | |
type_error(const char *exception_name, const std::string &msg) : dynd_exception(exception_name, msg) {} | |
type_error(const std::string &msg) : dynd_exception("type error", msg) {} | |
virtual ~type_error() throw(); | |
}; | |
class __declspec(dllimport) invalid_id : public type_error { | |
public: | |
invalid_id(int type_id); | |
virtual ~invalid_id() throw(); | |
}; | |
class __declspec(dllimport) string_decode_error : public dynd_exception { | |
std::string m_bytes; | |
string_encoding_t m_encoding; | |
public: | |
string_decode_error(const char *begin, const char *end, string_encoding_t encoding); | |
virtual ~string_decode_error() throw(); | |
const std::string &bytes() const; | |
string_encoding_t encoding() const; | |
}; | |
class __declspec(dllimport) string_encode_error : public dynd_exception { | |
uint32_t m_cp; | |
string_encoding_t m_encoding; | |
public: | |
string_encode_error(uint32_t cp, string_encoding_t encoding); | |
virtual ~string_encode_error() throw(); | |
uint32_t cp() const; | |
string_encoding_t encoding() const; | |
}; | |
enum comparison_type_t { | |
comparison_type_sorting_less, | |
comparison_type_less, | |
comparison_type_less_equal, | |
comparison_type_equal, | |
comparison_type_not_equal, | |
comparison_type_greater_equal, | |
comparison_type_greater | |
}; | |
class __declspec(dllimport) not_comparable_error : public dynd_exception { | |
public: | |
not_comparable_error(const ndt::type &lhs, const ndt::type &rhs, comparison_type_t comptype); | |
virtual ~not_comparable_error() throw(); | |
}; | |
} | |
namespace dynd { | |
namespace detail { | |
template <typename ValueType, int NDim> | |
class scalar_wrapper_iterator; | |
template <typename ValueType> | |
class scalar_wrapper { | |
protected: | |
const char *m_metadata; | |
char *m_data; | |
public: | |
typedef ValueType data_type; | |
static const intptr_t ndim = 0; | |
template <int NDim> | |
class iterator_type : public scalar_wrapper_iterator<ValueType, NDim> { | |
public: | |
iterator_type(const char *metadata, char *data) : scalar_wrapper_iterator<ValueType, NDim>(metadata, data) {} | |
}; | |
scalar_wrapper(const char *metadata, char *data) : m_metadata(metadata), m_data(data) {} | |
data_type &operator()(const char *, char *data) | |
{ | |
return *reinterpret_cast<data_type *>(data); | |
} | |
}; | |
template <typename ValueType> | |
class scalar_wrapper_iterator<ValueType, 0> { | |
protected: | |
char *m_data; | |
public: | |
scalar_wrapper_iterator(const char *, char *data) : m_data(data) {} | |
ValueType &operator*() { return *reinterpret_cast<ValueType *>(m_data); } | |
bool operator==(const scalar_wrapper_iterator &rhs) const { return m_data == rhs.m_data; } | |
bool operator!=(const scalar_wrapper_iterator &rhs) const { return m_data != rhs.m_data; } | |
}; | |
} | |
template <typename T> | |
using identity_t = T; | |
template <typename T> | |
using as_t = typename conditional_make<!std::is_fundamental<typename std::remove_cv<T>::type>::value && | |
!std::is_same<typename std::remove_cv<T>::type, ndt::type>::value, | |
identity_t, detail::scalar_wrapper, T>::type; | |
inline size_t inc_to_alignment(size_t offset, size_t alignment) | |
{ | |
return (offset + alignment - 1) & (std::size_t)(-(std::ptrdiff_t)alignment); | |
} | |
inline char *inc_to_alignment(char *ptr, size_t alignment) | |
{ | |
return reinterpret_cast<char *>((reinterpret_cast<std::size_t>(ptr) + alignment - 1) & | |
(std::size_t)(-(std::ptrdiff_t)alignment)); | |
} | |
inline void *inc_to_alignment(void *ptr, size_t alignment) | |
{ | |
return reinterpret_cast<char *>((reinterpret_cast<std::size_t>(ptr) + alignment - 1) & | |
(size_t)(-(std::ptrdiff_t)alignment)); | |
} | |
inline bool offset_is_aligned(size_t offset, size_t alignment) { return (offset & (alignment - 1)) == 0; } | |
void __declspec(dllimport) print_builtin_scalar(type_id_t type_id, std::ostream &o, const char *data); | |
struct __declspec(dllimport) iterdata_broadcasting_terminator { | |
iterdata_common common; | |
char *data; | |
}; | |
__declspec(dllimport) char *iterdata_broadcasting_terminator_incr(iterdata_common *iterdata, intptr_t level); | |
__declspec(dllimport) char *iterdata_broadcasting_terminator_adv(iterdata_common *iterdata, intptr_t level, intptr_t i); | |
__declspec(dllimport) char *iterdata_broadcasting_terminator_reset(iterdata_common *iterdata, char *data, intptr_t level); | |
namespace ndt { | |
typedef type (*type_make_t)(type_id_t tp_id, const nd::array &args); | |
__declspec(dllimport) type make_fixed_dim(size_t dim_size, const type &element_tp); | |
inline type make_var_dim(const type &element_tp); | |
template <typename T> | |
struct traits { | |
~traits() = delete; | |
}; | |
template <typename T> | |
struct has_traits { | |
static const bool value = std::is_destructible<traits<T>>::value; | |
}; | |
class __declspec(dllimport) type : public intrusive_ptr<const base_type> { | |
private: | |
template <typename T, typename C = typename T::value_type> | |
std::enable_if_t<is_vector<T>::value, const T> &property(const char *name) const | |
{ | |
const std::pair<ndt::type, const char *> pair = get_properties()[name]; | |
const ndt::type &dt = pair.first.get_dtype(); | |
if (pair.first.get_id() != fixed_dim_id) { | |
throw std::runtime_error("unsupported type for property access"); | |
} | |
if (dt.get_id() == property_type_id_of<C>::value) { | |
return *reinterpret_cast<const T *>(pair.second); | |
} | |
throw std::runtime_error("type mismatch or unsupported type in property access"); | |
} | |
template <typename T> | |
std::enable_if_t<!is_vector<T>::value, const T> &property(const char *name) const | |
{ | |
const std::pair<ndt::type, const char *> pair = get_properties()[name]; | |
if (pair.first.get_id() == property_type_id_of<T>::value) { | |
return *reinterpret_cast<const T *>(pair.second); | |
} | |
throw std::runtime_error("type mismatch in property access"); | |
} | |
public: | |
using intrusive_ptr<const base_type>::intrusive_ptr; | |
type() = default; | |
type(type_id_t tp_id); | |
explicit type(const std::string &rep); | |
type(const char *rep_begin, const char *rep_end); | |
bool operator==(const type &rhs) const | |
{ | |
return m_ptr == rhs.m_ptr || (!is_builtin() && !rhs.is_builtin() && *m_ptr == *rhs.m_ptr); | |
} | |
bool operator!=(const type &rhs) const { return !(operator==(rhs)); } | |
bool is_null() const { return m_ptr == 0; } | |
bool is_builtin() const { return is_builtin_type(m_ptr); } | |
type at_array(int nindices, const irange *indices) const; | |
type at_single(intptr_t i0, const char **inout_arrmeta = 0, const char **inout_data = 0) const | |
{ | |
if (!is_builtin()) { | |
return m_ptr->at_single(i0, inout_arrmeta, inout_data); | |
} | |
else { | |
throw too_many_indices(*this, 1, 0); | |
} | |
} | |
type at(const irange &i0) const { return at_array(1, &i0); } | |
type at(const irange &i0, const irange &i1) const | |
{ | |
irange i[2] = {i0, i1}; | |
return at_array(2, i); | |
} | |
type at(const irange &i0, const irange &i1, const irange &i2) const | |
{ | |
irange i[3] = {i0, i1, i2}; | |
return at_array(3, i); | |
} | |
type at(const irange &i0, const irange &i1, const irange &i2, const irange &i3) const | |
{ | |
irange i[4] = {i0, i1, i2, i3}; | |
return at_array(4, i); | |
} | |
bool match(const ndt::type &candidate_tp, std::map<std::string, ndt::type> &tp_vars) const; | |
bool match(const type &other) const | |
{ | |
std::map<std::string, type> tp_vars; | |
return match(other, tp_vars); | |
} | |
template <typename T> | |
const T &p(const char *name) const | |
{ | |
return property<T>(name); | |
} | |
template <typename T> | |
const T &p(const std::string &name) const | |
{ | |
return property<T>(name.c_str()); | |
} | |
type apply_linear_index(intptr_t nindices, const irange *indices, size_t current_i, const type &root_tp, | |
bool leading_dimension) const; | |
const type &value_type() const; | |
const type &storage_type() const; | |
type_id_t get_id() const | |
{ | |
if (is_builtin()) { | |
return static_cast<type_id_t>(reinterpret_cast<intptr_t>(m_ptr)); | |
} | |
else { | |
return m_ptr->get_id(); | |
} | |
} | |
type_id_t unchecked_get_builtin_id() const { return static_cast<type_id_t>(reinterpret_cast<intptr_t>(m_ptr)); } | |
type_id_t get_base_id() const; | |
size_t get_data_alignment() const; | |
size_t get_data_size() const; | |
size_t get_default_data_size() const; | |
size_t get_arrmeta_size() const | |
{ | |
if (is_builtin()) { | |
return 0; | |
} | |
else { | |
return m_ptr->get_arrmeta_size(); | |
} | |
} | |
bool data_layout_compatible_with(const type &rhs) const; | |
bool is_type_subarray(const ndt::type &subarray_tp) const | |
{ | |
if (is_builtin()) { | |
return *this == subarray_tp; | |
} | |
else { | |
return m_ptr->is_type_subarray(subarray_tp); | |
} | |
} | |
bool is_pod() const | |
{ | |
if (is_builtin()) { | |
return true; | |
} | |
else { | |
return m_ptr->get_data_size() > 0 && (m_ptr->get_flags() & (type_flag_blockref | type_flag_destructor)) == 0; | |
} | |
} | |
bool is_c_contiguous(const char *arrmeta) const | |
{ | |
if (is_builtin()) { | |
return true; | |
} | |
return m_ptr->is_c_contiguous(arrmeta); | |
} | |
bool is_indexable() const { return !is_builtin() && m_ptr->is_indexable(); } | |
bool is_scalar() const { return is_builtin() || m_ptr->is_scalar(); } | |
bool is_expression() const | |
{ | |
if (is_builtin()) { | |
return false; | |
} | |
else { | |
return m_ptr->is_expression(); | |
} | |
} | |
bool is_symbolic() const { return !is_builtin() && m_ptr->is_symbolic(); } | |
bool is_variadic() const { return !is_builtin() && (m_ptr->get_flags() & type_flag_variadic); } | |
type with_replaced_scalar_types(const type &scalar_type) const; | |
type with_replaced_dtype(const type &replacement_tp, intptr_t replace_ndim = 0) const; | |
type without_memory_type() const; | |
type with_new_axis(intptr_t i, intptr_t new_ndim = 1) const; | |
type get_canonical_type() const | |
{ | |
if (is_builtin()) { | |
return *this; | |
} | |
else { | |
return m_ptr->get_canonical_type(); | |
} | |
} | |
uint32_t get_flags() const | |
{ | |
if (is_builtin()) { | |
return type_flag_none; | |
} | |
else { | |
return m_ptr->get_flags(); | |
} | |
} | |
intptr_t get_ndim() const | |
{ | |
if (is_builtin()) { | |
return 0; | |
} | |
else { | |
return m_ptr->get_ndim(); | |
} | |
} | |
intptr_t get_strided_ndim() const | |
{ | |
if (is_builtin()) { | |
return 0; | |
} | |
else { | |
return m_ptr->get_strided_ndim(); | |
} | |
} | |
type get_dtype(size_t include_ndim = 0, char **inout_arrmeta = 0) const | |
{ | |
size_t ndim = get_ndim(); | |
if (ndim == include_ndim) { | |
return *this; | |
} | |
else if (ndim > include_ndim) { | |
return m_ptr->get_type_at_dimension(inout_arrmeta, ndim - include_ndim); | |
} | |
else { | |
std::stringstream ss; | |
ss << "Cannot use " << include_ndim << " array "; | |
ss << "dimensions from dynd type " << *this; | |
ss << ", it only has " << ndim; | |
throw dynd::type_error(ss.str()); | |
} | |
} | |
type get_dtype(size_t include_ndim, const char **inout_arrmeta) const | |
{ | |
return get_dtype(include_ndim, const_cast<char **>(inout_arrmeta)); | |
} | |
intptr_t get_dim_size(const char *arrmeta, const char *data) const; | |
intptr_t get_size(const char *arrmeta) const; | |
type get_type_at_dimension(char **inout_arrmeta, intptr_t i, intptr_t total_ndim = 0) const | |
{ | |
if (!is_builtin()) { | |
return m_ptr->get_type_at_dimension(inout_arrmeta, i, total_ndim); | |
} | |
else if (i == 0) { | |
return *this; | |
} | |
else { | |
throw too_many_indices(*this, total_ndim + i, total_ndim); | |
} | |
} | |
void get_vars(std::unordered_set<std::string> &vars) const | |
{ | |
if (!is_builtin()) { | |
m_ptr->get_vars(vars); | |
} | |
} | |
std::unordered_set<std::string> get_vars() const | |
{ | |
std::unordered_set<std::string> vars; | |
get_vars(vars); | |
return vars; | |
} | |
std::map<std::string, std::pair<ndt::type, const char *>> get_properties() const; | |
const base_type *extended() const { return m_ptr; } | |
template <class T> | |
const T *extended() const | |
{ | |
return static_cast<const T *>(m_ptr); | |
} | |
bool get_as_strided(const char *arrmeta, intptr_t *out_dim_size, intptr_t *out_stride, ndt::type *out_el_tp, | |
const char **out_el_arrmeta) const; | |
bool get_as_strided(const char *arrmeta, intptr_t ndim, const size_stride_t **out_size_stride, ndt::type *out_el_tp, | |
const char **out_el_arrmeta) const; | |
size_t get_iterdata_size(intptr_t ndim) const | |
{ | |
if (is_builtin()) { | |
return 0; | |
} | |
else { | |
return m_ptr->get_iterdata_size(ndim); | |
} | |
} | |
void iterdata_construct(iterdata_common *iterdata, const char **inout_arrmeta, intptr_t ndim, const intptr_t *shape, | |
type &out_uniform_type) const | |
{ | |
if (!is_builtin()) { | |
m_ptr->iterdata_construct(iterdata, inout_arrmeta, ndim, shape, out_uniform_type); | |
} | |
} | |
void iterdata_destruct(iterdata_common *iterdata, intptr_t ndim) const | |
{ | |
if (!is_builtin()) { | |
m_ptr->iterdata_destruct(iterdata, ndim); | |
} | |
} | |
size_t get_broadcasted_iterdata_size(intptr_t ndim) const | |
{ | |
if (is_builtin()) { | |
return sizeof(iterdata_broadcasting_terminator); | |
} | |
else { | |
return m_ptr->get_iterdata_size(ndim) + sizeof(iterdata_broadcasting_terminator); | |
} | |
} | |
void broadcasted_iterdata_construct(iterdata_common *iterdata, const char **inout_arrmeta, intptr_t ndim, | |
const intptr_t *shape, type &out_uniform_tp) const | |
{ | |
size_t size; | |
if (is_builtin()) { | |
size = 0; | |
} | |
else { | |
size = m_ptr->iterdata_construct(iterdata, inout_arrmeta, ndim, shape, out_uniform_tp); | |
} | |
iterdata_broadcasting_terminator *id = | |
reinterpret_cast<iterdata_broadcasting_terminator *>(reinterpret_cast<char *>(iterdata) + size); | |
id->common.incr = &iterdata_broadcasting_terminator_incr; | |
id->common.adv = &iterdata_broadcasting_terminator_adv; | |
id->common.reset = &iterdata_broadcasting_terminator_reset; | |
} | |
void print_data(std::ostream &o, const char *arrmeta, const char *data) const; | |
std::string str() const | |
{ | |
std::stringstream ss; | |
ss << *this; | |
return ss.str(); | |
} | |
static type make(type_id_t tp_id, const nd::array &args); | |
friend __declspec(dllimport) std::ostream &operator<<(std::ostream &o, const type &rhs); | |
}; | |
template <> | |
struct traits<void> { | |
static const size_t ndim = 0; | |
static const bool is_same_layout = false; | |
static type equivalent() { return type(type_id_of<void>::value); } | |
}; | |
namespace detail { | |
template <typename T, typename... ArgTypes> | |
auto _make_type(int, ArgTypes &&... args) -> decltype(traits<T>::equivalent(std::forward<ArgTypes>(args)...)) | |
{ | |
return traits<T>::equivalent(std::forward<ArgTypes>(args)...); | |
} | |
template <typename T, typename... ArgTypes> | |
auto _make_type(char, ArgTypes &&... ) -> decltype(traits<T>::equivalent()) | |
{ | |
return traits<T>::equivalent(); | |
} | |
} | |
template <typename T, typename... ArgTypes> | |
auto make_type(ArgTypes &&... args) -> decltype(detail::_make_type<T>(0, std::forward<ArgTypes>(args)...)) | |
{ | |
return detail::_make_type<T>(0, std::forward<ArgTypes>(args)...); | |
} | |
template <typename ValueType> | |
type type_for(const ValueType &value) | |
{ | |
return make_type<ValueType>(value); | |
} | |
template <typename ValueType> | |
type type_for(const std::initializer_list<ValueType> &values) | |
{ | |
return make_type<std::initializer_list<ValueType>>(values); | |
} | |
template <typename ValueType> | |
type type_for(const std::initializer_list<std::initializer_list<ValueType>> &values) | |
{ | |
return make_type<std::initializer_list<std::initializer_list<ValueType>>>(values); | |
} | |
template <typename ValueType> | |
type type_for(const std::initializer_list<std::initializer_list<std::initializer_list<ValueType>>> &values) | |
{ | |
return make_type<std::initializer_list<std::initializer_list<std::initializer_list<ValueType>>>>(values); | |
} | |
template <typename T, typename... ArgTypes> | |
std::enable_if_t<std::is_base_of<base_type, T>::value, type> make_type(ArgTypes &&... args) | |
{ | |
return type(new T(std::forward<ArgTypes>(args)...), false); | |
} | |
template <> | |
struct traits<bool1> { | |
static const size_t ndim = 0; | |
static const bool is_same_layout = true; | |
static type equivalent() { return type(type_id_of<bool1>::value); } | |
}; | |
template <> | |
struct traits<bool> { | |
static const size_t ndim = 0; | |
static const bool is_same_layout = false; | |
static type equivalent() { return traits<bool1>::equivalent(); } | |
}; | |
template <> | |
struct traits<signed char> { | |
static const size_t ndim = 0; | |
static const bool is_same_layout = true; | |
static type equivalent() { return type(type_id_of<signed char>::value); } | |
static signed char na() { return std::numeric_limits<signed char>::min(); } | |
}; | |
template <> | |
struct traits<short> { | |
static const size_t ndim = 0; | |
static const bool is_same_layout = true; | |
static type equivalent() { return type(type_id_of<short>::value); } | |
}; | |
template <> | |
struct traits<int> { | |
static const size_t ndim = 0; | |
static const bool is_same_layout = true; | |
static type equivalent() { return type(type_id_of<int>::value); } | |
static int na() { return std::numeric_limits<int>::min(); } | |
}; | |
template <> | |
struct traits<long> { | |
static const size_t ndim = 0; | |
static const bool is_same_layout = true; | |
static type equivalent() { return type(type_id_of<long>::value); } | |
}; | |
template <> | |
struct traits<long long> { | |
static const size_t ndim = 0; | |
static const bool is_same_layout = true; | |
static type equivalent() { return type(type_id_of<long long>::value); } | |
}; | |
template <> | |
struct traits<int128> { | |
static const size_t ndim = 0; | |
static const bool is_same_layout = true; | |
static type equivalent() { return type(type_id_of<int128>::value); } | |
}; | |
template <> | |
struct traits<unsigned char> { | |
static const size_t ndim = 0; | |
static const bool is_same_layout = true; | |
static type equivalent() { return type(type_id_of<unsigned char>::value); } | |
}; | |
template <> | |
struct traits<unsigned short> { | |
static const size_t ndim = 0; | |
static const bool is_same_layout = true; | |
static type equivalent() { return type(type_id_of<unsigned short>::value); } | |
}; | |
template <> | |
struct traits<unsigned int> { | |
static const size_t ndim = 0; | |
static const bool is_same_layout = true; | |
static type equivalent() { return type(type_id_of<unsigned int>::value); } | |
static unsigned int na() { return std::numeric_limits<unsigned int>::max(); } | |
}; | |
template <> | |
struct traits<unsigned long> { | |
static const size_t ndim = 0; | |
static const bool is_same_layout = true; | |
static type equivalent() { return type(type_id_of<unsigned long>::value); } | |
}; | |
template <> | |
struct traits<unsigned long long> { | |
static const size_t ndim = 0; | |
static const bool is_same_layout = true; | |
static type equivalent() { return type(type_id_of<unsigned long long>::value); } | |
}; | |
template <> | |
struct traits<uint128> { | |
static const size_t ndim = 0; | |
static const bool is_same_layout = true; | |
static type equivalent() { return type(type_id_of<uint128>::value); } | |
}; | |
template <> | |
struct traits<char> { | |
static const size_t ndim = 0; | |
static const bool is_same_layout = true; | |
static type equivalent() { return type(type_id_of<char>::value); } | |
}; | |
template <> | |
struct traits<float16> { | |
static const size_t ndim = 0; | |
static const bool is_same_layout = true; | |
static type equivalent() { return type(type_id_of<float16>::value); } | |
}; | |
template <> | |
struct traits<float> { | |
static const size_t ndim = 0; | |
static const bool is_same_layout = true; | |
static type equivalent() { return type(type_id_of<float>::value); } | |
}; | |
template <> | |
struct traits<double> { | |
static const size_t ndim = 0; | |
static const bool is_same_layout = true; | |
static type equivalent() { return type(type_id_of<double>::value); } | |
}; | |
template <> | |
struct traits<float128> { | |
static const size_t ndim = 0; | |
static const bool is_same_layout = true; | |
static type equivalent() { return type(type_id_of<float128>::value); } | |
}; | |
template <typename T> | |
struct traits<complex<T>> { | |
static const size_t ndim = 0; | |
static const bool is_same_layout = true; | |
static type equivalent() { return type(type_id_of<complex<T>>::value); } | |
}; | |
template <typename T> | |
struct traits<std::complex<T>> { | |
static const size_t ndim = 0; | |
static const bool is_same_layout = true; | |
static type equivalent() { return type(type_id_of<std::complex<T>>::value); } | |
}; | |
template <> | |
struct traits<const char *> { | |
static const size_t ndim = 0; | |
static const bool is_same_layout = false; | |
static type equivalent() { return type(string_id); } | |
}; | |
template <size_t N> | |
struct traits<char[N]> { | |
static const size_t ndim = 0; | |
static const bool is_same_layout = false; | |
static type equivalent() { return type(string_id); } | |
}; | |
template <size_t N> | |
struct traits<const char[N]> { | |
static const size_t ndim = 0; | |
static const bool is_same_layout = false; | |
static type equivalent() { return type(string_id); } | |
}; | |
template <> | |
struct traits<type> { | |
static const size_t ndim = 0; | |
static const bool is_same_layout = true; | |
static type equivalent() { return type(type_id); } | |
}; | |
template <typename T> | |
struct traits<const T> { | |
static const size_t ndim = traits<T>::ndim; | |
static const bool is_same_layout = traits<T>::is_same_layout; | |
static type equivalent() { return traits<T>::equivalent(); } | |
}; | |
template <typename T> | |
struct traits<T &> { | |
static const size_t ndim = traits<T>::ndim; | |
static const bool is_same_layout = traits<T>::is_same_layout; | |
static type equivalent() { return traits<T>::equivalent(); } | |
}; | |
template <typename T> | |
struct traits<T &&> { | |
static const size_t ndim = traits<T>::ndim; | |
static const bool is_same_layout = traits<T>::is_same_layout; | |
static type equivalent() { return traits<T>::equivalent(); } | |
}; | |
template <typename T, size_t N> | |
struct traits<T[N]> { | |
static const size_t ndim = traits<T>::ndim + 1; | |
static const bool is_same_layout = traits<T>::is_same_layout; | |
static type equivalent() { return make_fixed_dim(N, make_type<T>()); } | |
}; | |
template <> | |
struct traits<assign_error_mode> { | |
static const size_t ndim = 0; | |
static const bool is_same_layout = true; | |
static type equivalent() { return make_type<typename std::underlying_type<assign_error_mode>::type>(); } | |
static assign_error_mode na() | |
{ | |
return static_cast<assign_error_mode>(traits<typename std::underlying_type<assign_error_mode>::type>::na()); | |
} | |
}; | |
template <typename T, size_t N> | |
struct traits<const T[N]> { | |
static const size_t ndim = traits<T[N]>::ndim; | |
static const bool is_same_layout = traits<T[N]>::is_same_layout; | |
static type equivalent() { return make_type<T[N]>(); } | |
}; | |
template <typename ContainerType, size_t NDim> | |
struct container_traits { | |
static const size_t ndim = NDim; | |
static const bool is_same_layout = false; | |
static type equivalent(const ContainerType &values) | |
{ | |
intptr_t shape[ndim]; | |
container_traits::shape(shape, values); | |
type tp = value_type(); | |
for (intptr_t i = ndim - 1; i >= 0; --i) { | |
if (shape[i] == -1) { | |
tp = make_var_dim(tp); | |
} | |
else { | |
tp = make_fixed_dim(shape[i], tp); | |
} | |
} | |
return tp; | |
} | |
static void shape(intptr_t *res, const ContainerType &values) | |
{ | |
res[0] = values.size(); | |
auto iter = values.begin(); | |
ndt::traits<typename ContainerType::value_type>::shape(res + 1, *iter); | |
while (++iter != values.end()) { | |
intptr_t next_shape[ndim - 1]; | |
ndt::traits<typename ContainerType::value_type>::shape(next_shape, *iter); | |
for (size_t i = 1; i < ndim; ++i) { | |
if (res[i] != next_shape[i - 1]) { | |
res[i] = -1; | |
} | |
} | |
} | |
} | |
static type value_type() { return container_traits<typename ContainerType::value_type, ndim - 1>::value_type(); } | |
}; | |
template <typename ContainerType> | |
struct container_traits<ContainerType, 1> { | |
static const size_t ndim = 1; | |
static const bool is_same_layout = false; | |
static type equivalent(const ContainerType &values) | |
{ | |
intptr_t size; | |
shape(&size, values); | |
return make_fixed_dim(size, value_type()); | |
} | |
static void shape(intptr_t *res, const ContainerType &values) { res[0] = values.size(); } | |
static type value_type() { return traits<typename ContainerType::value_type>::equivalent(); } | |
}; | |
template <typename ValueType> | |
struct traits<std::initializer_list<ValueType>> | |
: container_traits<std::initializer_list<ValueType>, traits<ValueType>::ndim + 1> { | |
}; | |
template <typename ValueType> | |
struct traits<std::vector<ValueType>> : container_traits<std::vector<ValueType>, traits<ValueType>::ndim + 1> { | |
}; | |
__declspec(dllimport) extern class common_type { | |
typedef type (*child_type)(const type &, const type &); | |
struct init; | |
static std::map<std::array<type_id_t, 2>, child_type> children; | |
public: | |
common_type(); | |
__declspec(dllimport) ndt::type operator()(const ndt::type &tp0, const ndt::type &tp1) const; | |
} common_type; | |
__declspec(dllimport) type make_type(intptr_t ndim, const intptr_t *shape, const ndt::type &dtype); | |
template <int N> | |
inline type make_type(intptr_t ndim, const intptr_t *shape, const char(&dtype)[N]) | |
{ | |
return make_type(ndim, shape, ndt::type(dtype)); | |
} | |
__declspec(dllimport) type make_type(intptr_t ndim, const intptr_t *shape, const ndt::type &dtype, bool &out_any_var); | |
__declspec(dllimport) std::ostream &operator<<(std::ostream &o, const type &rhs); | |
struct reg_info_t { | |
type tp; | |
}; | |
namespace detail { | |
__declspec(dllimport) std::map<type_id_t, reg_info_t> &infos(); | |
} | |
__declspec(dllimport) void reg(type_id_t id, const ndt::type &tp); | |
} | |
__declspec(dllimport) void hexadecimal_print(std::ostream &o, char value); | |
__declspec(dllimport) void hexadecimal_print(std::ostream &o, unsigned char value); | |
__declspec(dllimport) void hexadecimal_print(std::ostream &o, unsigned short value); | |
__declspec(dllimport) void hexadecimal_print(std::ostream &o, unsigned int value); | |
__declspec(dllimport) void hexadecimal_print(std::ostream &o, unsigned long value); | |
__declspec(dllimport) void hexadecimal_print(std::ostream &o, unsigned long long value); | |
__declspec(dllimport) void hexadecimal_print(std::ostream &o, const char *data, intptr_t element_size); | |
__declspec(dllimport) void hexadecimal_print_summarized(std::ostream &o, const char *data, intptr_t element_size, | |
intptr_t summary_size); | |
__declspec(dllimport) void strided_array_summarized(std::ostream &o, const ndt::type &tp, const char *arrmeta, const char *data, | |
intptr_t dim_size, intptr_t stride); | |
__declspec(dllimport) void print_indented(std::ostream &o, const std::string &indent, const std::string &s, | |
bool skipfirstline = false); | |
__declspec(dllimport) bool is_lossless_assignment(const ndt::type &dst_tp, const ndt::type &src_tp); | |
} | |
namespace dynd { | |
class __declspec(dllimport) string : public bytes { | |
public: | |
string() {} | |
string(const char *data, size_t size) : bytes(data, size) {} | |
string(const std::string &other) : string(other.data(), other.size()) {} | |
bool operator<(const string &rhs) const | |
{ | |
return std::lexicographical_compare(begin(), end(), rhs.begin(), rhs.end()); | |
} | |
bool operator<=(const string &rhs) const | |
{ | |
return !std::lexicographical_compare(rhs.begin(), rhs.end(), begin(), end()); | |
} | |
bool operator>=(const string &rhs) const | |
{ | |
return !std::lexicographical_compare(begin(), end(), rhs.begin(), rhs.end()); | |
} | |
bool operator>(const string &rhs) const | |
{ | |
return std::lexicographical_compare(rhs.begin(), rhs.end(), begin(), end()); | |
} | |
const string operator+(const string &rhs) | |
{ | |
string result; | |
result.resize(size() + rhs.size()); | |
std::memcpy(result.begin(), begin(), size()); | |
std::memcpy(result.begin() + size(), rhs.begin(), rhs.size()); | |
return result; | |
} | |
}; | |
namespace ndt { | |
class __declspec(dllimport) string_type : public base_string_type { | |
private: | |
const string_encoding_t m_encoding{string_encoding_utf_8}; | |
const std::string m_encoding_repr{encoding_as_string(string_encoding_utf_8)}; | |
public: | |
typedef string data_type; | |
string_type(); | |
string_encoding_t get_encoding() const { return m_encoding; } | |
size_t get_target_alignment() const { return string_encoding_char_size_table[string_encoding_utf_8]; } | |
void get_string_range(const char **out_begin, const char **out_end, const char *arrmeta, const char *data) const; | |
void set_from_utf8_string(const char *arrmeta, char *dst, const char *utf8_begin, const char *utf8_end, | |
const eval::eval_context *ectx) const; | |
void print_data(std::ostream &o, const char *arrmeta, const char *data) const; | |
void print_type(std::ostream &o) const; | |
bool is_unique_data_owner(const char *arrmeta) const; | |
type get_canonical_type() const; | |
void get_shape(intptr_t ndim, intptr_t i, intptr_t *out_shape, const char *arrmeta, const char *data) const; | |
std::map<std::string, std::pair<ndt::type, const char *>> get_dynamic_type_properties() const; | |
bool is_lossless_assignment(const type &dst_tp, const type &src_tp) const; | |
bool operator==(const base_type &rhs) const; | |
void data_destruct(const char *arrmeta, char *data) const; | |
void data_destruct_strided(const char *arrmeta, char *data, intptr_t stride, size_t count) const; | |
}; | |
template <> | |
struct traits<string> { | |
static const size_t ndim = 0; | |
static const bool is_same_layout = true; | |
static type equivalent() { return type(string_id); } | |
static string na() { return string(); } | |
}; | |
template <> | |
struct traits<std::string> { | |
static const size_t ndim = 0; | |
static const bool is_same_layout = false; | |
static type equivalent() { return make_type<string>(); } | |
}; | |
} | |
} | |
namespace dynd { | |
namespace ndt { | |
class __declspec(dllimport) base_dim_type : public base_type { | |
protected: | |
type m_element_tp; | |
size_t m_element_arrmeta_offset; | |
public: | |
base_dim_type(type_id_t tp_id, const type &element_tp, size_t data_size, size_t data_alignment, | |
size_t element_arrmeta_offset, uint32_t flags, bool strided); | |
const type &get_element_type() const { return m_element_tp; } | |
void get_element_types(std::size_t ndim, const type **element_tp) const; | |
std::vector<const type *> get_element_types(std::size_t ndim) const | |
{ | |
std::vector<const type *> element_tp(ndim); | |
get_element_types(ndim, element_tp.data()); | |
return element_tp; | |
} | |
bool is_type_subarray(const type &subarray_tp) const | |
{ | |
intptr_t this_ndim = get_ndim(), stp_ndim = subarray_tp.get_ndim(); | |
if (this_ndim > stp_ndim) { | |
return get_element_type().is_type_subarray(subarray_tp); | |
} | |
else if (this_ndim == stp_ndim) { | |
return (*this) == (*subarray_tp.extended()); | |
} | |
else { | |
return false; | |
} | |
} | |
size_t get_element_arrmeta_offset() const { return m_element_arrmeta_offset; } | |
virtual intptr_t get_dim_size(const char *arrmeta = 0, const char *data = 0) const = 0; | |
intptr_t get_size(const char *arrmeta) const | |
{ | |
std::intptr_t dim_size = get_dim_size(arrmeta, 0); | |
if (dim_size == -1) { | |
return -1; | |
} | |
return dim_size * m_element_tp.get_size(0); | |
} | |
virtual void get_vars(std::unordered_set<std::string> &vars) const { m_element_tp.get_vars(vars); } | |
virtual size_t arrmeta_copy_construct_onedim(char *dst_arrmeta, const char *src_arrmeta, | |
const intrusive_ptr<memory_block_data> &embedded_reference) const = 0; | |
virtual bool match(const type &candidate_tp, std::map<std::string, type> &tp_vars) const; | |
virtual type with_element_type(const type &element_tp) const = 0; | |
}; | |
} | |
} | |
namespace dynd { | |
namespace ndt { | |
class __declspec(dllimport) var_dim_type : public base_dim_type { | |
public: | |
struct metadata_type { | |
intrusive_ptr<memory_block_data> blockref; | |
intptr_t stride; | |
intptr_t offset; | |
}; | |
struct data_type { | |
char *begin; | |
size_t size; | |
}; | |
var_dim_type(const type &element_tp); | |
size_t get_default_data_size() const { return sizeof(data_type); } | |
size_t get_target_alignment() const { return m_element_tp.get_data_alignment(); } | |
void print_data(std::ostream &o, const char *arrmeta, const char *data) const; | |
void print_type(std::ostream &o) const; | |
bool is_expression() const; | |
bool is_unique_data_owner(const char *arrmeta) const; | |
void transform_child_types(type_transform_fn_t transform_fn, intptr_t arrmeta_offset, void *extra, | |
type &out_transformed_tp, bool &out_was_transformed) const; | |
type get_canonical_type() const; | |
type apply_linear_index(intptr_t nindices, const irange *indices, size_t current_i, const type &root_tp, | |
bool leading_dimension) const; | |
intptr_t apply_linear_index(intptr_t nindices, const irange *indices, const char *arrmeta, const type &result_tp, | |
char *out_arrmeta, const intrusive_ptr<memory_block_data> &embedded_reference, | |
size_t current_i, const type &root_tp, bool leading_dimension, char **inout_data, | |
intrusive_ptr<memory_block_data> &inout_dataref) const; | |
type at_single(intptr_t i0, const char **inout_arrmeta, const char **inout_data) const; | |
type get_type_at_dimension(char **inout_arrmeta, intptr_t i, intptr_t total_ndim = 0) const; | |
intptr_t get_dim_size(const char *arrmeta, const char *data) const; | |
void get_shape(intptr_t ndim, intptr_t i, intptr_t *out_shape, const char *arrmeta, const char *data) const; | |
void get_strides(size_t i, intptr_t *out_strides, const char *arrmeta) const; | |
axis_order_classification_t classify_axis_order(const char *arrmeta) const; | |
bool is_lossless_assignment(const type &dst_tp, const type &src_tp) const; | |
bool operator==(const base_type &rhs) const; | |
void arrmeta_default_construct(char *arrmeta, bool blockref_alloc) const; | |
void arrmeta_copy_construct(char *dst_arrmeta, const char *src_arrmeta, | |
const intrusive_ptr<memory_block_data> &embedded_reference) const; | |
void arrmeta_reset_buffers(char *arrmeta) const; | |
void arrmeta_finalize_buffers(char *arrmeta) const; | |
void arrmeta_destruct(char *arrmeta) const; | |
void arrmeta_debug_print(const char *arrmeta, std::ostream &o, const std::string &indent) const; | |
size_t arrmeta_copy_construct_onedim(char *dst_arrmeta, const char *src_arrmeta, | |
const intrusive_ptr<memory_block_data> &embedded_reference) const; | |
void data_destruct(const char *arrmeta, char *data) const; | |
void data_destruct_strided(const char *arrmeta, char *data, intptr_t stride, size_t count) const; | |
size_t get_iterdata_size(intptr_t ndim) const; | |
size_t iterdata_construct(iterdata_common *iterdata, const char **inout_arrmeta, intptr_t ndim, | |
const intptr_t *shape, type &out_uniform_tp) const; | |
size_t iterdata_destruct(iterdata_common *iterdata, intptr_t ndim) const; | |
void foreach_leading(const char *arrmeta, char *data, foreach_fn_t callback, void *callback_data) const; | |
std::map<std::string, std::pair<ndt::type, const char *>> get_dynamic_type_properties() const; | |
virtual type with_element_type(const type &element_tp) const; | |
static type make(const type &element_tp) { return type(new var_dim_type(element_tp), false); } | |
static type make(const type &element_tp, intptr_t ndim) | |
{ | |
type result = element_tp; | |
for (intptr_t i = 0; i < ndim; ++i) { | |
result = make(result); | |
} | |
return result; | |
} | |
}; | |
inline type make_var_dim(const type &element_tp) { return var_dim_type::make(element_tp); } | |
} | |
} | |
namespace dynd { | |
namespace nd { | |
template <typename ValueType> | |
struct init { | |
init(const ndt::type &, const char *) {} | |
void single(char *data, const ValueType &value) const { *reinterpret_cast<ValueType *>(data) = value; } | |
void contiguous(char *data, const ValueType *values, size_t size) const | |
{ | |
for (size_t i = 0; i < size; ++i) { | |
single(data, values[i]); | |
data += sizeof(ValueType); | |
} | |
} | |
}; | |
template <> | |
struct init<bool> { | |
init(const ndt::type &, const char *) {} | |
void single(char *data, bool value) const { *reinterpret_cast<bool1 *>(data) = value; } | |
void contiguous(char *data, const bool *values, size_t size) const | |
{ | |
for (size_t i = 0; i < size; ++i) { | |
single(data, values[i]); | |
data += sizeof(bool1); | |
} | |
} | |
}; | |
template <> | |
struct init<bytes> { | |
init(const ndt::type &, const char *) {} | |
void single(char *data, const bytes &value) const | |
{ | |
reinterpret_cast<bytes *>(data)->assign(value.data(), value.size()); | |
} | |
void contiguous(char *data, const bytes *values, size_t size) const | |
{ | |
for (size_t i = 0; i < size; ++i) { | |
single(data, values[i]); | |
data += sizeof(bytes); | |
} | |
} | |
}; | |
template <> | |
struct init<std::string> { | |
init(const ndt::type &, const char *) {} | |
void single(char *data, const std::string &value) const | |
{ | |
reinterpret_cast<string *>(data)->assign(value.data(), value.size()); | |
} | |
void contiguous(char *data, const std::string *values, size_t size) const | |
{ | |
for (size_t i = 0; i < size; ++i) { | |
single(data, values[i]); | |
data += sizeof(string); | |
} | |
} | |
}; | |
template <> | |
struct init<const char *> { | |
init(const ndt::type &, const char *) {} | |
void single(char *data, const char *value) const { reinterpret_cast<string *>(data)->assign(value, strlen(value)); } | |
void contiguous(char *data, const char *const *values, size_t size) const | |
{ | |
for (size_t i = 0; i < size; ++i) { | |
single(data, values[i]); | |
data += sizeof(string); | |
} | |
} | |
}; | |
template <size_t N> | |
struct init<char[N]> { | |
init(const ndt::type &, const char *) {} | |
void single(char *data, const char *value) const { reinterpret_cast<string *>(data)->assign(value, N - 1); } | |
void contiguous(char *data, const char *const *values, size_t size) const | |
{ | |
for (size_t i = 0; i < size; ++i) { | |
single(data, values[i]); | |
data += sizeof(string); | |
} | |
} | |
}; | |
template <size_t N> | |
struct init<const char[N]> { | |
init(const ndt::type &, const char *) {} | |
void single(char *data, const char *value) const { reinterpret_cast<string *>(data)->assign(value, N - 1); } | |
void contiguous(char *data, const char *const *values, size_t size) const | |
{ | |
for (size_t i = 0; i < size; ++i) { | |
single(data, values[i]); | |
data += sizeof(string); | |
} | |
} | |
}; | |
template <typename ContainerType, size_t Rank> | |
struct container_init { | |
typedef void (*closure_type)(const container_init *, char *, const ContainerType &); | |
typedef typename ContainerType::value_type value_type; | |
intptr_t stride; | |
closure_type closure; | |
init<value_type> child; | |
container_init(const ndt::type &tp, const char *metadata) | |
: child(tp.extended<ndt::base_dim_type>()->get_element_type(), | |
metadata + tp.extended<ndt::base_dim_type>()->get_element_arrmeta_offset()) | |
{ | |
switch (tp.get_id()) { | |
case fixed_dim_id: | |
stride = reinterpret_cast<const size_stride_t *>(metadata)->stride; | |
closure = [](const container_init *self, char *data, const ContainerType &values) { | |
for (const value_type &value : values) { | |
self->child.single(data, value); | |
data += self->stride; | |
} | |
}; | |
break; | |
default: | |
throw std::runtime_error("unsupported"); | |
} | |
} | |
void single(char *data, const ContainerType &values) const { closure(this, data, values); } | |
}; | |
template <typename ValueType> | |
struct container_init<std::initializer_list<ValueType>, 1> { | |
typedef void (*closure_type)(const container_init *, char *, const std::initializer_list<ValueType> &); | |
typedef ValueType value_type; | |
intrusive_ptr<memory_block_data> memblock; | |
closure_type closure; | |
init<value_type> child; | |
container_init(const ndt::type &tp, const char *metadata) | |
: child(tp.extended<ndt::base_dim_type>()->get_element_type(), metadata + sizeof(size_stride_t)) | |
{ | |
switch (tp.get_id()) { | |
case fixed_dim_id: | |
closure = [](const container_init *self, char *data, const std::initializer_list<ValueType> &values) { | |
self->child.contiguous(data, values.begin(), values.size()); | |
}; | |
break; | |
case var_dim_id: | |
memblock = reinterpret_cast<const ndt::var_dim_type::metadata_type *>(metadata)->blockref; | |
closure = [](const container_init *self, char *data, const std::initializer_list<ValueType> &values) { | |
reinterpret_cast<ndt::var_dim_type::data_type *>(data)->begin = self->memblock->alloc(values.size()); | |
reinterpret_cast<ndt::var_dim_type::data_type *>(data)->size = values.size(); | |
self->child.contiguous(reinterpret_cast<ndt::var_dim_type::data_type *>(data)->begin, values.begin(), | |
values.size()); | |
}; | |
break; | |
default: | |
throw std::runtime_error("unexpected type id"); | |
} | |
} | |
void single(char *data, const std::initializer_list<ValueType> &values) const { closure(this, data, values); } | |
}; | |
template <typename ContainerType> | |
struct container_init<ContainerType, 1> { | |
typedef typename ContainerType::value_type value_type; | |
void (*func)(const container_init *, char *, const ContainerType &); | |
init<value_type> child; | |
container_init(const ndt::type &tp, const char *metadata) | |
: child(tp.extended<ndt::base_dim_type>()->get_element_type(), metadata + sizeof(size_stride_t)) | |
{ | |
} | |
void single(char *data, const ContainerType &values) const { child.contiguous(data, values.data(), values.size()); } | |
}; | |
template <typename T> | |
struct init<std::initializer_list<T>> : container_init<std::initializer_list<T>, ndt::traits<T>::ndim + 1> { | |
using container_init<std::initializer_list<T>, ndt::traits<T>::ndim + 1>::container_init; | |
}; | |
template <typename T> | |
struct init<std::vector<T>> : container_init<std::vector<T>, ndt::traits<T>::ndim + 1> { | |
using container_init<std::vector<T>, ndt::traits<T>::ndim + 1>::container_init; | |
}; | |
} | |
} | |
namespace dynd { | |
namespace ndt { | |
class __declspec(dllimport) base_memory_type : public base_type { | |
protected: | |
type m_element_tp; | |
size_t m_storage_arrmeta_offset; | |
public: | |
base_memory_type(type_id_t type_id, const type &element_tp, size_t data_size, size_t alignment, | |
size_t storage_arrmeta_offset, uint32_t flags); | |
const type &get_element_type() const { return m_element_tp; } | |
virtual size_t get_default_data_size() const; | |
virtual void get_vars(std::unordered_set<std::string> &vars) const; | |
virtual void print_data(std::ostream &o, const char *arrmeta, const char *data) const; | |
void get_shape(intptr_t ndim, intptr_t i, intptr_t *out_shape, const char *arrmeta, const char *data) const; | |
void get_strides(size_t i, intptr_t *out_strides, const char *arrmeta) const; | |
type apply_linear_index(intptr_t nindices, const irange *indices, size_t current_i, const type &root_tp, | |
bool leading_dimension) const; | |
intptr_t apply_linear_index(intptr_t nindices, const irange *indices, const char *arrmeta, const type &result_type, | |
char *out_arrmeta, const intrusive_ptr<memory_block_data> &embedded_reference, | |
size_t current_i, const type &root_tp, bool leading_dimension, char **inout_data, | |
intrusive_ptr<memory_block_data> &inout_dataref) const; | |
type at_single(intptr_t i0, const char **inout_arrmeta, const char **inout_data) const; | |
type get_type_at_dimension(char **inout_arrmeta, intptr_t i, intptr_t total_ndim = 0) const; | |
virtual bool is_lossless_assignment(const type &dst_tp, const type &src_tp) const; | |
virtual bool operator==(const base_type &rhs) const = 0; | |
inline bool is_type_subarray(const type &subarray_tp) const | |
{ | |
return (!subarray_tp.is_builtin() && (*this) == (*subarray_tp.extended())) || | |
m_element_tp.is_type_subarray(subarray_tp); | |
} | |
virtual void transform_child_types(type_transform_fn_t transform_fn, intptr_t arrmeta_offset, void *extra, | |
type &out_transformed_tp, bool &out_was_transformed) const; | |
virtual type get_canonical_type() const; | |
virtual type with_replaced_storage_type(const type &storage_tp) const = 0; | |
virtual void arrmeta_default_construct(char *arrmeta, bool blockref_alloc) const; | |
virtual void arrmeta_copy_construct(char *dst_arrmeta, const char *src_arrmeta, | |
const intrusive_ptr<memory_block_data> &embedded_reference) const; | |
virtual void arrmeta_destruct(char *arrmeta) const; | |
virtual void data_alloc(char **data, size_t size) const = 0; | |
virtual void data_zeroinit(char *data, size_t size) const = 0; | |
virtual void data_free(char *data) const = 0; | |
virtual bool match(const type &candidate_tp, std::map<std::string, type> &tp_vars) const; | |
virtual std::map<std::string, std::pair<ndt::type, const char *>> get_dynamic_type_properties() const; | |
}; | |
} | |
} | |
namespace dynd { | |
struct __declspec(dllimport) array_preamble : memory_block_data { | |
ndt::type tp; | |
uint64_t flags; | |
char *data; | |
intrusive_ptr<memory_block_data> owner; | |
~array_preamble() | |
{ | |
if (!tp.is_builtin()) { | |
char *arrmeta = reinterpret_cast<char *>(this + 1); | |
if (!owner) { | |
if (!tp->is_expression() && (tp->get_flags() & type_flag_destructor) != 0) { | |
tp->data_destruct(arrmeta, data); | |
} | |
if (!tp->is_expression()) { | |
const ndt::type &dtp = tp->get_type_at_dimension(0, tp->get_ndim()); | |
if (dtp.get_base_id() == memory_id) { | |
dtp.extended<ndt::base_memory_type>()->data_free(data); | |
} | |
} | |
} | |
tp->arrmeta_destruct(arrmeta); | |
} | |
} | |
char *metadata() { return reinterpret_cast<char *>(this + 1); } | |
const char *metadata() const { return reinterpret_cast<const char *>(this + 1); } | |
}; | |
__declspec(dllimport) intrusive_ptr<memory_block_data> make_array_memory_block(size_t arrmeta_size); | |
__declspec(dllimport) intrusive_ptr<memory_block_data> make_array_memory_block(size_t arrmeta_size, size_t extra_size, | |
size_t extra_alignment, char **out_extra_ptr); | |
__declspec(dllimport) intrusive_ptr<memory_block_data> shallow_copy_array_memory_block(const intrusive_ptr<memory_block_data> &ndo); | |
__declspec(dllimport) void array_memory_block_debug_print(const memory_block_data *memblock, std::ostream &o, | |
const std::string &indent); | |
inline long intrusive_ptr_use_count(array_preamble *ptr) { return ptr->m_use_count; } | |
inline void intrusive_ptr_retain(array_preamble *ptr) { ++ptr->m_use_count; } | |
inline void intrusive_ptr_release(array_preamble *ptr) | |
{ | |
if (--ptr->m_use_count == 0) { | |
detail::memory_block_free(ptr); | |
} | |
} | |
} | |
namespace dynd { | |
template<class T, int staticN = 3> | |
class shortvector { | |
T *m_data; | |
T m_shortdata[staticN]; | |
shortvector(const shortvector& rhs); | |
shortvector& operator=(const shortvector& rhs); | |
public: | |
shortvector() | |
: m_data(m_shortdata) { | |
} | |
void init(size_t size) { | |
if (m_data != m_shortdata) { | |
delete[] m_data; | |
} | |
if (size <= staticN) { | |
m_data = m_shortdata; | |
} else { | |
m_data = new T[size]; | |
} | |
} | |
void init(size_t size, const T *data) { | |
init(size); | |
memcpy(m_data, data, size * sizeof(T)); | |
} | |
explicit shortvector(size_t size) | |
: m_data((size <= staticN) ? m_shortdata : new T[size]) | |
{ | |
} | |
shortvector(size_t size, const shortvector& rhs) | |
: m_data((size <= staticN) ? m_shortdata : new T[size]) | |
{ | |
std::memcpy(m_data, rhs.m_data, size * sizeof(T)); | |
} | |
shortvector(size_t size, const T* data) | |
: m_data((size <= staticN) ? m_shortdata : new T[size]) | |
{ | |
std::memcpy(m_data, data, size * sizeof(T)); | |
} | |
shortvector(shortvector&& rhs) { | |
if (rhs.m_data == rhs.m_shortdata) { | |
std::memcpy(m_shortdata, rhs.m_shortdata, staticN * sizeof(T)); | |
m_data = m_shortdata; | |
} else { | |
m_data = rhs.m_data; | |
rhs.m_data = rhs.m_shortdata; | |
} | |
} | |
shortvector& operator=(shortvector&& rhs) { | |
if (this != &rhs) { | |
if (m_data != m_shortdata) { | |
delete[] m_data; | |
} | |
if (rhs.m_data == rhs.m_shortdata) { | |
std::memcpy(m_shortdata, rhs.m_shortdata, staticN * sizeof(T)); | |
m_data = m_shortdata; | |
} else { | |
m_data = rhs.m_data; | |
rhs.m_data = rhs.m_shortdata; | |
} | |
} | |
return *this; | |
} | |
~shortvector() { | |
if (m_data != m_shortdata) { | |
delete[] m_data; | |
} | |
} | |
void swap(shortvector& rhs) { | |
std::swap(m_data, rhs.m_data); | |
if (m_data == rhs.m_shortdata) { | |
m_data = m_shortdata; | |
if (rhs.m_data == m_shortdata) { | |
T tmp[staticN]; | |
rhs.m_data = rhs.m_shortdata; | |
std::memcpy(tmp, m_shortdata, staticN * sizeof(T)); | |
std::memcpy(m_shortdata, rhs.m_shortdata, staticN * sizeof(T)); | |
std::memcpy(rhs.m_shortdata, tmp, staticN * sizeof(T)); | |
} else { | |
std::memcpy(m_shortdata, rhs.m_shortdata, staticN * sizeof(T)); | |
} | |
} else if (rhs.m_data == m_shortdata) { | |
rhs.m_data = rhs.m_shortdata; | |
std::memcpy(rhs.m_shortdata, m_shortdata, staticN * sizeof(T)); | |
} | |
} | |
const T* get() const { | |
return m_data; | |
} | |
T* get() { | |
return m_data; | |
} | |
const T& operator[](size_t i) const { | |
return m_data[i]; | |
} | |
T& operator[](size_t i) { | |
return m_data[i]; | |
} | |
}; | |
template<class T, int M, int staticN = 3> | |
class multi_shortvector { | |
T *m_shortvectors[M]; | |
T m_static_data[staticN * M]; | |
T *m_alloc_data; | |
void internal_init(int n) { | |
if (n <= staticN) { | |
if (n == 0) { | |
n = 1; | |
} | |
for (int i = 0; i < M; ++i) { | |
m_shortvectors[i] = &m_static_data[i*n]; | |
} | |
} else { | |
m_alloc_data = new T[n * M]; | |
for (int i = 0; i < M; ++i) { | |
m_shortvectors[i] = m_alloc_data + i*n; | |
} | |
} | |
} | |
multi_shortvector(const multi_shortvector&); | |
multi_shortvector& operator=(const multi_shortvector&); | |
public: | |
multi_shortvector() | |
: m_alloc_data(0) { | |
} | |
multi_shortvector(int n) | |
: m_alloc_data(0) { | |
internal_init(n); | |
} | |
~multi_shortvector() { | |
delete[] m_alloc_data; | |
} | |
void init(int n) { | |
if (m_alloc_data != 0) { | |
delete[] m_alloc_data; | |
} | |
internal_init(n); | |
} | |
T **get_all() { | |
return m_shortvectors; | |
} | |
const T * const*get_all() const { | |
return m_shortvectors; | |
} | |
T *get(int i) { | |
return m_shortvectors[i]; | |
} | |
const T *get(int i) const { | |
return m_shortvectors[i]; | |
} | |
T& get(int i, int j) { | |
return m_shortvectors[i][j]; | |
} | |
const T& get(int i, int j) const { | |
return m_shortvectors[i][j]; | |
} | |
}; | |
typedef shortvector<intptr_t> dimvector; | |
} | |
namespace dynd { | |
namespace ndt { | |
class __declspec(dllimport) base_bytes_type : public base_type { | |
public: | |
base_bytes_type(type_id_t type_id, size_t data_size, size_t alignment, uint32_t flags, size_t arrmeta_size) | |
: base_type(type_id, data_size, alignment, flags, arrmeta_size, 0, 0) | |
{ | |
} | |
virtual void get_bytes_range(const char **out_begin, const char **out_end, const char *arrmeta, | |
const char *data) const = 0; | |
size_t get_iterdata_size(intptr_t ndim) const; | |
}; | |
} | |
} | |
namespace dynd { | |
namespace ndt { | |
class __declspec(dllimport) bytes_type : public base_bytes_type { | |
size_t m_alignment; | |
public: | |
typedef bytes data_type; | |
bytes_type(size_t alignment); | |
size_t get_target_alignment() const { return m_alignment; } | |
void print_data(std::ostream &o, const char *arrmeta, const char *data) const; | |
void print_type(std::ostream &o) const; | |
void get_bytes_range(const char **out_begin, const char **out_end, const char *arrmeta, const char *data) const; | |
void set_bytes_data(const char *arrmeta, char *data, const char *bytes_begin, const char *bytes_end) const; | |
bool is_unique_data_owner(const char *arrmeta) const; | |
type get_canonical_type() const; | |
void get_shape(intptr_t ndim, intptr_t i, intptr_t *out_shape, const char *arrmeta, const char *data) const; | |
bool is_lossless_assignment(const type &dst_tp, const type &src_tp) const; | |
bool operator==(const base_type &rhs) const; | |
void data_destruct(const char *arrmeta, char *data) const; | |
void data_destruct_strided(const char *arrmeta, char *data, intptr_t stride, size_t count) const; | |
std::map<std::string, std::pair<ndt::type, const char *>> get_dynamic_type_properties() const; | |
static const type &make() | |
{ | |
static const type bytes_tp(new bytes_type(1), false); | |
return *reinterpret_cast<const type *>(&bytes_tp); | |
} | |
static type make(size_t alignment) { return type(new bytes_type(alignment), false); } | |
}; | |
template <> | |
struct traits<bytes> { | |
static const size_t ndim = 0; | |
static const bool is_same_layout = true; | |
static type equivalent() { return type(bytes_id); } | |
static bytes na() { return bytes(); } | |
}; | |
} | |
} | |
namespace dynd { | |
struct __declspec(dllimport) pointer_type_arrmeta { | |
intrusive_ptr<memory_block_data> blockref; | |
intptr_t offset; | |
}; | |
namespace ndt { | |
class __declspec(dllimport) pointer_type : public base_type { | |
type m_target_tp; | |
public: | |
pointer_type(const type &target_tp); | |
const type &get_value_type() const { return m_target_tp.value_type(); } | |
const type &get_operand_type() const; | |
const type &get_target_type() const { return m_target_tp; } | |
void print_data(std::ostream &o, const char *arrmeta, const char *data) const; | |
void print_type(std::ostream &o) const; | |
inline bool is_type_subarray(const type &subarray_tp) const | |
{ | |
return (!subarray_tp.is_builtin() && (*this) == (*subarray_tp.extended())) || | |
m_target_tp.is_type_subarray(subarray_tp); | |
} | |
bool is_unique_data_owner(const char *arrmeta) const; | |
void transform_child_types(type_transform_fn_t transform_fn, intptr_t arrmeta_offset, void *extra, | |
type &out_transformed_tp, bool &out_was_transformed) const; | |
type get_canonical_type() const; | |
type apply_linear_index(intptr_t nindices, const irange *indices, size_t current_i, const type &root_tp, | |
bool leading_dimension) const; | |
intptr_t apply_linear_index(intptr_t nindices, const irange *indices, const char *arrmeta, const type &result_tp, | |
char *out_arrmeta, const intrusive_ptr<memory_block_data> &embedded_reference, | |
size_t current_i, const type &root_tp, bool leading_dimension, char **inout_data, | |
intrusive_ptr<memory_block_data> &inout_dataref) const; | |
type at_single(intptr_t i0, const char **inout_arrmeta, const char **inout_data) const; | |
type get_type_at_dimension(char **inout_arrmeta, intptr_t i, intptr_t total_ndim = 0) const; | |
void get_shape(intptr_t ndim, intptr_t i, intptr_t *out_shape, const char *arrmeta, const char *data) const; | |
axis_order_classification_t classify_axis_order(const char *arrmeta) const; | |
bool is_lossless_assignment(const type &dst_tp, const type &src_tp) const; | |
bool operator==(const base_type &rhs) const; | |
type with_replaced_storage_type(const type &replacement_type) const; | |
void arrmeta_default_construct(char *arrmeta, bool blockref_alloc) const; | |
void arrmeta_copy_construct(char *dst_arrmeta, const char *src_arrmeta, | |
const intrusive_ptr<memory_block_data> &embedded_reference) const; | |
void arrmeta_reset_buffers(char *arrmeta) const; | |
void arrmeta_finalize_buffers(char *arrmeta) const; | |
void arrmeta_destruct(char *arrmeta) const; | |
void arrmeta_debug_print(const char *arrmeta, std::ostream &o, const std::string &indent) const; | |
bool match(const type &candidate_tp, std::map<std::string, type> &tp_vars) const; | |
std::map<std::string, std::pair<ndt::type, const char *>> get_dynamic_type_properties() const; | |
static type make(const type &target_tp); | |
}; | |
template <typename T> | |
struct traits<T *> { | |
static const size_t ndim = 0; | |
static const bool is_same_layout = true; | |
static type equivalent() { return pointer_type::make(make_type<T>()); } | |
}; | |
inline type make_pointer_type(const type &target_tp) { return pointer_type::make(target_tp); } | |
} | |
} | |
namespace dynd { | |
namespace ndt { | |
class __declspec(dllimport) type_type : public base_type { | |
type m_pattern_tp; | |
public: | |
typedef type data_type; | |
type_type(); | |
type_type(const type &pattern_tp); | |
const type &get_pattern_type() const { return m_pattern_tp; } | |
void print_data(std::ostream &o, const char *arrmeta, const char *data) const; | |
void print_type(std::ostream &o) const; | |
bool operator==(const base_type &rhs) const; | |
void arrmeta_default_construct(char *arrmeta, bool blockref_alloc) const; | |
void arrmeta_copy_construct(char *dst_arrmeta, const char *src_arrmeta, | |
const intrusive_ptr<memory_block_data> &embedded_reference) const; | |
void arrmeta_reset_buffers(char *arrmeta) const; | |
void arrmeta_finalize_buffers(char *arrmeta) const; | |
void arrmeta_destruct(char *arrmeta) const; | |
void arrmeta_debug_print(const char *, std::ostream &, | |
const std::string &) const | |
{ | |
} | |
void data_destruct(const char *arrmeta, char *data) const; | |
void data_destruct_strided(const char *arrmeta, char *data, intptr_t stride, size_t count) const; | |
}; | |
} | |
} | |
namespace dynd { | |
namespace ndt { | |
__declspec(dllimport) type make_fixed_dim(size_t dim_size, const type &element_tp); | |
} | |
namespace nd { | |
class callable; | |
__declspec(dllexport) callable ®(const std::string &name); | |
class __declspec(dllexport) array; | |
__declspec(dllexport) array empty(const ndt::type &tp); | |
enum array_access_flags { | |
read_access_flag = 0x01, | |
write_access_flag = 0x02, | |
immutable_access_flag = 0x04 | |
}; | |
enum { | |
readwrite_access_flags = read_access_flag | write_access_flag, | |
default_access_flags = read_access_flag | write_access_flag, | |
}; | |
__declspec(dllexport) std::ostream &operator<<(std::ostream &o, const array &rhs); | |
class array_vals; | |
class array_vals_at; | |
namespace detail { | |
template <typename CArrayType, bool IsTriviallyCopyable> | |
struct init_from_c_array; | |
template <typename ValueType, size_t Size> | |
struct init_from_c_array<ValueType[Size], true> { | |
nd::init<ValueType> child; | |
intptr_t stride; | |
init_from_c_array(const ndt::type &tp, const char *metadata) | |
: child(tp.extended<ndt::base_dim_type>()->get_element_type(), metadata + sizeof(size_stride_t)), | |
stride(reinterpret_cast<const size_stride_t *>(metadata)->stride) | |
{ | |
} | |
void single(char *data, const ValueType (&values)[Size]) const | |
{ | |
for (const ValueType &value : values) { | |
child.single(data, value); | |
data += stride; | |
} | |
} | |
}; | |
template <typename ValueType, size_t Size> | |
struct init_from_c_array<ValueType[Size], false> { | |
nd::init<ValueType> child; | |
intptr_t stride; | |
init_from_c_array(const ndt::type &tp, const char *metadata) | |
: child(tp.extended<ndt::base_dim_type>()->get_element_type(), metadata + sizeof(size_stride_t)), | |
stride(reinterpret_cast<const size_stride_t *>(metadata)->stride) | |
{ | |
} | |
void single(char *data, const ValueType (&values)[Size]) const | |
{ | |
for (const ValueType &value : values) { | |
child.single(data, value); | |
data += stride; | |
} | |
} | |
}; | |
} | |
template <typename ValueType, size_t Size> | |
struct init<ValueType[Size]> | |
: detail::init_from_c_array<ValueType[Size], | |
std::is_pod<ValueType>::value && ndt::traits<ValueType>::is_same_layout> { | |
using detail::init_from_c_array<ValueType[Size], std::is_pod<ValueType>::value && | |
ndt::traits<ValueType>::is_same_layout>::init_from_c_array; | |
}; | |
template <typename ValueType> | |
struct as { | |
void single(ValueType &value, char *data) const { value = *reinterpret_cast<ValueType *>(data); } | |
}; | |
template <> | |
struct as<std::string> { | |
void single(std::string &value, char *data) const | |
{ | |
value.assign(reinterpret_cast<string *>(data)->data(), reinterpret_cast<string *>(data)->size()); | |
} | |
}; | |
class __declspec(dllexport) array : public intrusive_ptr<array_preamble> { | |
template <typename T> | |
void init(T &&value) | |
{ | |
nd::init<typename remove_reference_then_cv<T>::type> init(get()->tp, get()->metadata()); | |
init.single(get()->data, std::forward<T>(value)); | |
get()->flags = | |
(get()->tp.get_ndim() == 0) ? (nd::read_access_flag | nd::immutable_access_flag) : nd::readwrite_access_flags; | |
} | |
template <typename ValueType> | |
void init(const ValueType *values, size_t size) | |
{ | |
nd::init<ValueType> init(get()->tp, get()->metadata()); | |
init.contiguous(get()->data, values, size); | |
get()->flags = | |
(get()->tp.get_ndim() == 0) ? (nd::read_access_flag | nd::immutable_access_flag) : nd::readwrite_access_flags; | |
} | |
public: | |
using intrusive_ptr<array_preamble>::intrusive_ptr; | |
array() = default; | |
template <typename T, | |
typename = std::enable_if_t<ndt::has_traits<typename remove_reference_then_cv<T>::type>::value>> | |
array(T &&value) : intrusive_ptr<array_preamble>(empty(ndt::type_for(value))) | |
{ | |
init(std::forward<T>(value)); | |
} | |
template <typename ValueType> | |
array(const std::initializer_list<ValueType> &values) : intrusive_ptr<array_preamble>(empty(ndt::type_for(values))) | |
{ | |
init(values); | |
} | |
template <typename ValueType> | |
array(const std::initializer_list<std::initializer_list<ValueType>> &values) | |
: intrusive_ptr<array_preamble>(empty(ndt::type_for(values))) | |
{ | |
init(values); | |
} | |
template <typename ValueType> | |
array(const std::initializer_list<std::initializer_list<std::initializer_list<ValueType>>> &values) | |
: intrusive_ptr<array_preamble>(empty(ndt::type_for(values))) | |
{ | |
init(values); | |
} | |
template <typename ValueType> | |
array(const ValueType *values, size_t size) | |
: intrusive_ptr<array_preamble>(empty(ndt::make_fixed_dim(size, ndt::make_type<ValueType>()))) | |
{ | |
init(values, size); | |
} | |
inline bool is_null() const { return intrusive_ptr<array_preamble>::get() == 0; } | |
char *data() const | |
{ | |
if (get()->flags & write_access_flag) { | |
return get()->data; | |
} | |
throw std::runtime_error("tried to write to a dynd array that is not writable"); | |
} | |
const char *cdata() const { return get()->data; } | |
inline uint32_t get_access_flags() const | |
{ | |
return get()->flags & (immutable_access_flag | read_access_flag | write_access_flag); | |
} | |
inline bool is_immutable() const { return (get()->flags & immutable_access_flag) != 0; } | |
inline bool is_scalar() const { return get_type().is_scalar(); } | |
const ndt::type &get_type() const { return *reinterpret_cast<const ndt::type *>(&get()->tp); } | |
inline intptr_t get_ndim() const | |
{ | |
if (get()->tp.is_builtin()) { | |
return 0; | |
} | |
else { | |
return get()->tp->get_ndim(); | |
} | |
} | |
inline ndt::type get_dtype() const | |
{ | |
size_t ndim = get()->tp.get_ndim(); | |
if (ndim == 0) { | |
return get()->tp; | |
} | |
return get()->tp->get_type_at_dimension(0, ndim); | |
} | |
inline ndt::type get_dtype(size_t include_ndim) const | |
{ | |
if (get()->tp.is_builtin()) { | |
if (include_ndim > 0) { | |
throw too_many_indices(get_type(), include_ndim, 0); | |
} | |
return ndt::type(get()->tp.get_id()); | |
} | |
else { | |
size_t ndim = get()->tp->get_ndim(); | |
if (ndim < include_ndim) { | |
throw too_many_indices(get_type(), include_ndim, ndim); | |
} | |
ndim -= include_ndim; | |
if (ndim == 0) { | |
return get()->tp; | |
} | |
else { | |
return get()->tp->get_type_at_dimension(0, ndim); | |
} | |
} | |
} | |
void flag_as_immutable(); | |
inline uint64_t get_flags() const { return get()->flags; } | |
inline std::vector<intptr_t> get_shape() const | |
{ | |
std::vector<intptr_t> result(get_ndim()); | |
get_shape(&result[0]); | |
return result; | |
} | |
inline void get_shape(intptr_t *out_shape) const | |
{ | |
if (!get()->tp.is_builtin() && get()->tp->get_ndim() > 0) { | |
get()->tp->get_shape(get()->tp->get_ndim(), 0, out_shape, get()->metadata(), get()->data); | |
} | |
} | |
inline intptr_t get_dim_size() const { return get_type().get_dim_size(get()->metadata(), get()->data); } | |
inline intptr_t get_dim_size(intptr_t i) const | |
{ | |
if (0 <= i && i < get_type().get_strided_ndim()) { | |
const size_stride_t *ss = reinterpret_cast<const size_stride_t *>(get()->metadata()); | |
return ss[i].dim_size; | |
} | |
else if (0 <= i && i < get_ndim()) { | |
dimvector shape(i + 1); | |
get()->tp->get_shape(i + 1, 0, shape.get(), get()->metadata(), get()->data); | |
return shape[i]; | |
} | |
else { | |
std::stringstream ss; | |
ss << "Not enough dimensions in array, tried to access axis " << i << " for type " << get_type(); | |
throw std::invalid_argument(ss.str()); | |
} | |
} | |
std::vector<intptr_t> get_strides() const | |
{ | |
std::vector<intptr_t> result(get_ndim()); | |
get_strides(&result[0]); | |
return result; | |
} | |
inline void get_strides(intptr_t *out_strides) const | |
{ | |
if (!get()->tp.is_builtin()) { | |
get()->tp->get_strides(0, out_strides, get()->metadata()); | |
} | |
} | |
inline intrusive_ptr<memory_block_data> get_data_memblock() const | |
{ | |
if (get()->owner) { | |
return get()->owner; | |
} | |
else { | |
return intrusive_ptr<memory_block_data>(get(), true); | |
} | |
} | |
array p(const char *name) const; | |
array p(const std::string &name) const; | |
static nd::array from_type_property(const std::pair<ndt::type, const char *> &pair); | |
template <typename... ArgTypes> | |
array f(const char *name, ArgTypes &&... args) const | |
{ | |
callable &f = reg(name); | |
return f(*this, std::forward<ArgTypes>(args)...); | |
} | |
array &operator+=(const array &rhs); | |
array &operator-=(const array &rhs); | |
array &operator*=(const array &rhs); | |
array &operator/=(const array &rhs); | |
array_vals vals() const; | |
array_vals_at vals_at(const irange &i0) const; | |
array_vals_at vals_at(const irange &i0, const irange &i1) const; | |
array_vals_at vals_at(const irange &i0, const irange &i1, const irange &i2) const; | |
array_vals_at vals_at(const irange &i0, const irange &i1, const irange &i2, const irange &i3) const; | |
array eval() const; | |
array eval_immutable() const; | |
array eval_copy(uint32_t access_flags = 0) const; | |
array storage() const; | |
array at_array(intptr_t nindices, const irange *indices, bool collapse_leading = true) const; | |
array operator()(const irange &i0) const { return at_array(1, &i0); } | |
array operator()(const irange &i0, const irange &i1) const | |
{ | |
irange i[2] = {i0, i1}; | |
return at_array(2, i); | |
} | |
array operator()(const irange &i0, const irange &i1, const irange &i2) const | |
{ | |
irange i[3] = {i0, i1, i2}; | |
return at_array(3, i); | |
} | |
array operator()(const irange &i0, const irange &i1, const irange &i2, const irange &i3) const | |
{ | |
irange i[4] = {i0, i1, i2, i3}; | |
return at_array(4, i); | |
} | |
array operator()(const irange &i0, const irange &i1, const irange &i2, const irange &i3, const irange &i4) const | |
{ | |
irange i[5] = {i0, i1, i2, i3, i4}; | |
return at_array(5, i); | |
} | |
array at(const irange &i0) const { return at_array(1, &i0); } | |
array assign(const array &rhs, assign_error_mode error_mode = assign_error_fractional) const; | |
array assign_na() const; | |
array cast(const ndt::type &tp) const; | |
array ucast(const ndt::type &uniform_dt, intptr_t replace_ndim = 0) const; | |
template <class T> | |
inline array ucast(intptr_t replace_ndim = 0) const | |
{ | |
return ucast(ndt::make_type<T>(), replace_ndim); | |
} | |
array view(const ndt::type &tp) const; | |
template <int N> | |
inline array view(const char (&rhs)[N]) | |
{ | |
return view(ndt::type(rhs)); | |
} | |
template <typename T> | |
typename std::enable_if<ndt::traits<T>::is_same_layout, T>::type view() const | |
{ | |
return *reinterpret_cast<const T *>(cdata()); | |
} | |
template <typename T> | |
typename std::enable_if<!ndt::traits<T>::is_same_layout, T>::type view() | |
{ | |
return T(get()->metadata(), data()); | |
} | |
array uview(const ndt::type &uniform_dt, intptr_t replace_ndim) const; | |
array permute(intptr_t ndim, const intptr_t *axes) const; | |
array rotate(intptr_t to, intptr_t from = 0) const; | |
array rotate(intptr_t from = 0) const { return rotate(get_ndim() - 1, from); } | |
array transpose() const; | |
array view_scalars(const ndt::type &scalar_tp) const; | |
array replace_dtype(const ndt::type &replacement_tp, intptr_t replace_ndim = 0) const; | |
array new_axis(intptr_t i, intptr_t new_ndim = 1) const; | |
template <class T> | |
array view_scalars() const | |
{ | |
return view_scalars(ndt::make_type<T>()); | |
} | |
template <typename ValueType> | |
ValueType as(assign_error_mode error_mode = assign_error_fractional) const | |
{ | |
ValueType value; | |
nd::as<ValueType> as; | |
ndt::type tp = ndt::make_type<ValueType>(); | |
if (tp == get()->tp) { | |
as.single(value, get()->data); | |
} | |
else { | |
array a = empty(tp); | |
a.assign(*this, error_mode); | |
as.single(value, a.get()->data); | |
} | |
return value; | |
} | |
array to_host() const; | |
bool is_na() const; | |
bool equals_exact(const array &rhs) const; | |
void debug_print(std::ostream &o, const std::string &indent = "") const; | |
friend __declspec(dllexport) std::ostream &operator<<(std::ostream &o, const array &rhs); | |
friend class array_vals; | |
friend class array_vals_at; | |
}; | |
__declspec(dllexport) array as_struct(size_t size, const std::pair<const char *, array> *pairs); | |
inline array as_struct(const std::initializer_list<std::pair<const char *, array>> &pairs) | |
{ | |
return as_struct(pairs.size(), pairs.begin()); | |
} | |
__declspec(dllexport) array operator+(const array &a0); | |
__declspec(dllexport) array operator-(const array &a0); | |
__declspec(dllexport) array operator!(const array &a0); | |
__declspec(dllexport) array operator~(const array &a0); | |
__declspec(dllexport) array operator+(const array &op0, const array &op1); | |
__declspec(dllexport) array operator-(const array &op0, const array &op1); | |
__declspec(dllexport) array operator/(const array &op0, const array &op1); | |
__declspec(dllexport) array operator*(const array &op0, const array &op1); | |
__declspec(dllexport) array operator&&(const array &a0, const array &a1); | |
__declspec(dllexport) array operator||(const array &a0, const array &a1); | |
__declspec(dllexport) array operator<(const array &a0, const array &a1); | |
__declspec(dllexport) array operator<=(const array &a0, const array &a1); | |
__declspec(dllexport) array operator==(const array &a0, const array &a1); | |
__declspec(dllexport) array operator!=(const array &a0, const array &a1); | |
__declspec(dllexport) array operator>=(const array &a0, const array &a1); | |
__declspec(dllexport) array operator>(const array &a0, const array &a1); | |
class __declspec(dllexport) array_vals { | |
const array &m_arr; | |
array_vals(const array &arr) : m_arr(arr) {} | |
array_vals(const array_vals &); | |
array_vals &operator=(const array_vals &); | |
public: | |
array_vals &operator=(const array &rhs) | |
{ | |
m_arr.assign(rhs); | |
return *this; | |
} | |
template <class T> | |
typename std::enable_if<is_dynd_scalar<T>::value, array_vals &>::type operator=(const T &rhs) | |
{ | |
m_arr.assign(rhs); | |
return *this; | |
} | |
friend class array; | |
friend array_vals array::vals() const; | |
}; | |
class __declspec(dllexport) array_vals_at { | |
array m_arr; | |
array_vals_at(const array &arr) : m_arr(arr) {} | |
array_vals_at(array &&arr) : m_arr(std::move(arr)) {} | |
array_vals_at(const array_vals &); | |
array_vals_at &operator=(const array_vals_at &); | |
public: | |
array_vals_at &operator=(const array &rhs) | |
{ | |
m_arr.assign(rhs); | |
return *this; | |
} | |
template <class T> | |
typename std::enable_if<is_dynd_scalar<T>::value, array_vals_at &>::type operator=(const T &rhs) | |
{ | |
m_arr.assign(rhs); | |
return *this; | |
} | |
friend class array; | |
friend array_vals_at array::vals_at(const irange &) const; | |
friend array_vals_at array::vals_at(const irange &, const irange &) const; | |
friend array_vals_at array::vals_at(const irange &, const irange &, const irange &) const; | |
friend array_vals_at array::vals_at(const irange &, const irange &, const irange &, const irange &) const; | |
}; | |
__declspec(dllexport) array make_strided_array_from_data(const ndt::type &uniform_dtype, intptr_t ndim, const intptr_t *shape, | |
const intptr_t *strides, int64_t access_flags, char *data_ptr, | |
const intrusive_ptr<memory_block_data> &data_reference, | |
char **out_uniform_arrmeta = 0); | |
inline array_vals array::vals() const { return array_vals(*this); } | |
inline array_vals_at array::vals_at(const irange &i0) const { return array_vals_at(at_array(1, &i0, false)); } | |
inline array_vals_at array::vals_at(const irange &i0, const irange &i1) const | |
{ | |
irange i[2] = {i0, i1}; | |
return array_vals_at(at_array(2, i, false)); | |
} | |
inline array_vals_at array::vals_at(const irange &i0, const irange &i1, const irange &i2) const | |
{ | |
irange i[3] = {i0, i1, i2}; | |
return array_vals_at(at_array(3, i, false)); | |
} | |
inline array_vals_at array::vals_at(const irange &i0, const irange &i1, const irange &i2, const irange &i3) const | |
{ | |
irange i[4] = {i0, i1, i2, i3}; | |
return array_vals_at(at_array(4, i, false)); | |
} | |
__declspec(dllexport) array empty_shell(const ndt::type &tp); | |
inline array dtyped_empty(intptr_t ndim, const intptr_t *shape, const ndt::type &tp) | |
{ | |
if (ndim > 0) { | |
intptr_t i = ndim - 1; | |
ndt::type rtp = shape[i] >= 0 ? ndt::make_fixed_dim(shape[i], tp) : ndt::var_dim_type::make(tp); | |
while (i-- > 0) { | |
rtp = shape[i] >= 0 ? ndt::make_fixed_dim(shape[i], rtp) : ndt::var_dim_type::make(rtp); | |
} | |
return empty(rtp); | |
} | |
else { | |
return empty(tp); | |
} | |
} | |
inline array dtyped_empty(const std::vector<intptr_t> &shape, const ndt::type &tp) | |
{ | |
return dtyped_empty(shape.size(), shape.empty() ? 0 : &shape[0], tp); | |
} | |
template <int N> | |
inline array empty(const char (&dshape)[N]) | |
{ | |
return nd::empty(ndt::type(dshape, dshape + N - 1)); | |
} | |
inline array empty(intptr_t dim0, const ndt::type &tp) | |
{ | |
return nd::empty(dim0 >= 0 ? ndt::make_fixed_dim(dim0, tp) : ndt::var_dim_type::make(tp)); | |
} | |
template <int N> | |
inline array empty(intptr_t dim0, const char (&dshape)[N]) | |
{ | |
return empty(dim0, ndt::type(dshape, dshape + N - 1)); | |
} | |
inline array empty(intptr_t dim0, intptr_t dim1, const ndt::type &tp) | |
{ | |
ndt::type rtp = (dim1 >= 0) ? ndt::make_fixed_dim(dim1, tp) : ndt::var_dim_type::make(tp); | |
rtp = (dim0 >= 0) ? ndt::make_fixed_dim(dim0, rtp) : ndt::var_dim_type::make(rtp); | |
return nd::empty(rtp); | |
} | |
template <int N> | |
inline array empty(intptr_t dim0, intptr_t dim1, const char (&dshape)[N]) | |
{ | |
return empty(dim0, dim1, ndt::type(dshape, dshape + N - 1)); | |
} | |
inline array empty(intptr_t dim0, intptr_t dim1, intptr_t dim2, const ndt::type &tp) | |
{ | |
ndt::type rtp = (dim2 >= 0) ? ndt::make_fixed_dim(dim2, tp) : ndt::var_dim_type::make(tp); | |
rtp = (dim1 >= 0) ? ndt::make_fixed_dim(dim1, rtp) : ndt::var_dim_type::make(rtp); | |
rtp = (dim0 >= 0) ? ndt::make_fixed_dim(dim0, rtp) : ndt::var_dim_type::make(rtp); | |
return empty(rtp); | |
} | |
template <int N> | |
inline array empty(intptr_t dim0, intptr_t dim1, intptr_t dim2, const char (&dshape)[N]) | |
{ | |
return empty(dim0, dim1, dim2, ndt::type(dshape, dshape + N - 1)); | |
} | |
__declspec(dllexport) array empty_like(const array &rhs, const ndt::type &uniform_dtype); | |
__declspec(dllexport) array empty_like(const array &rhs); | |
inline array dtyped_zeros(intptr_t ndim, const intptr_t *shape, const ndt::type &tp) | |
{ | |
nd::array res = dtyped_empty(ndim, shape, tp); | |
res.assign(0); | |
return res; | |
} | |
inline array zeros(intptr_t dim0, const ndt::type &tp) | |
{ | |
intptr_t shape[1] = {dim0}; | |
return dtyped_zeros(1, shape, tp); | |
} | |
inline array zeros(intptr_t dim0, intptr_t dim1, const ndt::type &tp) | |
{ | |
intptr_t shape[2] = {dim0, dim1}; | |
return dtyped_zeros(2, shape, tp); | |
} | |
__declspec(dllexport) array typed_ones(intptr_t ndim, const intptr_t *shape, const ndt::type &tp); | |
inline array ones(const std::vector<intptr_t> &shape, const ndt::type &tp) | |
{ | |
return typed_ones(shape.size(), shape.empty() ? 0 : &shape[0], tp); | |
} | |
inline array dtyped_ones(intptr_t ndim, const intptr_t *shape, const ndt::type &tp) | |
{ | |
nd::array res = dtyped_empty(ndim, shape, tp); | |
res.assign(1); | |
return res; | |
} | |
inline array ones(intptr_t dim0, const ndt::type &tp) | |
{ | |
intptr_t shape[1] = {dim0}; | |
return dtyped_ones(1, shape, tp); | |
} | |
inline array ones(intptr_t dim0, intptr_t dim1, const ndt::type &tp) | |
{ | |
intptr_t shape[2] = {dim0, dim1}; | |
return dtyped_ones(2, shape, tp); | |
} | |
__declspec(dllexport) array concatenate(const nd::array &x, const nd::array &y); | |
__declspec(dllexport) array reshape(const array &a, const array &shape); | |
inline array reshape(const array &a, intptr_t ndim, const intptr_t *shape) | |
{ | |
return reshape(a, nd::array(shape, ndim)); | |
} | |
__declspec(dllexport) array memmap(const std::string &filename, intptr_t begin = 0, | |
intptr_t end = std::numeric_limits<intptr_t>::max(), uint32_t access = default_access_flags); | |
__declspec(dllexport) array combine_into_tuple(size_t field_count, const array *field_values); | |
} | |
namespace ndt { | |
template <typename T> | |
inline const T &unchecked_fixed_dim_get(const nd::array &a, intptr_t i) | |
{ | |
const size_stride_t *md = reinterpret_cast<const size_stride_t *>(a.get()->metadata()); | |
return *reinterpret_cast<const T *>(a.cdata() + i * md->stride); | |
} | |
template <typename T> | |
inline T &unchecked_fixed_dim_get_rw(const nd::array &a, intptr_t i) | |
{ | |
const size_stride_t *md = reinterpret_cast<const size_stride_t *>(a.get()->metadata()); | |
return *reinterpret_cast<T *>(a.data() + i * md->stride); | |
} | |
} | |
__declspec(dllexport) void broadcast_input_shapes(intptr_t ninputs, const nd::array *inputs, intptr_t &out_undim, | |
dimvector &out_shape, shortvector<int> &out_axis_perm); | |
class __declspec(dllexport) broadcast_error : public dynd_exception { | |
public: | |
broadcast_error(const std::string &m); | |
broadcast_error(intptr_t dst_ndim, const intptr_t *dst_shape, intptr_t src_ndim, const intptr_t *src_shape); | |
broadcast_error(const nd::array &dst, const nd::array &src); | |
broadcast_error(intptr_t ninputs, const nd::array *inputs); | |
broadcast_error(const ndt::type &dst_tp, const char *dst_arrmeta, const ndt::type &src_tp, const char *src_arrmeta); | |
broadcast_error(const ndt::type &dst_tp, const char *dst_arrmeta, const char *src_name); | |
broadcast_error(intptr_t dst_size, intptr_t src_size, const char *dst_name, const char *src_name); | |
virtual ~broadcast_error() throw(); | |
}; | |
__declspec(dllexport) void broadcast_to_shape(intptr_t ndim, const intptr_t *shape, intptr_t src_ndim, const intptr_t *src_shape, | |
const intptr_t *src_strides, intptr_t *out_strides); | |
__declspec(dllexport) void incremental_broadcast(intptr_t out_undim, intptr_t *out_shape, intptr_t undim, const intptr_t *shape); | |
} | |
namespace dynd { | |
namespace ndt { | |
namespace detail { | |
__declspec(dllexport) ndt::type internal_substitute(const ndt::type &pattern, const std::map<std::string, ndt::type> &typevars, | |
bool concrete); | |
} | |
inline ndt::type substitute(const ndt::type &pattern, const std::map<std::string, ndt::type> &typevars, bool concrete) | |
{ | |
if (!pattern.is_symbolic() && pattern.get_id() != callable_id) { | |
return pattern; | |
} | |
else { | |
return detail::internal_substitute(pattern, typevars, concrete); | |
} | |
} | |
} | |
} | |
namespace dynd { | |
namespace ndt { | |
class __declspec(dllimport) base_fixed_dim_type : public base_dim_type { | |
public: | |
using base_dim_type::base_dim_type; | |
base_fixed_dim_type(const type &element_tp); | |
size_t get_default_data_size() const; | |
void print_data(std::ostream &o, const char *arrmeta, const char *data) const; | |
void print_type(std::ostream &o) const; | |
bool is_expression() const; | |
bool is_unique_data_owner(const char *arrmeta) const; | |
void transform_child_types(type_transform_fn_t transform_fn, intptr_t arrmeta_offset, void *extra, | |
type &out_transformed_tp, bool &out_was_transformed) const; | |
type get_canonical_type() const; | |
type at_single(intptr_t i0, const char **inout_arrmeta, const char **inout_data) const; | |
type get_type_at_dimension(char **inout_arrmeta, intptr_t i, intptr_t total_ndim = 0) const; | |
intptr_t get_dim_size(const char *arrmeta, const char *data) const; | |
void get_shape(intptr_t ndim, intptr_t i, intptr_t *out_shape, const char *arrmeta, const char *data) const; | |
bool is_lossless_assignment(const type &dst_tp, const type &src_tp) const; | |
virtual bool is_sized() const { return false; } | |
bool operator==(const base_type &rhs) const; | |
void arrmeta_default_construct(char *arrmeta, bool blockref_alloc) const; | |
void arrmeta_copy_construct(char *dst_arrmeta, const char *src_arrmeta, | |
const intrusive_ptr<memory_block_data> &embedded_reference) const; | |
void arrmeta_reset_buffers(char *arrmeta) const; | |
void arrmeta_finalize_buffers(char *arrmeta) const; | |
void arrmeta_destruct(char *arrmeta) const; | |
void arrmeta_debug_print(const char *arrmeta, std::ostream &o, const std::string &indent) const; | |
size_t arrmeta_copy_construct_onedim(char *dst_arrmeta, const char *src_arrmeta, | |
const intrusive_ptr<memory_block_data> &embedded_reference) const; | |
void data_destruct(const char *arrmeta, char *data) const; | |
void data_destruct_strided(const char *arrmeta, char *data, intptr_t stride, size_t count) const; | |
bool match(const type &candidate_tp, std::map<std::string, type> &tp_vars) const; | |
std::map<std::string, std::pair<ndt::type, const char *>> get_dynamic_type_properties() const; | |
virtual type with_element_type(const type &element_tp) const; | |
static type make(const type &element_tp) { return type(new base_fixed_dim_type(element_tp), false); } | |
static type make(const type &element_tp, intptr_t ndim) | |
{ | |
if (ndim > 0) { | |
type result = make(element_tp); | |
for (intptr_t i = 1; i < ndim; ++i) { | |
result = make(result); | |
} | |
return result; | |
} | |
else { | |
return element_tp; | |
} | |
} | |
}; | |
__declspec(dllimport) type make_fixed_dim_kind(const type &element_tp); | |
inline type make_fixed_dim_kind(const type &uniform_tp, intptr_t ndim) | |
{ | |
return base_fixed_dim_type::make(uniform_tp, ndim); | |
} | |
template <typename T> | |
struct traits<T[]> { | |
static type equivalent() { return base_fixed_dim_type::make(make_type<T>()); } | |
}; | |
template <typename T> | |
struct traits<const T[]> { | |
static type equivalent() { return make_type<T[]>(); } | |
}; | |
} | |
} | |
namespace dynd { | |
typedef size_stride_t fixed_dim_type_arrmeta; | |
struct __declspec(dllimport) fixed_dim_type_iterdata { | |
iterdata_common common; | |
char *data; | |
intptr_t stride; | |
}; | |
template <typename ElementType, int NDim> | |
class fixed_dim_iterator; | |
template <typename ElementType> | |
class fixed_dim : public as_t<ElementType> { | |
protected: | |
fixed_dim operator()(const char *metadata, char *data) { return fixed_dim(metadata, data); } | |
template <typename Index0Type, typename... IndexType> | |
decltype(auto) operator()(const char *metadata, char *data, Index0Type index0, IndexType... index) | |
{ | |
return as_t<ElementType>::operator()( | |
metadata + sizeof(fixed_dim_type_arrmeta), | |
data + index0 * reinterpret_cast<const fixed_dim_type_arrmeta *>(metadata)->stride, index...); | |
} | |
public: | |
static const intptr_t ndim = as_t<ElementType>::ndim + 1; | |
typedef typename as_t<ElementType>::data_type data_type; | |
template <int NDim> | |
class iterator_type : public fixed_dim_iterator<ElementType, NDim> { | |
public: | |
iterator_type(const char *metadata, char *data) : fixed_dim_iterator<ElementType, NDim>(metadata, data) {} | |
}; | |
fixed_dim(const char *metadata, char *data) : as_t<ElementType>(metadata, data) {} | |
size_t size() const { return reinterpret_cast<const fixed_dim_type_arrmeta *>(this->m_metadata)->dim_size; } | |
void set_data(char *data) { this->m_data = data; } | |
template <typename... IndexType> | |
decltype(auto) operator()(IndexType... index) | |
{ | |
static_assert(sizeof...(IndexType) <= ndim, "too many indices"); | |
return (*this)(this->m_metadata, this->m_data, index...); | |
} | |
template <int NDim = 1> | |
iterator_type<NDim> begin() | |
{ | |
return iterator_type<NDim>(this->m_metadata, this->m_data); | |
} | |
template <int NDim = 1> | |
iterator_type<NDim> end() | |
{ | |
return iterator_type<NDim>(this->m_metadata, | |
this->m_data + | |
reinterpret_cast<const fixed_dim_type_arrmeta *>(this->m_metadata)->dim_size * | |
reinterpret_cast<const fixed_dim_type_arrmeta *>(this->m_metadata)->stride); | |
} | |
}; | |
template <typename ElementType> | |
class fixed_dim_iterator<ElementType, 0> { | |
protected: | |
const char *m_metadata; | |
char *m_data; | |
public: | |
fixed_dim_iterator(const char *metadata, char *data) : m_metadata(metadata), m_data(data) {} | |
fixed_dim<ElementType> operator*() { return fixed_dim<ElementType>(m_metadata, m_data); } | |
bool operator==(const fixed_dim_iterator &rhs) const { return m_data == rhs.m_data; } | |
bool operator!=(const fixed_dim_iterator &rhs) const { return m_data != rhs.m_data; } | |
}; | |
template <typename ElementType, int NDim> | |
class fixed_dim_iterator : public as_t<ElementType>::template iterator_type<NDim - 1> { | |
intptr_t m_stride; | |
public: | |
fixed_dim_iterator(const char *metadata, char *data) | |
: as_t<ElementType>::template iterator_type<NDim - 1>(metadata + sizeof(fixed_dim_type_arrmeta), data), | |
m_stride(reinterpret_cast<const fixed_dim_type_arrmeta *>(metadata)->stride) | |
{ | |
} | |
fixed_dim_iterator &operator++() | |
{ | |
this->m_data += m_stride; | |
return *this; | |
} | |
fixed_dim_iterator operator++(int) | |
{ | |
fixed_dim_iterator tmp(*this); | |
operator++(); | |
return tmp; | |
} | |
}; | |
namespace ndt { | |
class __declspec(dllimport) fixed_dim_type : public base_fixed_dim_type { | |
intptr_t m_dim_size; | |
public: | |
typedef size_stride_t metadata_type; | |
fixed_dim_type(intptr_t dim_size, const type &element_tp); | |
size_t get_default_data_size() const; | |
intptr_t get_fixed_dim_size() const { return m_dim_size; } | |
intptr_t get_fixed_stride(const char *arrmeta) const | |
{ | |
return reinterpret_cast<const size_stride_t *>(arrmeta)->stride; | |
} | |
void print_data(std::ostream &o, const char *arrmeta, const char *data) const; | |
void print_type(std::ostream &o) const; | |
bool is_c_contiguous(const char *arrmeta) const; | |
bool is_expression() const; | |
bool is_unique_data_owner(const char *arrmeta) const; | |
void transform_child_types(type_transform_fn_t transform_fn, intptr_t arrmeta_offset, void *extra, | |
type &out_transformed_tp, bool &out_was_transformed) const; | |
type get_canonical_type() const; | |
type apply_linear_index(intptr_t nindices, const irange *indices, size_t current_i, const type &root_tp, | |
bool leading_dimension) const; | |
intptr_t apply_linear_index(intptr_t nindices, const irange *indices, const char *arrmeta, const type &result_tp, | |
char *out_arrmeta, const intrusive_ptr<memory_block_data> &embedded_reference, | |
size_t current_i, const type &root_tp, bool leading_dimension, char **inout_data, | |
intrusive_ptr<memory_block_data> &inout_dataref) const; | |
type at_single(intptr_t i0, const char **inout_arrmeta, const char **inout_data) const; | |
type get_type_at_dimension(char **inout_arrmeta, intptr_t i, intptr_t total_ndim = 0) const; | |
intptr_t get_dim_size(const char *arrmeta, const char *data) const; | |
void get_shape(intptr_t ndim, intptr_t i, intptr_t *out_shape, const char *arrmeta, const char *data) const; | |
void get_strides(size_t i, intptr_t *out_strides, const char *arrmeta) const; | |
bool is_sized() const { return true; } | |
axis_order_classification_t classify_axis_order(const char *arrmeta) const; | |
bool is_lossless_assignment(const type &dst_tp, const type &src_tp) const; | |
bool operator==(const base_type &rhs) const; | |
void arrmeta_default_construct(char *arrmeta, bool blockref_alloc) const; | |
void arrmeta_copy_construct(char *dst_arrmeta, const char *src_arrmeta, | |
const intrusive_ptr<memory_block_data> &embedded_reference) const; | |
void arrmeta_reset_buffers(char *arrmeta) const; | |
void arrmeta_finalize_buffers(char *arrmeta) const; | |
void arrmeta_destruct(char *arrmeta) const; | |
void arrmeta_debug_print(const char *arrmeta, std::ostream &o, const std::string &indent) const; | |
size_t arrmeta_copy_construct_onedim(char *dst_arrmeta, const char *src_arrmeta, | |
const intrusive_ptr<memory_block_data> &embedded_reference) const; | |
size_t get_iterdata_size(intptr_t ndim) const; | |
size_t iterdata_construct(iterdata_common *iterdata, const char **inout_arrmeta, intptr_t ndim, | |
const intptr_t *shape, type &out_uniform_tp) const; | |
size_t iterdata_destruct(iterdata_common *iterdata, intptr_t ndim) const; | |
void data_destruct(const char *arrmeta, char *data) const; | |
void data_destruct_strided(const char *arrmeta, char *data, intptr_t stride, size_t count) const; | |
void foreach_leading(const char *arrmeta, char *data, foreach_fn_t callback, void *callback_data) const; | |
void reorder_default_constructed_strides(char *dst_arrmeta, const type &src_tp, const char *src_arrmeta) const; | |
bool match(const type &candidate_tp, std::map<std::string, type> &tp_vars) const; | |
std::map<std::string, std::pair<ndt::type, const char *>> get_dynamic_type_properties() const; | |
virtual type with_element_type(const type &element_tp) const; | |
}; | |
__declspec(dllimport) type make_fixed_dim(size_t dim_size, const type &element_tp); | |
__declspec(dllimport) type make_fixed_dim(intptr_t ndim, const intptr_t *shape, const type &dtp); | |
inline type make_fixed_dim(size_t dim_size, const type &element_tp, intptr_t ndim) | |
{ | |
type result = element_tp; | |
for (intptr_t i = 0; i < ndim; ++i) { | |
result = make_fixed_dim(dim_size, result); | |
} | |
return result; | |
} | |
template <typename ElementType> | |
struct traits<fixed_dim<ElementType>> { | |
static const bool is_same_layout = false; | |
static type equivalent() { return base_fixed_dim_type::make(make_type<ElementType>()); } | |
}; | |
} | |
} | |
namespace dynd { | |
namespace ndt { | |
class __declspec(dllimport) tuple_type : public base_type { | |
protected: | |
intptr_t m_field_count; | |
const std::vector<type> m_field_types; | |
std::vector<uintptr_t> m_arrmeta_offsets; | |
bool m_variadic; | |
tuple_type(type_id_t type_id, const std::vector<type> &field_types, uint32_t flags, bool layout_in_arrmeta, | |
bool variadic); | |
uintptr_t *get_arrmeta_data_offsets(char *arrmeta) const { return reinterpret_cast<uintptr_t *>(arrmeta); } | |
public: | |
tuple_type(const std::vector<type> &field_types, bool variadic); | |
inline const uintptr_t *get_data_offsets(const char *arrmeta) const | |
{ | |
return reinterpret_cast<const uintptr_t *>(arrmeta); | |
} | |
intptr_t get_field_count() const { return m_field_count; } | |
const ndt::type get_type() const { return ndt::type_for(m_field_types); } | |
const std::vector<type> &get_field_types() const { return m_field_types; } | |
const type *get_field_types_raw() const { return m_field_types.data(); } | |
const std::vector<uintptr_t> &get_arrmeta_offsets() const { return m_arrmeta_offsets; } | |
const uintptr_t *get_arrmeta_offsets_raw() const { return m_arrmeta_offsets.data(); } | |
const type &get_field_type(intptr_t i) const { return m_field_types[i]; } | |
uintptr_t get_arrmeta_offset(intptr_t i) const { return m_arrmeta_offsets[i]; } | |
bool is_variadic() const { return m_variadic; } | |
virtual void get_vars(std::unordered_set<std::string> &vars) const; | |
void print_data(std::ostream &o, const char *arrmeta, const char *data) const; | |
bool is_expression() const; | |
bool is_unique_data_owner(const char *arrmeta) const; | |
size_t get_default_data_size() const; | |
void get_shape(intptr_t ndim, intptr_t i, intptr_t *out_shape, const char *arrmeta, const char *data) const; | |
type apply_linear_index(intptr_t nindices, const irange *indices, size_t current_i, const type &root_tp, | |
bool leading_dimension) const; | |
intptr_t apply_linear_index(intptr_t nindices, const irange *indices, const char *arrmeta, const type &result_tp, | |
char *out_arrmeta, const intrusive_ptr<memory_block_data> &embedded_reference, | |
size_t current_i, const type &root_tp, bool leading_dimension, char **inout_data, | |
intrusive_ptr<memory_block_data> &inout_dataref) const; | |
void print_type(std::ostream &o) const; | |
void transform_child_types(type_transform_fn_t transform_fn, intptr_t arrmeta_offset, void *extra, | |
type &out_transformed_tp, bool &out_was_transformed) const; | |
type get_canonical_type() const; | |
bool is_lossless_assignment(const type &dst_tp, const type &src_tp) const; | |
bool operator==(const base_type &rhs) const; | |
void arrmeta_default_construct(char *arrmeta, bool blockref_alloc) const; | |
void arrmeta_copy_construct(char *dst_arrmeta, const char *src_arrmeta, | |
const intrusive_ptr<memory_block_data> &embedded_reference) const; | |
void arrmeta_reset_buffers(char *arrmeta) const; | |
void arrmeta_finalize_buffers(char *arrmeta) const; | |
void arrmeta_destruct(char *arrmeta) const; | |
void data_destruct(const char *arrmeta, char *data) const; | |
void data_destruct_strided(const char *arrmeta, char *data, intptr_t stride, size_t count) const; | |
void foreach_leading(const char *arrmeta, char *data, foreach_fn_t callback, void *callback_data) const; | |
void arrmeta_debug_print(const char *arrmeta, std::ostream &o, const std::string &indent) const; | |
virtual bool match(const type &candidate_tp, std::map<std::string, type> &tp_vars) const; | |
std::map<std::string, std::pair<ndt::type, const char *>> get_dynamic_type_properties() const; | |
static void fill_default_data_offsets(intptr_t nfields, const type *field_tps, uintptr_t *out_data_offsets) | |
{ | |
if (nfields > 0) { | |
out_data_offsets[0] = 0; | |
size_t offs = 0; | |
for (intptr_t i = 1; i < nfields; ++i) { | |
offs += field_tps[i - 1].get_default_data_size(); | |
offs = inc_to_alignment(offs, field_tps[i].get_data_alignment()); | |
out_data_offsets[i] = offs; | |
} | |
} | |
} | |
static type make(const std::vector<type> &field_types, bool variadic = false) | |
{ | |
return type(new tuple_type(field_types, variadic), false); | |
} | |
static type make(bool variadic = false) { return make(std::vector<type>(), variadic); } | |
}; | |
} | |
} | |
namespace dynd { | |
namespace ndt { | |
class __declspec(dllimport) struct_type : public tuple_type { | |
const std::vector<std::string> m_field_names; | |
protected: | |
uintptr_t *get_arrmeta_data_offsets(char *arrmeta) const { return reinterpret_cast<uintptr_t *>(arrmeta); } | |
public: | |
struct_type(const std::vector<std::string> &field_names, const std::vector<type> &field_types, | |
bool variadic = false); | |
const std::vector<std::string> &get_field_names() const { return m_field_names; } | |
const std::string &get_field_name(intptr_t i) const { return m_field_names[i]; } | |
intptr_t get_field_index(const std::string &field_name) const; | |
const type &get_field_type(const std::string &field_name) const; | |
const type &get_field_type(intptr_t i) const; | |
inline const uintptr_t *get_data_offsets(const char *arrmeta) const | |
{ | |
return reinterpret_cast<const uintptr_t *>(arrmeta); | |
} | |
uintptr_t get_data_offset(const char *arrmeta, const std::string &field_name) const; | |
void print_type(std::ostream &o) const; | |
void transform_child_types(type_transform_fn_t transform_fn, intptr_t arrmeta_offset, void *extra, | |
type &out_transformed_tp, bool &out_was_transformed) const; | |
type get_canonical_type() const; | |
type at_single(intptr_t i0, const char **inout_arrmeta, const char **inout_data) const; | |
bool is_lossless_assignment(const type &dst_tp, const type &src_tp) const; | |
bool operator==(const base_type &rhs) const; | |
void arrmeta_debug_print(const char *arrmeta, std::ostream &o, const std::string &indent) const; | |
type apply_linear_index(intptr_t nindices, const irange *indices, size_t current_i, const type &root_tp, | |
bool leading_dimension) const; | |
intptr_t apply_linear_index(intptr_t nindices, const irange *indices, const char *arrmeta, const type &result_tp, | |
char *out_arrmeta, const intrusive_ptr<memory_block_data> &embedded_reference, | |
size_t current_i, const type &root_tp, bool leading_dimension, char **inout_data, | |
intrusive_ptr<memory_block_data> &inout_dataref) const; | |
std::map<std::string, std::pair<ndt::type, const char *>> get_dynamic_type_properties() const; | |
virtual bool match(const type &candidate_tp, std::map<std::string, type> &tp_vars) const; | |
static type make(const std::vector<std::string> &field_names, const std::vector<type> &field_types, | |
bool variadic = false) | |
{ | |
return type(new struct_type(field_names, field_types, variadic), false); | |
} | |
static type make(bool variadic = false) { return make(std::vector<std::string>(), std::vector<type>(), variadic); } | |
}; | |
} | |
} | |
namespace dynd { | |
namespace ndt { | |
class __declspec(dllimport) callable_type : public base_type { | |
type m_return_type; | |
type m_pos_tuple; | |
type m_kwd_struct; | |
std::vector<intptr_t> m_opt_kwd_indices; | |
struct get_pos_types_kernel; | |
public: | |
typedef nd::callable data_type; | |
callable_type(const type &ret_type, const type &pos_types, const type &kwd_types); | |
const type &get_return_type() const { return m_return_type; } | |
const type &get_pos_tuple() const { return m_pos_tuple; } | |
const std::vector<type> &get_pos_types() const { return m_pos_tuple.extended<tuple_type>()->get_field_types(); } | |
bool is_pos_variadic() const { return m_pos_tuple.extended<tuple_type>()->is_variadic(); } | |
bool is_kwd_variadic() const { return m_kwd_struct.extended<struct_type>()->is_variadic(); } | |
const type &get_kwd_struct() const { return m_kwd_struct; } | |
const std::vector<type> &get_kwd_types() const { return m_kwd_struct.extended<struct_type>()->get_field_types(); } | |
const std::vector<std::string> &get_kwd_names() const | |
{ | |
return m_kwd_struct.extended<struct_type>()->get_field_names(); | |
} | |
const type &get_pos_type(intptr_t i) const | |
{ | |
if (i == -1) { | |
return get_return_type(); | |
} | |
return m_pos_tuple.extended<tuple_type>()->get_field_type(i); | |
} | |
const type &get_kwd_type(intptr_t i) const { return m_kwd_struct.extended<struct_type>()->get_field_type(i); } | |
std::string get_kwd_name(intptr_t i) const { return m_kwd_struct.extended<struct_type>()->get_field_name(i); } | |
intptr_t get_kwd_index(const std::string &arg_name) const | |
{ | |
return m_kwd_struct.extended<struct_type>()->get_field_index(arg_name); | |
} | |
void get_vars(std::unordered_set<std::string> &vars) const; | |
bool has_kwd(const std::string &name) const { return get_kwd_index(name) != -1; } | |
const std::vector<intptr_t> &get_option_kwd_indices() const { return m_opt_kwd_indices; } | |
intptr_t get_narg() const { return get_npos() + get_nkwd(); } | |
intptr_t get_npos() const { return m_pos_tuple.extended<tuple_type>()->get_field_count(); } | |
intptr_t get_nkwd() const { return m_kwd_struct.extended<tuple_type>()->get_field_count(); } | |
intptr_t get_nopt() const { return m_opt_kwd_indices.size(); } | |
void print_data(std::ostream &o, const char *arrmeta, const char *data) const; | |
void print_type(std::ostream &o) const; | |
void transform_child_types(type_transform_fn_t transform_fn, intptr_t arrmeta_offset, void *extra, | |
type &out_transformed_tp, bool &out_was_transformed) const; | |
type get_canonical_type() const; | |
type apply_linear_index(intptr_t nindices, const irange *indices, size_t current_i, const type &root_tp, | |
bool leading_dimension) const; | |
intptr_t apply_linear_index(intptr_t nindices, const irange *indices, const char *arrmeta, const type &result_tp, | |
char *out_arrmeta, const intrusive_ptr<memory_block_data> &embedded_reference, | |
size_t current_i, const type &root_tp, bool leading_dimension, char **inout_data, | |
intrusive_ptr<memory_block_data> &inout_dataref) const; | |
bool is_lossless_assignment(const type &dst_tp, const type &src_tp) const; | |
bool operator==(const base_type &rhs) const; | |
void arrmeta_default_construct(char *arrmeta, bool blockref_alloc) const; | |
void arrmeta_copy_construct(char *dst_arrmeta, const char *src_arrmeta, | |
const intrusive_ptr<memory_block_data> &embedded_reference) const; | |
void arrmeta_reset_buffers(char *arrmeta) const; | |
void arrmeta_finalize_buffers(char *arrmeta) const; | |
void arrmeta_destruct(char *arrmeta) const; | |
void data_destruct(const char *arrmeta, char *data) const; | |
void data_destruct_strided(const char *arrmeta, char *data, intptr_t stride, size_t count) const; | |
bool match(const type &candidate_tp, std::map<std::string, type> &tp_vars) const; | |
std::map<std::string, std::pair<ndt::type, const char *>> get_dynamic_type_properties() const; | |
static type make(const type &ret_tp, const type &tuple_tp, const type &struct_tp) | |
{ | |
return type(new callable_type(ret_tp, tuple_tp, struct_tp), false); | |
} | |
static type make(const type &ret_tp, const std::vector<type> &pos_tp, const std::vector<std::string> &kwd_names, | |
const std::vector<type> &kwd_tp) | |
{ | |
return make(ret_tp, tuple_type::make(pos_tp), struct_type::make(kwd_names, kwd_tp)); | |
} | |
static type make(const type &ret_tp, const type &tuple_tp) | |
{ | |
if (tuple_tp.get_id() != tuple_id) { | |
return make(ret_tp, tuple_type::make({tuple_tp}), struct_type::make()); | |
} | |
return make(ret_tp, tuple_tp, struct_type::make(tuple_tp.extended<tuple_type>()->is_variadic())); | |
} | |
static type make(const type &ret_tp, const std::vector<type> &pos_tp) | |
{ | |
return make(ret_tp, tuple_type::make(pos_tp), struct_type::make()); | |
} | |
static type make(const type &ret_tp) { return make(ret_tp, tuple_type::make(), struct_type::make()); } | |
}; | |
template <typename R> | |
struct traits<R()> { | |
static type equivalent() { return callable_type::make(make_type<R>()); } | |
}; | |
template <typename R, typename A0, typename... A> | |
struct traits<R(A0, A...)> { | |
static type equivalent() { return callable_type::make(make_type<R>(), {make_type<A0>(), make_type<A>()...}); } | |
template <typename... T> | |
static type equivalent(const T &... names) | |
{ | |
size_t num_pos = 1 + sizeof...(A) - sizeof...(T); | |
const std::vector<type> tp{make_type<A0>(), make_type<A>()...}; | |
const std::vector<type> pos(tp.begin(), tp.begin() + num_pos); | |
const std::vector<type> kwargs(tp.begin() + num_pos, tp.end()); | |
return callable_type::make(make_type<R>(), pos, {names...}, kwargs); | |
} | |
}; | |
template <typename R, typename T, typename... A> | |
struct traits<R (T::*)(A...)> { | |
static type equivalent() { return make_type<typename funcproto_of<R (T::*)(A...)>::type>(); } | |
}; | |
__declspec(dllimport) type make_generic_funcproto(intptr_t nargs); | |
} | |
} | |
namespace dynd { | |
namespace nd { | |
template <typename ClosureType> | |
struct closure_call : call_node { | |
ClosureType closure; | |
closure_call(ClosureType closure) | |
: call_node(instantiate_wrapper, destructor_wrapper, sizeof(closure_call)), closure(closure) {} | |
template <typename... ArgTypes> | |
static void init(closure_call *self, ArgTypes &&... args) { | |
new (self) closure_call(std::forward<ArgTypes>(args)...); | |
} | |
static void destructor_wrapper(call_node *self) { reinterpret_cast<closure_call *>(self)->~closure_call(); } | |
static void instantiate_wrapper(call_node *self, kernel_builder *kb, kernel_request_t kernreq, | |
const char *dst_arrmeta, size_t nsrc, const char *const *src_arrmeta) { | |
reinterpret_cast<closure_call *>(self)->closure(*kb, kernreq, dst_arrmeta, nsrc, src_arrmeta); | |
} | |
}; | |
} | |
} | |
namespace dynd { | |
namespace nd { | |
class call_graph : public storagebuf<call_node, call_graph> { | |
public: | |
__declspec(dllexport) void destroy() {} | |
~call_graph() { | |
intptr_t offset = 0; | |
while (offset != m_size) { | |
call_node *node = get_at<call_node>(offset); | |
offset += node->aligned_size; | |
node->destroy(node); | |
} | |
} | |
template <typename ClosureType> | |
void emplace_back(ClosureType closure) { | |
storagebuf<call_node, call_graph>::emplace_back<closure_call<ClosureType>>(closure); | |
} | |
}; | |
} | |
} | |
namespace dynd { | |
namespace nd { | |
class call_graph; | |
enum callable_property { | |
none = 0x00000000, | |
left_associative = 0x00000001, | |
right_associative = 0x00000002, | |
commutative = 0x00000004 | |
}; | |
inline callable_property operator|(callable_property a, callable_property b) { | |
return static_cast<callable_property>(static_cast<int>(a) | static_cast<int>(b)); | |
} | |
enum callable_flags_t { | |
callable_flag_none = 0x00000000, | |
callable_flag_abstract = 0x00000001, | |
}; | |
class __declspec(dllexport) base_callable { | |
protected: | |
std::atomic_long m_use_count; | |
ndt::type m_tp; | |
public: | |
base_callable(const ndt::type &tp) : m_use_count(0), m_tp(tp) {} | |
base_callable(const base_callable &) = delete; | |
virtual ~base_callable(); | |
const ndt::type &get_type() const { return m_tp; } | |
const ndt::type &get_return_type() const { return m_tp.extended<ndt::callable_type>()->get_return_type(); } | |
std::intptr_t get_narg() const { return m_tp.extended<ndt::callable_type>()->get_npos(); } | |
const ndt::type &get_arg_type(std::intptr_t i) const { | |
return m_tp.extended<ndt::callable_type>()->get_pos_type(i); | |
} | |
const std::vector<ndt::type> &get_argument_types() const { | |
return m_tp.extended<ndt::callable_type>()->get_pos_types(); | |
} | |
virtual ndt::type resolve(base_callable *caller, char *data, call_graph &cg, const ndt::type &res_tp, size_t narg, | |
const ndt::type *arg_tp, size_t nkwd, const array *kwds, | |
const std::map<std::string, ndt::type> &tp_vars) = 0; | |
virtual array alloc(const ndt::type *dst_tp) const { return empty(*dst_tp); } | |
virtual void overload(const ndt::type &, intptr_t , | |
const ndt::type *, const callable &) { | |
throw std::runtime_error("callable is not overloadable"); | |
} | |
virtual const callable &specialize(const ndt::type &, intptr_t , | |
const ndt::type *) { | |
throw std::runtime_error("callable is not specializable"); | |
} | |
array call(ndt::type &dst_tp, size_t nsrc, const ndt::type *src_tp, const char *const *src_arrmeta, | |
char *const *src_data, size_t nkwd, const array *kwds, const std::map<std::string, ndt::type> &tp_vars); | |
array call(ndt::type &dst_tp, size_t nsrc, const ndt::type *src_tp, const char *const *src_arrmeta, | |
const array *src_data, size_t nkwd, const array *kwds, const std::map<std::string, ndt::type> &tp_vars); | |
void call(const ndt::type &dst_tp, const char *dst_arrmeta, array *dst_data, size_t nsrc, const ndt::type *src_tp, | |
const char *const *src_arrmeta, const array *src_data, size_t nkwd, const array *kwds, | |
const std::map<std::string, ndt::type> &tp_vars); | |
void call(const ndt::type &dst_tp, const char *dst_arrmeta, char *dst_data, size_t nsrc, const ndt::type *src_tp, | |
const char *const *src_arrmeta, char *const *src_data, size_t nkwd, const array *kwds, | |
const std::map<std::string, ndt::type> &tp_vars); | |
friend void intrusive_ptr_retain(base_callable *ptr); | |
friend void intrusive_ptr_release(base_callable *ptr); | |
friend long intrusive_ptr_use_count(base_callable *ptr); | |
}; | |
inline void intrusive_ptr_retain(base_callable *ptr) { ++ptr->m_use_count; } | |
inline void intrusive_ptr_release(base_callable *ptr) { | |
if (--ptr->m_use_count == 0) { | |
delete ptr; | |
} | |
} | |
inline long intrusive_ptr_use_count(base_callable *ptr) { return ptr->m_use_count; } | |
} | |
} | |
namespace dynd { | |
namespace nd { | |
template <typename KernelType> | |
class default_instantiable_callable : public base_callable { | |
protected: | |
using base_callable::base_callable; | |
public: | |
default_instantiable_callable(const ndt::type &tp) : base_callable(tp) {} | |
ndt::type resolve(base_callable *, char *, call_graph &cg, | |
const ndt::type &dst_tp, size_t , const ndt::type *, | |
size_t , const array *, | |
const std::map<std::string, ndt::type> &) { | |
cg.emplace_back([](kernel_builder &kb, kernel_request_t kernreq, const char *, | |
size_t , | |
const char *const *) { kb.emplace_back<KernelType>(kernreq); }); | |
return dst_tp; | |
} | |
}; | |
} | |
} | |
namespace dynd { | |
namespace nd { | |
template <typename...> | |
struct base_kernel; | |
template <typename PrefixType, typename SelfType> | |
struct base_kernel<PrefixType, SelfType> : PrefixType { | |
kernel_prefix *get_child(intptr_t offset) { return kernel_prefix::get_child(kernel_builder::aligned_size(offset)); } | |
kernel_prefix *get_child() { return kernel_prefix::get_child(reinterpret_cast<SelfType *>(this)->size()); } | |
template <size_t I> | |
std::enable_if_t<I == 0, kernel_prefix *> get_child() | |
{ | |
return get_child(); | |
} | |
template <size_t I> | |
std::enable_if_t<(I > 0), kernel_prefix *> get_child() | |
{ | |
const size_t *offsets = this->get_offsets(); | |
return kernel_prefix::get_child(offsets[I - 1]); | |
} | |
constexpr size_t size() const { return sizeof(SelfType); } | |
template <typename... ArgTypes> | |
static void init(SelfType *self, kernel_request_t kernreq, ArgTypes &&... args) | |
{ | |
new (self) SelfType(std::forward<ArgTypes>(args)...); | |
self->destructor = SelfType::destruct; | |
switch (kernreq) { | |
case kernel_request_call: | |
self->function = reinterpret_cast<void *>(SelfType::call_wrapper); | |
break; | |
case kernel_request_single: | |
self->function = reinterpret_cast<void *>(SelfType::single_wrapper); | |
break; | |
default: | |
throw std::invalid_argument("expr ckernel init: unrecognized ckernel request " + std::to_string(kernreq)); | |
} | |
} | |
static void destruct(kernel_prefix *self) { reinterpret_cast<SelfType *>(self)->~SelfType(); } | |
void call(array *, const array *) | |
{ | |
std::stringstream ss; | |
ss << "void call(array *dst, const array *src) is not implemented in " << typeid(SelfType).name(); | |
throw std::runtime_error(ss.str()); | |
} | |
static void call_wrapper(kernel_prefix *self, array *dst, const array *src) | |
{ | |
reinterpret_cast<SelfType *>(self)->call(dst, src); | |
} | |
void single(char *, char *const *) | |
{ | |
std::stringstream ss; | |
ss << "void single(char *dst, char *const *src) is not implemented in " << typeid(SelfType).name(); | |
throw std::runtime_error(ss.str()); | |
} | |
static void single_wrapper(kernel_prefix *self, char *dst, char *const *src) | |
{ | |
reinterpret_cast<SelfType *>(self)->single(dst, src); | |
} | |
static const volatile char *ir; | |
}; | |
template <typename PrefixType, typename SelfType> | |
const volatile char *(base_kernel<PrefixType, SelfType>::ir) = 0; | |
template <typename SelfType> | |
struct base_kernel<SelfType> : base_kernel<kernel_prefix, SelfType> { | |
}; | |
} | |
} | |
namespace dynd { | |
namespace nd { | |
namespace functional { | |
template <typename A, size_t I> | |
struct apply_arg { | |
typedef typename std::remove_cv<typename std::remove_reference<A>::type>::type D; | |
apply_arg(const char *, const nd::array *) {} | |
D &get(char *data) { return *reinterpret_cast<D *>(data); } | |
}; | |
template <typename ElementType, size_t I> | |
struct apply_arg<fixed_dim<ElementType>, I> { | |
fixed_dim<ElementType> value; | |
apply_arg(const char *arrmeta, const nd::array *) : value(arrmeta, 0) {} | |
fixed_dim<ElementType> &get(char *data) | |
{ | |
value.set_data(data); | |
return value; | |
} | |
}; | |
template <typename func_type, int N = args_of<typename funcproto_of<func_type>::type>::type::size> | |
using as_apply_arg_sequence = typename to<typename args_of<typename funcproto_of<func_type>::type>::type, N>::type; | |
template <typename A, typename I = make_index_sequence<A::size>> | |
struct apply_args; | |
template <typename... A, size_t... I> | |
struct apply_args<type_sequence<A...>, index_sequence<I...>> : apply_arg<A, I>... { | |
apply_args(const char *const *src_arrmeta, const nd::array *kwds) | |
: apply_arg<A, I>(src_arrmeta[I], kwds)... | |
{ | |
} | |
}; | |
template <typename T, size_t I> | |
struct apply_kwd { | |
T m_val; | |
apply_kwd(nd::array val) : m_val(val.as<T>()) {} | |
T get() { return m_val; } | |
}; | |
template <typename K, typename J = make_index_sequence<K::size>> | |
struct apply_kwds; | |
template <> | |
struct apply_kwds<type_sequence<>, index_sequence<>> { | |
apply_kwds(intptr_t , const nd::array *) {} | |
}; | |
template <typename... K, size_t... J> | |
struct apply_kwds<type_sequence<K...>, index_sequence<J...>> : apply_kwd<K, J>... { | |
apply_kwds(intptr_t , const nd::array *kwds) : apply_kwd<K, J>(kwds[J])... {} | |
}; | |
template <typename func_type, int N> | |
using as_apply_kwd_sequence = | |
typename from<typename args_of<typename funcproto_of<func_type>::type>::type, N>::type; | |
} | |
} | |
} | |
namespace dynd { | |
namespace nd { | |
template <typename SelfType, size_t... N> | |
struct base_strided_kernel; | |
template <typename SelfType> | |
struct base_strided_kernel<SelfType> : base_kernel<SelfType> { | |
static void strided_wrapper(kernel_prefix *self, char *dst, intptr_t dst_stride, char *const *src, | |
const intptr_t *src_stride, size_t count) | |
{ | |
reinterpret_cast<SelfType *>(self)->strided(dst, dst_stride, src, src_stride, count); | |
} | |
template <typename... ArgTypes> | |
static void init(SelfType *self, kernel_request_t kernreq, ArgTypes &&... args) | |
{ | |
new (self) SelfType(std::forward<ArgTypes>(args)...); | |
self->destructor = SelfType::destruct; | |
switch (kernreq) { | |
case kernel_request_call: | |
self->function = reinterpret_cast<void *>(SelfType::call_wrapper); | |
break; | |
case kernel_request_single: | |
self->function = reinterpret_cast<void *>(SelfType::single_wrapper); | |
break; | |
case kernel_request_strided: | |
self->function = reinterpret_cast<void *>(SelfType::strided_wrapper); | |
break; | |
default: | |
throw std::invalid_argument("expr ckernel init: unrecognized ckernel request " + std::to_string(kernreq)); | |
} | |
} | |
}; | |
template <typename SelfType, size_t N> | |
struct base_strided_kernel<SelfType, N> : base_strided_kernel<SelfType> { | |
void call(array *dst, const array *src) | |
{ | |
char *src_data[N]; | |
for (size_t i = 0; i < N; ++i) { | |
src_data[i] = const_cast<char *>(src[i].cdata()); | |
} | |
reinterpret_cast<SelfType *>(this)->single(const_cast<char *>(dst->cdata()), src_data); | |
} | |
void strided(char *dst, intptr_t dst_stride, char *const *src, const intptr_t *src_stride, size_t count) | |
{ | |
char *src_copy[N]; | |
memcpy(src_copy, src, sizeof(src_copy)); | |
for (size_t i = 0; i != count; ++i) { | |
reinterpret_cast<SelfType *>(this)->single(dst, src_copy); | |
dst += dst_stride; | |
for (size_t j = 0; j < N; ++j) { | |
src_copy[j] += src_stride[j]; | |
} | |
} | |
} | |
}; | |
template <typename SelfType> | |
struct base_strided_kernel<SelfType, 0> : base_strided_kernel<SelfType> { | |
void call(array *dst, const array *) | |
{ | |
reinterpret_cast<SelfType *>(this)->single(const_cast<char *>(dst->cdata()), nullptr); | |
} | |
void strided(char *dst, intptr_t dst_stride, char *const *, const intptr_t *, | |
size_t count) | |
{ | |
for (size_t i = 0; i != count; ++i) { | |
reinterpret_cast<SelfType *>(this)->single(dst, 0); | |
dst += dst_stride; | |
} | |
} | |
}; | |
} | |
} | |
namespace dynd { | |
namespace nd { | |
namespace functional { | |
namespace detail { | |
template <typename func_type, func_type func, typename R, typename A, typename I, typename K, typename J> | |
struct apply_function_kernel; | |
template <typename func_type, func_type func, typename R, typename... A, size_t... I, typename... K, size_t... J> | |
struct apply_function_kernel<func_type, func, R, type_sequence<A...>, index_sequence<I...>, type_sequence<K...>, | |
index_sequence<J...>> | |
: base_strided_kernel<apply_function_kernel<func_type, func, R, type_sequence<A...>, index_sequence<I...>, | |
type_sequence<K...>, index_sequence<J...>>, | |
sizeof...(A)>, | |
apply_args<type_sequence<A...>, index_sequence<I...>>, | |
apply_kwds<type_sequence<K...>, index_sequence<J...>> { | |
typedef apply_args<type_sequence<A...>, index_sequence<I...>> args_type; | |
typedef apply_kwds<type_sequence<K...>, index_sequence<J...>> kwds_type; | |
apply_function_kernel(args_type args, kwds_type kwds) : args_type(args), kwds_type(kwds) {} | |
void single(char *dst, char *const *src) | |
{ | |
*reinterpret_cast<R *>(dst) = func(apply_arg<A, I>::get(src[I])..., apply_kwd<K, J>::get()...); | |
} | |
}; | |
template <typename func_type, func_type func, typename... A, size_t... I, typename... K, size_t... J> | |
struct apply_function_kernel<func_type, func, void, type_sequence<A...>, index_sequence<I...>, | |
type_sequence<K...>, index_sequence<J...>> | |
: base_strided_kernel<apply_function_kernel<func_type, func, void, type_sequence<A...>, index_sequence<I...>, | |
type_sequence<K...>, index_sequence<J...>>, | |
sizeof...(A)>, | |
apply_args<type_sequence<A...>, index_sequence<I...>>, | |
apply_kwds<type_sequence<K...>, index_sequence<J...>> { | |
typedef apply_args<type_sequence<A...>, index_sequence<I...>> args_type; | |
typedef apply_kwds<type_sequence<K...>, index_sequence<J...>> kwds_type; | |
apply_function_kernel(args_type args, kwds_type kwds) : args_type(args), kwds_type(kwds) {} | |
void single(char *, char *const *src) | |
{ | |
func(apply_arg<A, I>::get(src[I])..., apply_kwd<K, J>::get()...); | |
} | |
}; | |
} | |
template <typename func_type, func_type func, int N = arity_of<func_type>::value> | |
using apply_function_kernel = | |
detail::apply_function_kernel<func_type, func, typename return_of<func_type>::type, | |
as_apply_arg_sequence<func_type, N>, make_index_sequence<N>, | |
as_apply_kwd_sequence<func_type, N>, | |
make_index_sequence<arity_of<func_type>::value - N>>; | |
} | |
} | |
} | |
namespace dynd { | |
namespace nd { | |
namespace functional { | |
namespace detail { | |
template <typename T, typename mem_func_type, typename R, typename A, typename I, typename K, typename J> | |
struct apply_member_function_kernel; | |
template <typename T, typename mem_func_type, typename R, typename... A, size_t... I, typename... K, size_t... J> | |
struct apply_member_function_kernel<T *, mem_func_type, R, type_sequence<A...>, index_sequence<I...>, | |
type_sequence<K...>, index_sequence<J...>> | |
: base_strided_kernel< | |
apply_member_function_kernel<T *, mem_func_type, R, type_sequence<A...>, index_sequence<I...>, | |
type_sequence<K...>, index_sequence<J...>>, | |
sizeof...(A)>, | |
apply_args<type_sequence<A...>, index_sequence<I...>>, | |
apply_kwds<type_sequence<K...>, index_sequence<J...>> { | |
typedef apply_args<type_sequence<A...>, index_sequence<I...>> args_type; | |
typedef apply_kwds<type_sequence<K...>, index_sequence<J...>> kwds_type; | |
typedef std::pair<T *, mem_func_type> data_type; | |
T *obj; | |
mem_func_type mem_func; | |
apply_member_function_kernel(T *obj, mem_func_type mem_func, args_type args, kwds_type kwds) | |
: args_type(args), kwds_type(kwds), obj(obj), mem_func(mem_func) | |
{ | |
} | |
void single(char *dst, char *const *src) | |
{ | |
*reinterpret_cast<R *>(dst) = (obj->*mem_func)(apply_arg<A, I>::get(src[I])..., apply_kwd<K, J>::get()...); | |
} | |
}; | |
template <typename T, typename mem_func_type, typename... A, size_t... I, typename... K, size_t... J> | |
struct apply_member_function_kernel<T *, mem_func_type, void, type_sequence<A...>, index_sequence<I...>, | |
type_sequence<K...>, index_sequence<J...>> | |
: base_strided_kernel< | |
apply_member_function_kernel<T *, mem_func_type, void, type_sequence<A...>, index_sequence<I...>, | |
type_sequence<K...>, index_sequence<J...>>, | |
sizeof...(A)>, | |
apply_args<type_sequence<A...>, index_sequence<I...>>, | |
apply_kwds<type_sequence<K...>, index_sequence<J...>> { | |
typedef apply_args<type_sequence<A...>, index_sequence<I...>> args_type; | |
typedef apply_kwds<type_sequence<K...>, index_sequence<J...>> kwds_type; | |
typedef std::pair<T *, mem_func_type> data_type; | |
T *obj; | |
mem_func_type mem_func; | |
apply_member_function_kernel(T *obj, mem_func_type mem_func, args_type args, kwds_type kwds) | |
: args_type(args), kwds_type(kwds), obj(obj), mem_func(mem_func) | |
{ | |
} | |
void single(char *, char *const *src) | |
{ | |
(obj->*mem_func)(apply_arg<A, I>::get(src[I])..., apply_kwd<K, J>::get()...); | |
} | |
}; | |
} | |
template <typename T, typename mem_func_type, int N> | |
using apply_member_function_kernel = | |
detail::apply_member_function_kernel<T, mem_func_type, typename return_of<mem_func_type>::type, | |
as_apply_arg_sequence<mem_func_type, N>, make_index_sequence<N>, | |
as_apply_kwd_sequence<mem_func_type, N>, | |
make_index_sequence<arity_of<mem_func_type>::value - N>>; | |
} | |
} | |
} | |
namespace dynd { | |
namespace nd { | |
namespace functional { | |
namespace detail { | |
template <typename func_type, typename R, typename A, typename I, typename K, typename J> | |
struct construct_then_apply_callable_kernel; | |
template <typename func_type, typename R, typename... A, size_t... I, typename... K, size_t... J> struct construct_then_apply_callable_kernel<func_type, R, type_sequence<A...>, index_sequence<I...>, type_sequence<K...>, index_sequence<J...>> : base_strided_kernel< construct_then_apply_callable_kernel<func_type, R, type_sequence<A...>, index_sequence<I...>, type_sequence<K...>, index_sequence<J...>>, sizeof...(A)>, apply_args<type_sequence<A...>, index_sequence<I...>> { typedef apply_args<type_sequence<A...>, index_sequence<I...>> args_type; typedef apply_kwds<type_sequence<K...>, index_sequence<J...>> kwds_type; func_type func; construct_then_apply_callable_kernel(args_type args, kwds_type kwds) : args_type(args), func(kwds.apply_kwd<K, J>::get()...) { } void single(char *dst, char *const *src) { *reinterpret_cast<R *>(dst) = func(apply_arg<A, I>::get(src[I])...); } }; template <typename func_type, typename... A, size_t... I, typename... K, size_t... J> struct construct_then_apply_callable_kernel<func_type, void, type_sequence<A...>, index_sequence<I...>, type_sequence<K...>, index_sequence<J...>> : base_strided_kernel< construct_then_apply_callable_kernel<func_type, void, type_sequence<A...>, index_sequence<I...>, type_sequence<K...>, index_sequence<J...>>, sizeof...(A)>, apply_args<type_sequence<A...>, index_sequence<I...>> { typedef apply_args<type_sequence<A...>, index_sequence<I...>> args_type; typedef apply_kwds<type_sequence<K...>, index_sequence<J...>> kwds_type; func_type func; construct_then_apply_callable_kernel(args_type args, kwds_type kwds) : args_type(args), func(kwds.apply_kwd<K, J>::get()...) { } void single(char *, char *const *src) { func(apply_arg<A, I>::get(src[I])...); } }; | |
} | |
template <typename func_type, typename... K> | |
using construct_then_apply_callable_kernel = detail::construct_then_apply_callable_kernel< | |
func_type, typename return_of<func_type>::type, as_apply_arg_sequence<func_type, arity_of<func_type>::value>, | |
make_index_sequence<arity_of<func_type>::value>, type_sequence<K...>, make_index_sequence<sizeof...(K)>>; | |
} | |
} | |
} | |
namespace dynd { | |
namespace nd { | |
namespace functional { | |
namespace detail { | |
template <typename func_type, typename R, typename A, typename I, typename K, typename J> | |
struct apply_callable_kernel; | |
template <typename func_type, typename R, typename... A, size_t... I, typename... K, size_t... J> | |
struct apply_callable_kernel<func_type, R, type_sequence<A...>, index_sequence<I...>, type_sequence<K...>, | |
index_sequence<J...>> | |
: base_strided_kernel<apply_callable_kernel<func_type, R, type_sequence<A...>, index_sequence<I...>, | |
type_sequence<K...>, index_sequence<J...>>, | |
sizeof...(A)>, | |
apply_args<type_sequence<A...>, index_sequence<I...>>, | |
apply_kwds<type_sequence<K...>, index_sequence<J...>> { | |
typedef apply_args<type_sequence<A...>, index_sequence<I...>> args_type; | |
typedef apply_kwds<type_sequence<K...>, index_sequence<J...>> kwds_type; | |
func_type func; | |
apply_callable_kernel(func_type func, args_type args, kwds_type kwds) | |
: args_type(args), kwds_type(kwds), func(func) | |
{ | |
} | |
void single(char *dst, char *const *src) | |
{ | |
*reinterpret_cast<R *>(dst) = func(apply_arg<A, I>::get(src[I])..., apply_kwd<K, J>::get()...); | |
} | |
}; | |
template <typename func_type, typename... A, size_t... I, typename... K, size_t... J> | |
struct apply_callable_kernel<func_type, void, type_sequence<A...>, index_sequence<I...>, type_sequence<K...>, | |
index_sequence<J...>> | |
: base_strided_kernel<apply_callable_kernel<func_type, void, type_sequence<A...>, index_sequence<I...>, | |
type_sequence<K...>, index_sequence<J...>>, | |
sizeof...(A)>, | |
apply_args<type_sequence<A...>, index_sequence<I...>>, | |
apply_kwds<type_sequence<K...>, index_sequence<J...>> { | |
typedef apply_args<type_sequence<A...>, index_sequence<I...>> args_type; | |
typedef apply_kwds<type_sequence<K...>, index_sequence<J...>> kwds_type; | |
func_type func; | |
apply_callable_kernel(func_type func, args_type args, kwds_type kwds) | |
: args_type(args), kwds_type(kwds), func(func) | |
{ | |
} | |
void single(char *, char *const *src) | |
{ | |
func(apply_arg<A, I>::get(src[I])..., apply_kwd<K, J>::get()...); | |
} | |
}; | |
template <typename func_type, typename R, typename... A, size_t... I, typename... K, size_t... J> | |
struct apply_callable_kernel<func_type *, R, type_sequence<A...>, index_sequence<I...>, type_sequence<K...>, | |
index_sequence<J...>> | |
: base_strided_kernel<apply_callable_kernel<func_type *, R, type_sequence<A...>, index_sequence<I...>, | |
type_sequence<K...>, index_sequence<J...>>, | |
sizeof...(A)>, | |
apply_args<type_sequence<A...>, index_sequence<I...>>, | |
apply_kwds<type_sequence<K...>, index_sequence<J...>> { | |
typedef apply_args<type_sequence<A...>, index_sequence<I...>> args_type; | |
typedef apply_kwds<type_sequence<K...>, index_sequence<J...>> kwds_type; | |
func_type *func; | |
apply_callable_kernel(func_type *func, args_type args, kwds_type kwds) | |
: args_type(args), kwds_type(kwds), func(func) | |
{ | |
} | |
void single(char *dst, char *const *src) | |
{ | |
*reinterpret_cast<R *>(dst) = (*func)(apply_arg<A, I>::get(src[I])..., apply_kwd<K, J>::get()...); | |
} | |
}; | |
template <typename func_type, typename... A, size_t... I, typename... K, size_t... J> | |
struct apply_callable_kernel<func_type *, void, type_sequence<A...>, index_sequence<I...>, type_sequence<K...>, | |
index_sequence<J...>> | |
: base_strided_kernel<apply_callable_kernel<func_type *, void, type_sequence<A...>, index_sequence<I...>, | |
type_sequence<K...>, index_sequence<J...>>, | |
sizeof...(A)>, | |
apply_args<type_sequence<A...>, index_sequence<I...>>, | |
apply_kwds<type_sequence<K...>, index_sequence<J...>> { | |
typedef apply_args<type_sequence<A...>, index_sequence<I...>> args_type; | |
typedef apply_kwds<type_sequence<K...>, index_sequence<J...>> kwds_type; | |
func_type *func; | |
apply_callable_kernel(func_type *func, args_type args, kwds_type kwds) | |
: args_type(args), kwds_type(kwds), func(func) | |
{ | |
} | |
void single(char *, char *const *src) | |
{ | |
(*func)(apply_arg<A, I>::get(src[I])..., apply_kwd<K, J>::get()...); | |
} | |
}; | |
} | |
template <typename func_type, int N> | |
using apply_callable_kernel = detail::apply_callable_kernel< | |
func_type, typename return_of<func_type>::type, as_apply_arg_sequence<func_type, N>, make_index_sequence<N>, | |
as_apply_kwd_sequence<func_type, N>, make_index_sequence<arity_of<func_type>::value - N>>; | |
} | |
} | |
} | |
namespace dynd { | |
namespace nd { | |
namespace functional { | |
template <typename func_type, int N> | |
class apply_callable_callable : public base_callable { | |
func_type m_func; | |
public: | |
template <typename... T> | |
apply_callable_callable(func_type func, T &&... names) | |
: base_callable(ndt::make_type<typename funcproto_of<func_type>::type>(std::forward<T>(names)...)), | |
m_func(func) {} | |
ndt::type resolve(base_callable *, char *, call_graph &cg, | |
const ndt::type &dst_tp, size_t , const ndt::type *, | |
size_t nkwd, const array *kwds, const std::map<std::string, ndt::type> &) { | |
typedef apply_callable_kernel<func_type, N> kernel_type; | |
cg.emplace_back([ func = m_func, kwds = typename kernel_type::kwds_type(nkwd, kwds) ]( | |
kernel_builder & kb, kernel_request_t kernreq, const char *, | |
size_t , const char *const *src_arrmeta) { | |
kb.emplace_back<kernel_type>(kernreq, func, typename kernel_type::args_type(src_arrmeta, nullptr), kwds); | |
}); | |
return dst_tp; | |
} | |
}; | |
} | |
} | |
} | |
namespace dynd { | |
struct id_info { | |
std::string name; | |
std::vector<type_id_t> base_ids; | |
std::vector<char> is_base_id; | |
id_info() = default; | |
id_info(const char *name, type_id_t id, const std::vector<type_id_t> &base_ids) | |
: name(name), base_ids(base_ids), is_base_id(128) | |
{ | |
is_base_id[id] = true; | |
for (type_id_t base_id : base_ids) { | |
is_base_id[base_id] = true; | |
} | |
} | |
}; | |
namespace detail { | |
extern __declspec(dllimport) std::vector<id_info> &infos(); | |
} | |
__declspec(dllimport) type_id_t new_id(const char *name, type_id_t base_id); | |
inline type_id_t min_id() { return static_cast<type_id_t>(1); } | |
inline type_id_t max_id() | |
{ | |
const std::vector<id_info> &infos = detail::infos(); | |
return static_cast<type_id_t>(infos.size() - 1); | |
} | |
inline type_id_t base_id(type_id_t id) | |
{ | |
const std::vector<id_info> &infos = detail::infos(); | |
return infos[id].base_ids.front(); | |
} | |
template <type_id_t ID> | |
std::enable_if_t<ID == any_kind_id, std::vector<type_id_t>> base_ids() | |
{ | |
return {}; | |
} | |
template <type_id_t ID> | |
std::enable_if_t<ID != any_kind_id, std::vector<type_id_t>> base_ids() | |
{ | |
std::vector<type_id_t> res{base_id_of<ID>::value}; | |
for (type_id_t base_id : base_ids<base_id_of<ID>::value>()) { | |
res.push_back(base_id); | |
} | |
return res; | |
} | |
inline const std::vector<type_id_t> &base_ids(type_id_t id) | |
{ | |
const std::vector<id_info> &infos = detail::infos(); | |
return infos[id].base_ids; | |
} | |
inline bool is_base_id_of(type_id_t base_id, type_id_t id) | |
{ | |
const std::vector<id_info> &infos = detail::infos(); | |
return infos[id].is_base_id[base_id] != 0; | |
} | |
} | |
namespace dynd { | |
inline bool consistent(const std::vector<type_id_t> &lhs, const std::vector<type_id_t> &rhs) | |
{ | |
if (lhs.size() != rhs.size()) { | |
return false; | |
} | |
for (size_t i = 0; i < lhs.size(); ++i) { | |
if (!is_base_id_of(lhs[i], rhs[i]) && !is_base_id_of(rhs[i], lhs[i])) { | |
return false; | |
} | |
} | |
return true; | |
} | |
inline bool supercedes(const std::vector<type_id_t> &lhs, const std::vector<type_id_t> &rhs) | |
{ | |
if (lhs.size() != rhs.size()) { | |
return false; | |
} | |
for (size_t i = 0; i < lhs.size(); ++i) { | |
if (!is_base_id_of(rhs[i], lhs[i])) { | |
return false; | |
} | |
} | |
return true; | |
} | |
inline bool ambiguous(const std::vector<type_id_t> &lhs, const std::vector<type_id_t> &rhs) | |
{ | |
return consistent(lhs, rhs) && !(supercedes(lhs, rhs) || supercedes(rhs, lhs)); | |
} | |
template <size_t N> | |
bool supercedes(const type_id_t (&lhs)[N], const std::vector<type_id_t> &rhs) | |
{ | |
if (rhs.size() != N) { | |
return false; | |
} | |
for (size_t i = 0; i < N; ++i) { | |
if (!is_base_id_of(rhs[i], lhs[i])) { | |
return false; | |
} | |
} | |
return true; | |
} | |
inline bool supercedes(size_t N, const type_id_t *lhs, const std::vector<type_id_t> &rhs) | |
{ | |
if (rhs.size() != N) { | |
return false; | |
} | |
for (size_t i = 0; i < N; ++i) { | |
if (!is_base_id_of(rhs[i], lhs[i])) { | |
return false; | |
} | |
} | |
return true; | |
} | |
namespace detail { | |
class topological_sort_marker { | |
char m_mark; | |
public: | |
topological_sort_marker() : m_mark(0) {} | |
void temporarily_mark() { m_mark = 1; } | |
void mark() { m_mark = 2; } | |
bool is_temporarily_marked() { return m_mark == 1; } | |
bool is_marked() { return m_mark == 2; } | |
}; | |
template <typename VertexIterator, typename EdgeIterator, typename MarkerIterator, typename Iterator> | |
void topological_sort_visit(size_t i, VertexIterator vertices, EdgeIterator edges, MarkerIterator markers, | |
Iterator &res) | |
{ | |
if (markers[i].is_temporarily_marked()) { | |
throw std::runtime_error("not a dag"); | |
} | |
if (!markers[i].is_marked()) { | |
markers[i].temporarily_mark(); | |
for (auto j : edges[i]) { | |
topological_sort_visit(j, vertices, edges, markers, res); | |
} | |
markers[i].mark(); | |
*res = vertices[i]; | |
--res; | |
} | |
} | |
} | |
template <typename VertexIterator, typename EdgeIterator, typename Iterator> | |
void topological_sort(VertexIterator begin, VertexIterator end, EdgeIterator edges, Iterator res) | |
{ | |
size_t size = end - begin; | |
res += size - 1; | |
std::unique_ptr<detail::topological_sort_marker[]> markers = | |
std::make_unique<detail::topological_sort_marker[]>(size); | |
for (size_t i = 0; i < size; ++i) { | |
detail::topological_sort_visit(i, begin, edges, markers.get(), res); | |
} | |
} | |
template <typename VertexType, typename Iterator> | |
void topological_sort(std::initializer_list<VertexType> vertices, | |
std::initializer_list<std::initializer_list<size_t>> edges, Iterator res) | |
{ | |
topological_sort(vertices.begin(), vertices.end(), edges.begin(), res); | |
} | |
inline std::ostream &print_ids(std::ostream &o, size_t nids, const type_id_t *ids) | |
{ | |
o << "(" << ids[0]; | |
for (size_t i = 1; i < nids; ++i) { | |
o << ", " << ids[i]; | |
} | |
o << ")"; | |
return o; | |
} | |
template <typename T, typename Map = std::map<size_t, T>> | |
class dispatcher { | |
public: | |
typedef T value_type; | |
typedef std::pair<std::vector<type_id_t>, value_type> pair_type; | |
typedef Map map_type; | |
typedef typename std::vector<pair_type>::iterator iterator; | |
typedef typename std::vector<pair_type>::const_iterator const_iterator; | |
private: | |
std::vector<pair_type> m_pairs; | |
map_type m_map; | |
static size_t hash_combine(size_t seed, type_id_t id) { return seed ^ (id + (seed << 6) + (seed >> 2)); } | |
template <typename... IDTypes> | |
static size_t hash_combine(size_t seed, type_id_t id0, IDTypes... ids) | |
{ | |
return hash_combine(hash_combine(seed, id0), ids...); | |
} | |
public: | |
dispatcher() = default; | |
dispatcher(const dispatcher &other) : m_pairs(other.m_pairs), m_map(other.m_map) {} | |
template <typename Iterator> | |
dispatcher(Iterator begin, Iterator end, const map_type &map = map_type()) : m_map(map) | |
{ | |
assign(begin, end); | |
} | |
dispatcher(std::initializer_list<pair_type> pairs, const map_type &map = map_type()) | |
: dispatcher(pairs.begin(), pairs.end(), map) | |
{ | |
} | |
template <typename Iterator> | |
void assign(Iterator begin, Iterator end) | |
{ | |
m_pairs.resize(end - begin); | |
std::vector<std::vector<size_t>> edges(m_pairs.size()); | |
for (size_t i = 0; i < edges.size(); ++i) { | |
for (size_t j = i + 1; j < edges.size(); ++j) { | |
if (ambiguous(begin[i].first, begin[j].first)) { | |
bool ok = false; | |
for (size_t k = 0; k < edges.size(); ++k) { | |
if (supercedes(begin[k].first, begin[i].first) && supercedes(begin[k].first, begin[j].first)) { | |
ok = true; | |
} | |
} | |
if (!ok) { | |
std::stringstream ss; | |
print_ids(ss, begin[i].first.size(), begin[i].first.data()); | |
ss << " and "; | |
print_ids(ss, begin[j].first.size(), begin[j].first.data()); | |
ss << " are ambiguous"; | |
throw std::runtime_error(ss.str()); | |
} | |
} | |
if (edge(begin[i].first, begin[j].first)) { | |
edges[i].push_back(j); | |
} | |
else if (edge(begin[j].first, begin[i].first)) { | |
edges[j].push_back(i); | |
} | |
} | |
} | |
topological_sort(begin, end, edges, m_pairs.begin()); | |
m_map.clear(); | |
} | |
void assign(std::initializer_list<pair_type> pairs) { assign(pairs.begin(), pairs.end()); } | |
template <typename Iterator> | |
void insert(Iterator begin, Iterator end) | |
{ | |
std::vector<pair_type> vertices = m_pairs; | |
vertices.insert(vertices.end(), begin, end); | |
assign(vertices.begin(), vertices.end()); | |
} | |
void insert(const pair_type &pair) { insert(&pair, &pair + 1); } | |
void insert(std::initializer_list<pair_type> pairs) { insert(pairs.begin(), pairs.end()); } | |
iterator begin() { return m_pairs.begin(); } | |
const_iterator begin() const { return m_pairs.begin(); } | |
const_iterator cbegin() const { return m_pairs.cbegin(); } | |
iterator end() { return m_pairs.end(); } | |
const_iterator end() const { return m_pairs.end(); } | |
const_iterator cend() const { return m_pairs.cend(); } | |
template <typename... IDTypes> | |
const value_type &operator()(IDTypes... ids) | |
{ | |
size_t key = hash(ids...); | |
const auto &it = m_map.find(key); | |
if (it != m_map.end()) { | |
return it->second; | |
} | |
for (const pair_type &pair : m_pairs) { | |
if (supercedes({ids...}, pair.first)) { | |
return m_map[key] = pair.second; | |
} | |
} | |
throw std::out_of_range("signature not found"); | |
} | |
const value_type &operator()(size_t nids, const type_id_t *ids) | |
{ | |
size_t key = static_cast<size_t>(ids[0]); | |
for (size_t i = 1; i < nids; ++i) { | |
key = hash_combine(key, ids[i]); | |
} | |
const auto &it = m_map.find(key); | |
if (it != m_map.end()) { | |
return it->second; | |
} | |
for (const pair_type &pair : m_pairs) { | |
if (supercedes(nids, ids, pair.first)) { | |
return m_map[key] = pair.second; | |
} | |
} | |
throw std::out_of_range("signature not found"); | |
} | |
const value_type &operator()(std::initializer_list<type_id_t> ids) { return operator()(ids.size(), ids.begin()); } | |
static bool edge(const std::vector<type_id_t> &u, const std::vector<type_id_t> &v) | |
{ | |
if (supercedes(u, v)) { | |
if (supercedes(v, u)) { | |
return false; | |
} | |
else { | |
return true; | |
} | |
} | |
return false; | |
} | |
static size_t hash(type_id_t id) { return static_cast<size_t>(id); } | |
template <typename... IDTypes> | |
static size_t hash(type_id_t id0, IDTypes... ids) | |
{ | |
return hash_combine(hash(id0), ids...); | |
} | |
}; | |
} | |
namespace dynd { | |
namespace nd { | |
namespace detail { | |
__declspec(dllexport) std::map<std::string, callable> &get_regfunctions(); | |
inline bool is_special_kwd(const ndt::callable_type *, array &dst, const std::string &name, | |
const nd::array &value) { | |
if (name == "dst_tp") { | |
dst = nd::empty(value.as<ndt::type>()); | |
return true; | |
} else if (name == "dst") { | |
dst = value; | |
return true; | |
} | |
return false; | |
} | |
__declspec(dllexport) void check_narg(const ndt::callable_type *af_tp, intptr_t narg); | |
__declspec(dllexport) void check_arg(const ndt::callable_type *af_tp, intptr_t i, const ndt::type &actual_tp, | |
const char *actual_arrmeta, std::map<std::string, ndt::type> &tp_vars); | |
template <template <type_id_t...> class KernelType> | |
struct make_all; | |
template <template <type_id_t...> class KernelType> | |
struct new_make_all; | |
template <template <type_id_t...> class KernelType, template <type_id_t...> class Condition> | |
struct make_all_if; | |
} | |
typedef array callable_arg_t; | |
typedef std::pair<const char *, array> callable_kwd_t; | |
class __declspec(dllexport) callable : public intrusive_ptr<base_callable> { | |
public: | |
using intrusive_ptr<base_callable>::intrusive_ptr; | |
callable() = default; | |
template <typename CallableType, typename... T, typename = std::enable_if_t<all_char_string_params<T...>::value>> | |
callable(CallableType f, T &&... names) | |
: callable(new functional::apply_callable_callable<CallableType, arity_of<CallableType>::value - sizeof...(T)>( | |
f, std::forward<T>(names)...), | |
true) {} | |
bool is_null() const { return get() == 0; } | |
callable_property get_flags() const { return right_associative; } | |
const ndt::callable_type *get_type() const { | |
if (get() == 0) { | |
return 0; | |
} | |
return m_ptr->get_type().extended<ndt::callable_type>(); | |
} | |
ndt::type resolve(const ndt::type &dst_tp, size_t nsrc, const ndt::type *src_tp, size_t nkwd, const array *kwds) { | |
std::map<std::string, ndt::type> tp_vars; | |
call_graph cg; | |
return m_ptr->resolve(nullptr, nullptr, cg, dst_tp, nsrc, src_tp, nkwd, kwds, tp_vars); | |
} | |
ndt::type resolve(const ndt::type &dst_tp, std::initializer_list<ndt::type> src_tp, | |
std::initializer_list<array> kwds) { | |
return resolve(dst_tp, src_tp.size(), src_tp.begin(), kwds.size(), kwds.begin()); | |
} | |
ndt::type resolve(std::initializer_list<ndt::type> src_tp, std::initializer_list<array> kwds) { | |
return resolve(get_type()->get_return_type(), src_tp.size(), src_tp.begin(), kwds.size(), kwds.begin()); | |
} | |
const ndt::type &get_array_type() const { return m_ptr->get_type(); } | |
const ndt::type &get_ret_type() const { return get_type()->get_return_type(); } | |
std::intptr_t get_narg() const { return get_type()->get_npos(); } | |
const ndt::type &get_arg_type(std::intptr_t i) const { return get_type()->get_pos_type(i); } | |
const std::vector<ndt::type> &get_arg_types() const { return get_type()->get_pos_types(); } | |
void overload(const ndt::type &ret_tp, intptr_t narg, const ndt::type *arg_tp, const callable &value) { | |
get()->overload(ret_tp, narg, arg_tp, value); | |
} | |
void overload(const ndt::type &ret_tp, const std::initializer_list<ndt::type> &arg_tp, const callable &value) { | |
overload(ret_tp, arg_tp.size(), arg_tp.begin(), value); | |
} | |
const callable &specialize(const ndt::type &ret_tp, intptr_t narg, const ndt::type *arg_tp) const { | |
return get()->specialize(ret_tp, narg, arg_tp); | |
} | |
const callable &specialize(const ndt::type &ret_tp, const std::initializer_list<ndt::type> &arg_tp) const { | |
return specialize(ret_tp, arg_tp.size(), arg_tp.begin()); | |
} | |
array call(size_t args_size, const array *args_values, size_t kwds_size, | |
const std::pair<const char *, array> *kwds_values) const; | |
template <typename... ArgTypes> | |
array operator()(ArgTypes &&... args) const { | |
array tmp[sizeof...(ArgTypes)] = {std::forward<ArgTypes>(args)...}; | |
return call(sizeof...(ArgTypes), tmp, 0, nullptr); | |
} | |
array operator()() const { return call(0, nullptr, 0, nullptr); } | |
array operator()(const std::initializer_list<array> &args, | |
const std::initializer_list<std::pair<const char *, array>> &kwds) const { | |
return call(args.size(), args.begin(), kwds.size(), kwds.begin()); | |
} | |
template <template <type_id_t> class KernelType, typename I0, typename... A> | |
static dispatcher<callable> new_make_all(A &&... a) { | |
std::vector<std::pair<std::vector<type_id_t>, callable>> callables; | |
for_each<I0>(detail::new_make_all<KernelType>(), callables, std::forward<A>(a)...); | |
return dispatcher<callable>(callables.begin(), callables.end()); | |
} | |
template <template <type_id_t> class KernelType, typename I0, typename... A> | |
static std::map<type_id_t, callable> make_all(A &&... a) { | |
std::map<type_id_t, callable> callables; | |
for_each<I0>(detail::make_all<KernelType>(), callables, std::forward<A>(a)...); | |
return callables; | |
} | |
template <template <type_id_t, type_id_t, type_id_t...> class KernelType, typename I0, typename I1, typename... I, | |
typename... A> | |
static std::map<std::array<type_id_t, 2 + sizeof...(I)>, callable> make_all(A &&... a) { | |
std::map<std::array<type_id_t, 2 + sizeof...(I)>, callable> callables; | |
for_each<typename outer<I0, I1, I...>::type>(detail::make_all<KernelType>(), callables, std::forward<A>(a)...); | |
return callables; | |
} | |
template <template <type_id_t, type_id_t, type_id_t...> class KernelType, typename I0, typename I1, typename... I, | |
typename... A> | |
static dispatcher<callable> new_make_all(A &&... a) { | |
std::vector<std::pair<std::vector<type_id_t>, callable>> callables; | |
for_each<typename outer<I0, I1, I...>::type>(detail::new_make_all<KernelType>(), callables, | |
std::forward<A>(a)...); | |
return dispatcher<callable>(callables.begin(), callables.end()); | |
} | |
template <template <type_id_t> class KernelType, template <type_id_t> class Condition, typename I0, typename... A> | |
static dispatcher<callable> make_all_if(A &&... a) { | |
std::vector<std::pair<std::vector<type_id_t>, callable>> callables; | |
for_each<I0>(detail::make_all_if<KernelType, Condition>(), callables, std::forward<A>(a)...); | |
return dispatcher<callable>(callables.begin(), callables.end()); | |
} | |
template <template <type_id_t, type_id_t, type_id_t...> class KernelType, | |
template <type_id_t, type_id_t, type_id_t...> class Condition, typename I0, typename I1, typename... I, | |
typename... A> | |
static dispatcher<callable> make_all_if(A &&... a) { | |
std::vector<std::pair<std::vector<type_id_t>, callable>> callables; | |
for_each<typename outer<I0, I1, I...>::type>(detail::make_all_if<KernelType, Condition>(), callables, | |
std::forward<A>(a)...); | |
return dispatcher<callable>(callables.begin(), callables.end()); | |
} | |
}; | |
template <typename CallableType, typename... ArgTypes> | |
std::enable_if_t<std::is_base_of<base_callable, CallableType>::value, callable> make_callable(ArgTypes &&... args) { | |
return callable(new CallableType(std::forward<ArgTypes>(args)...), true); | |
} | |
template <typename KernelType, typename... ArgTypes> | |
std::enable_if_t<std::is_base_of<base_kernel<KernelType>, KernelType>::value, callable> | |
make_callable(const ndt::type &tp) { | |
return make_callable<default_instantiable_callable<KernelType>>(tp); | |
} | |
inline std::ostream &operator<<(std::ostream &o, const callable &rhs) { | |
return o << "<callable <" << rhs->get_type() << "> at " << reinterpret_cast<const void *>(rhs.get()) << ">"; | |
} | |
namespace detail { | |
template <template <type_id_t...> class KernelType, typename S> | |
struct apply; | |
template <template <type_id_t...> class KernelType, type_id_t... I> | |
struct apply<KernelType, type_id_sequence<I...>> { | |
typedef KernelType<I...> type; | |
}; | |
template <template <type_id_t...> class KernelType> | |
struct make_all { | |
template <type_id_t TypeID, typename... A> | |
void on_each(std::map<type_id_t, callable> &callables, A &&... a) const { | |
callables[TypeID] = make_callable<KernelType<TypeID>>(std::forward<A>(a)...); | |
} | |
template <typename TypeIDSequence, typename... A> | |
void on_each(std::map<std::array<type_id_t, TypeIDSequence::size2()>, callable> &callables, A &&... a) const { | |
callables[i2a<TypeIDSequence>()] = | |
make_callable<typename apply<KernelType, TypeIDSequence>::type>(std::forward<A>(a)...); | |
} | |
}; | |
template <template <type_id_t...> class KernelType> | |
struct new_make_all { | |
template <type_id_t TypeID, typename... A> | |
void on_each(std::vector<std::pair<std::vector<type_id_t>, callable>> &callables, A &&... a) const { | |
callables.push_back({{TypeID}, make_callable<KernelType<TypeID>>(std::forward<A>(a)...)}); | |
} | |
template <typename TypeIDSequence, typename... A> | |
void on_each(std::vector<std::pair<std::vector<type_id_t>, callable>> &callables, A &&... a) const { | |
auto arr = i2a<TypeIDSequence>(); | |
std::vector<type_id_t> v(arr.size()); | |
for (size_t i = 0; i < arr.size(); ++i) { | |
v[i] = arr[i]; | |
} | |
callables.push_back( | |
{{v}, make_callable<typename apply<KernelType, TypeIDSequence>::type>(std::forward<A>(a)...)}); | |
} | |
}; | |
template <template <type_id_t...> class KernelType, template <type_id_t...> class Condition> | |
struct make_all_if { | |
template <type_id_t TypeID, typename... A> | |
void on_each(std::vector<std::pair<std::vector<type_id_t>, callable>> &callables, A &&... a) const { | |
if (Condition<TypeID>::value) { | |
callables.push_back({{TypeID}, make_callable<KernelType<TypeID>>(std::forward<A>(a)...)}); | |
} | |
} | |
template <typename TypeIDSequence, typename... A> | |
void on_each(std::vector<std::pair<std::vector<type_id_t>, callable>> &callables, A &&... a) const { | |
if (apply<Condition, TypeIDSequence>::type::value) { | |
auto arr = i2a<TypeIDSequence>(); | |
std::vector<type_id_t> v; | |
for (size_t i = 0; i < arr.size(); ++i) { | |
v.push_back(arr[i]); | |
} | |
callables.push_back( | |
{{v}, make_callable<typename apply<KernelType, TypeIDSequence>::type>(std::forward<A>(a)...)}); | |
} | |
} | |
}; | |
} | |
__declspec(dllexport) std::map<std::string, callable> &callables(); | |
} | |
__declspec(dllexport) nd::callable make_callable_from_assignment(const ndt::type &dst_tp, const ndt::type &src_tp, | |
assign_error_mode errmode); | |
} | |
namespace dynd { | |
namespace nd { | |
extern __declspec(dllexport) callable plus; | |
extern __declspec(dllexport) callable minus; | |
extern __declspec(dllexport) callable logical_not; | |
extern __declspec(dllexport) callable bitwise_not; | |
extern __declspec(dllexport) callable add; | |
extern __declspec(dllexport) callable subtract; | |
extern __declspec(dllexport) callable multiply; | |
extern __declspec(dllexport) callable divide; | |
extern __declspec(dllexport) callable logical_and; | |
extern __declspec(dllexport) callable logical_or; | |
extern __declspec(dllexport) callable compound_add; | |
extern __declspec(dllexport) callable compound_div; | |
extern __declspec(dllexport) callable sum; | |
} | |
} | |
namespace dynd { | |
namespace nd { | |
namespace functional { | |
template <typename func_type, func_type func, int N = arity_of<func_type>::value> | |
class apply_function_callable : public base_callable { | |
public: | |
template <typename... T> | |
apply_function_callable(T &&... names) | |
: base_callable(ndt::make_type<typename funcproto_of<func_type>::type>(std::forward<T>(names)...)) {} | |
ndt::type resolve(base_callable *, char *, call_graph &cg, | |
const ndt::type &dst_tp, size_t , const ndt::type *, | |
size_t nkwd, const array *kwds, const std::map<std::string, ndt::type> &) { | |
typedef apply_function_kernel<func_type, func, N> kernel_type; | |
cg.emplace_back([kwds = typename kernel_type::kwds_type(nkwd, kwds)]( | |
kernel_builder & kb, kernel_request_t kernreq, const char *, | |
size_t , const char *const *src_arrmeta) { | |
kb.emplace_back<kernel_type>(kernreq, typename kernel_type::args_type(src_arrmeta, nullptr), kwds); | |
}); | |
return dst_tp; | |
} | |
}; | |
} | |
} | |
} | |
namespace dynd { | |
namespace detail { | |
template <typename> | |
struct sfinae_true : std::true_type {}; | |
template <typename T> static auto plus_isdef_test(int )->sfinae_true<decltype(+ std::declval<T>())>; template <typename> static auto plus_isdef_test(long)->std::false_type; template <type_id_t Src0TypeID> struct isdef_plus : decltype(plus_isdef_test<typename type_of<Src0TypeID>::type>(0)) {}; | |
__pragma(warning(push)) __pragma(warning(disable : 4146)) | |
template <typename T> static auto minus_isdef_test(int )->sfinae_true<decltype(- std::declval<T>())>; template <typename> static auto minus_isdef_test(long)->std::false_type; template <type_id_t Src0TypeID> struct isdef_minus : decltype(minus_isdef_test<typename type_of<Src0TypeID>::type>(0)) {}; | |
__pragma(warning(pop)) | |
template <typename T> static auto logical_not_isdef_test(int )->sfinae_true<decltype(! std::declval<T>())>; template <typename> static auto logical_not_isdef_test(long)->std::false_type; template <type_id_t Src0TypeID> struct isdef_logical_not : decltype(logical_not_isdef_test<typename type_of<Src0TypeID>::type>(0)) {}; | |
template <typename T> static auto bitwise_not_isdef_test(int )->sfinae_true<decltype(~ std::declval<T>())>; template <typename> static auto bitwise_not_isdef_test(long)->std::false_type; template <type_id_t Src0TypeID> struct isdef_bitwise_not : decltype(bitwise_not_isdef_test<typename type_of<Src0TypeID>::type>(0)) {}; | |
template <typename T, typename U> static auto add_isdef_test(int )->sfinae_true<decltype(std::declval<T>() + std::declval<U>())>; template <typename, typename> static auto add_isdef_test(long)->std::false_type; template <type_id_t Src0TypeID, type_id_t Src1TypeID> struct isdef_add : decltype(add_isdef_test<typename type_of<Src0TypeID>::type, typename type_of<Src1TypeID>::type>(0)) {}; | |
template <typename T, typename U> static auto subtract_isdef_test(int )->sfinae_true<decltype(std::declval<T>() - std::declval<U>())>; template <typename, typename> static auto subtract_isdef_test(long)->std::false_type; template <type_id_t Src0TypeID, type_id_t Src1TypeID> struct isdef_subtract : decltype(subtract_isdef_test<typename type_of<Src0TypeID>::type, typename type_of<Src1TypeID>::type>(0)) {}; | |
template <typename T, typename U> static auto multiply_isdef_test(int )->sfinae_true<decltype(std::declval<T>() * std::declval<U>())>; template <typename, typename> static auto multiply_isdef_test(long)->std::false_type; template <type_id_t Src0TypeID, type_id_t Src1TypeID> struct isdef_multiply : decltype(multiply_isdef_test<typename type_of<Src0TypeID>::type, typename type_of<Src1TypeID>::type>(0)) {}; | |
template <typename T, typename U> static auto divide_isdef_test(int )->sfinae_true<decltype(std::declval<T>() / std::declval<U>())>; template <typename, typename> static auto divide_isdef_test(long)->std::false_type; template <type_id_t Src0TypeID, type_id_t Src1TypeID> struct isdef_divide : decltype(divide_isdef_test<typename type_of<Src0TypeID>::type, typename type_of<Src1TypeID>::type>(0)) {}; | |
template <typename T, typename U> static auto mod_isdef_test(int )->sfinae_true<decltype(std::declval<T>() % std::declval<U>())>; template <typename, typename> static auto mod_isdef_test(long)->std::false_type; template <type_id_t Src0TypeID, type_id_t Src1TypeID> struct isdef_mod : decltype(mod_isdef_test<typename type_of<Src0TypeID>::type, typename type_of<Src1TypeID>::type>(0)) {}; | |
template <typename T, typename U> static auto bitwise_and_isdef_test(int )->sfinae_true<decltype(std::declval<T>() & std::declval<U>())>; template <typename, typename> static auto bitwise_and_isdef_test(long)->std::false_type; template <type_id_t Src0TypeID, type_id_t Src1TypeID> struct isdef_bitwise_and : decltype(bitwise_and_isdef_test<typename type_of<Src0TypeID>::type, typename type_of<Src1TypeID>::type>(0)) {}; | |
template <typename T, typename U> static auto logical_and_isdef_test(int )->sfinae_true<decltype(std::declval<T>() && std::declval<U>())>; template <typename, typename> static auto logical_and_isdef_test(long)->std::false_type; template <type_id_t Src0TypeID, type_id_t Src1TypeID> struct isdef_logical_and : decltype(logical_and_isdef_test<typename type_of<Src0TypeID>::type, typename type_of<Src1TypeID>::type>(0)) {}; | |
template <typename T, typename U> static auto bitwise_or_isdef_test(int )->sfinae_true<decltype(std::declval<T>() | std::declval<U>())>; template <typename, typename> static auto bitwise_or_isdef_test(long)->std::false_type; template <type_id_t Src0TypeID, type_id_t Src1TypeID> struct isdef_bitwise_or : decltype(bitwise_or_isdef_test<typename type_of<Src0TypeID>::type, typename type_of<Src1TypeID>::type>(0)) {}; | |
template <typename T, typename U> static auto logical_or_isdef_test(int )->sfinae_true<decltype(std::declval<T>() || std::declval<U>())>; template <typename, typename> static auto logical_or_isdef_test(long)->std::false_type; template <type_id_t Src0TypeID, type_id_t Src1TypeID> struct isdef_logical_or : decltype(logical_or_isdef_test<typename type_of<Src0TypeID>::type, typename type_of<Src1TypeID>::type>(0)) {}; | |
template <typename T, typename U> static auto bitwise_xor_isdef_test(int )->sfinae_true<decltype(std::declval<T>() ^ std::declval<U>())>; template <typename, typename> static auto bitwise_xor_isdef_test(long)->std::false_type; template <type_id_t Src0TypeID, type_id_t Src1TypeID> struct isdef_bitwise_xor : decltype(bitwise_xor_isdef_test<typename type_of<Src0TypeID>::type, typename type_of<Src1TypeID>::type>(0)) {}; | |
template <typename T, typename U> static auto left_shift_isdef_test(int )->sfinae_true<decltype(std::declval<T>() << std::declval<U>())>; template <typename, typename> static auto left_shift_isdef_test(long)->std::false_type; template <type_id_t Src0TypeID, type_id_t Src1TypeID> struct isdef_left_shift : decltype(left_shift_isdef_test<typename type_of<Src0TypeID>::type, typename type_of<Src1TypeID>::type>(0)) {}; | |
template <typename T, typename U> static auto right_shift_isdef_test(int )->sfinae_true<decltype(std::declval<T>() >> std::declval<U>())>; template <typename, typename> static auto right_shift_isdef_test(long)->std::false_type; template <type_id_t Src0TypeID, type_id_t Src1TypeID> struct isdef_right_shift : decltype(right_shift_isdef_test<typename type_of<Src0TypeID>::type, typename type_of<Src1TypeID>::type>(0)) {}; | |
} | |
namespace nd { | |
namespace detail { template <type_id_t Src0TypeID> struct inline_plus { static auto f(typename type_of<Src0TypeID>::type a) { return + a; } }; } | |
__pragma(warning(push)) __pragma(warning(disable : 4146)) | |
namespace detail { template <type_id_t Src0TypeID> struct inline_minus { static auto f(typename type_of<Src0TypeID>::type a) { return - a; } }; } | |
__pragma(warning(pop)) | |
namespace detail { template <type_id_t Src0TypeID> struct inline_logical_not { static auto f(typename type_of<Src0TypeID>::type a) { return ! a; } }; } | |
namespace detail { template <type_id_t Src0TypeID> struct inline_bitwise_not { static auto f(typename type_of<Src0TypeID>::type a) { return ~ a; } }; } | |
namespace detail { template <type_id_t Src0TypeID, type_id_t Src1TypeID> struct inline_add { static auto f(typename type_of<Src0TypeID>::type a, typename type_of<Src1TypeID>::type b) { return a + b; } }; } | |
namespace detail { template <type_id_t Src0TypeID, type_id_t Src1TypeID> struct inline_subtract { static auto f(typename type_of<Src0TypeID>::type a, typename type_of<Src1TypeID>::type b) { return a - b; } }; } | |
namespace detail { template <type_id_t Src0TypeID, type_id_t Src1TypeID> struct inline_multiply { static auto f(typename type_of<Src0TypeID>::type a, typename type_of<Src1TypeID>::type b) { return a * b; } }; } | |
namespace detail { template <type_id_t Src0TypeID, type_id_t Src1TypeID> struct inline_bitwise_and { static auto f(typename type_of<Src0TypeID>::type a, typename type_of<Src1TypeID>::type b) { return a & b; } }; } | |
namespace detail { template <type_id_t Src0TypeID, type_id_t Src1TypeID> struct inline_logical_and { static auto f(typename type_of<Src0TypeID>::type a, typename type_of<Src1TypeID>::type b) { return a && b; } }; } | |
namespace detail { template <type_id_t Src0TypeID, type_id_t Src1TypeID> struct inline_bitwise_or { static auto f(typename type_of<Src0TypeID>::type a, typename type_of<Src1TypeID>::type b) { return a | b; } }; } | |
namespace detail { template <type_id_t Src0TypeID, type_id_t Src1TypeID> struct inline_logical_or { static auto f(typename type_of<Src0TypeID>::type a, typename type_of<Src1TypeID>::type b) { return a || b; } }; } | |
namespace detail { template <type_id_t Src0TypeID, type_id_t Src1TypeID> struct inline_bitwise_xor { static auto f(typename type_of<Src0TypeID>::type a, typename type_of<Src1TypeID>::type b) { return a ^ b; } }; } | |
namespace detail { template <type_id_t Src0TypeID, type_id_t Src1TypeID> struct inline_left_shift { static auto f(typename type_of<Src0TypeID>::type a, typename type_of<Src1TypeID>::type b) { return a << b; } }; } | |
namespace detail { template <type_id_t Src0TypeID, type_id_t Src1TypeID> struct inline_right_shift { static auto f(typename type_of<Src0TypeID>::type a, typename type_of<Src1TypeID>::type b) { return a >> b; } }; } | |
namespace detail { | |
template <type_id_t Src0TypeID, type_id_t Src1TypeID> | |
struct inline_logical_xor { | |
static auto f(typename type_of<Src0TypeID>::type a, typename type_of<Src1TypeID>::type b) { return (!a) ^ (!b); } | |
}; | |
} | |
namespace detail { | |
template <type_id_t Src0TypeID, type_id_t Src1TypeID> | |
constexpr bool needs_zero_check() { | |
using Base0 = base_id_of<Src0TypeID>; | |
using Base1 = base_id_of<Src1TypeID>; | |
return ((Base0::value == bool_kind_id) || (Base0::value == int_kind_id) || (Base0::value == uint_kind_id)) && | |
((Base1::value == bool_kind_id) || (Base1::value == int_kind_id) || (Base1::value == uint_kind_id)); | |
} | |
} | |
namespace detail { template <type_id_t Src0TypeID, type_id_t Src1TypeID, bool check> struct inline_divide_base; template <type_id_t Src0TypeID, type_id_t Src1TypeID> struct inline_divide_base<Src0TypeID, Src1TypeID, true> { static auto f(typename type_of<Src0TypeID>::type a, typename type_of<Src1TypeID>::type b) { if (b == 0) { throw dynd::zero_division_error("Integer division or modulo by zero."); } return a / b; } }; template <type_id_t Src0TypeID, type_id_t Src1TypeID> struct inline_divide_base<Src0TypeID, Src1TypeID, false> { static auto f(typename type_of<Src0TypeID>::type a, typename type_of<Src1TypeID>::type b) { return a / b; } }; template <type_id_t Src0TypeID, type_id_t Src1TypeID> using inline_divide = inline_divide_base<Src0TypeID, Src1TypeID, needs_zero_check<Src0TypeID, Src1TypeID>()>; } | |
namespace detail { template <type_id_t Src0TypeID, type_id_t Src1TypeID, bool check> struct inline_mod_base; template <type_id_t Src0TypeID, type_id_t Src1TypeID> struct inline_mod_base<Src0TypeID, Src1TypeID, true> { static auto f(typename type_of<Src0TypeID>::type a, typename type_of<Src1TypeID>::type b) { if (b == 0) { throw dynd::zero_division_error("Integer division or modulo by zero."); } return a % b; } }; template <type_id_t Src0TypeID, type_id_t Src1TypeID> struct inline_mod_base<Src0TypeID, Src1TypeID, false> { static auto f(typename type_of<Src0TypeID>::type a, typename type_of<Src1TypeID>::type b) { return a % b; } }; template <type_id_t Src0TypeID, type_id_t Src1TypeID> using inline_mod = inline_mod_base<Src0TypeID, Src1TypeID, needs_zero_check<Src0TypeID, Src1TypeID>()>; } | |
} | |
namespace ndt { | |
__pragma(warning(push)) __pragma(warning(disable : 4146)) | |
__pragma(warning(pop)) | |
} | |
} | |
namespace dynd { | |
namespace nd { | |
template <type_id_t Src0TypeID, type_id_t Src1TypeID> | |
using add_callable = functional::apply_function_callable<decltype(&detail::inline_add<Src0TypeID, Src1TypeID>::f), | |
&detail::inline_add<Src0TypeID, Src1TypeID>::f>; | |
} | |
} | |
namespace dynd { | |
namespace nd { | |
class base_dispatch_callable : public base_callable { | |
public: | |
using base_callable::base_callable; | |
ndt::type resolve(base_callable *, char *, call_graph &cg, | |
const ndt::type &dst_tp, size_t nsrc, const ndt::type *src_tp, size_t nkwd, const array *kwds, | |
const std::map<std::string, ndt::type> &tp_vars) { | |
const callable &child = specialize(dst_tp, nsrc, src_tp); | |
return child->resolve(this, nullptr, cg, dst_tp.is_symbolic() ? child.get_ret_type() : dst_tp, nsrc, src_tp, nkwd, | |
kwds, tp_vars); | |
} | |
}; | |
} | |
} | |
namespace dynd { | |
namespace nd { | |
template <size_t N> | |
class arithmetic_dispatch_callable; | |
template <> | |
class arithmetic_dispatch_callable<1> : public base_dispatch_callable { | |
dispatcher<callable> m_dispatcher; | |
public: | |
arithmetic_dispatch_callable(const ndt::type &tp, const dispatcher<callable> &dispatcher) | |
: base_dispatch_callable(tp), m_dispatcher(dispatcher) | |
{ | |
} | |
void overload(const ndt::type &, intptr_t , const ndt::type *src_tp, | |
const callable &value) | |
{ | |
m_dispatcher.insert({{src_tp[0].get_id()}, value}); | |
} | |
const callable &specialize(const ndt::type &, intptr_t , | |
const ndt::type *src_tp) | |
{ | |
return m_dispatcher(src_tp[0].get_id()); | |
} | |
}; | |
template <> | |
class arithmetic_dispatch_callable<2> : public base_dispatch_callable { | |
dispatcher<callable> m_dispatcher; | |
public: | |
arithmetic_dispatch_callable(const ndt::type &tp, const dispatcher<callable> &dispatcher) | |
: base_dispatch_callable(tp), m_dispatcher(dispatcher) | |
{ | |
} | |
void overload(const ndt::type &, intptr_t , const ndt::type *src_tp, | |
const callable &value) | |
{ | |
m_dispatcher.insert({{src_tp[0].get_id(), src_tp[1].get_id()}, value}); | |
} | |
const callable &specialize(const ndt::type &, intptr_t , | |
const ndt::type *src_tp) | |
{ | |
return m_dispatcher(src_tp[0].get_id(), src_tp[1].get_id()); | |
} | |
}; | |
} | |
} | |
namespace dynd { | |
namespace nd { | |
template <type_id_t Src0TypeID, type_id_t Src1TypeID> | |
using bitwise_and_callable = | |
functional::apply_function_callable<decltype(&detail::inline_bitwise_and<Src0TypeID, Src1TypeID>::f), | |
&detail::inline_bitwise_and<Src0TypeID, Src1TypeID>::f>; | |
} | |
} | |
namespace dynd { | |
namespace nd { | |
template <type_id_t Arg0ID> | |
using bitwise_not_callable = functional::apply_function_callable<decltype(&detail::inline_bitwise_not<Arg0ID>::f), | |
&detail::inline_bitwise_not<Arg0ID>::f>; | |
} | |
} | |
namespace dynd { | |
namespace nd { | |
template <type_id_t Src0TypeID, type_id_t Src1TypeID> | |
using bitwise_or_callable = | |
functional::apply_function_callable<decltype(&detail::inline_bitwise_or<Src0TypeID, Src1TypeID>::f), | |
&detail::inline_bitwise_or<Src0TypeID, Src1TypeID>::f>; | |
} | |
} | |
namespace dynd { | |
namespace nd { | |
template <type_id_t Src0TypeID, type_id_t Src1TypeID> | |
using bitwise_xor_callable = | |
functional::apply_function_callable<decltype(&detail::inline_bitwise_xor<Src0TypeID, Src1TypeID>::f), | |
&detail::inline_bitwise_xor<Src0TypeID, Src1TypeID>::f>; | |
} | |
} | |
namespace dynd { | |
namespace nd { | |
template <typename DstType, typename Src0Type, bool UseBinaryOperator> | |
struct compound_add_kernel; | |
template <typename DstType, typename Src0Type> | |
struct compound_add_kernel<DstType, Src0Type, false> | |
: base_strided_kernel<compound_add_kernel<DstType, Src0Type, false>, 1> { | |
typedef DstType dst_type; | |
typedef Src0Type src0_type; | |
void single(char *dst, char *const *src) | |
{ | |
*reinterpret_cast<dst_type *>(dst) += *reinterpret_cast<src0_type *>(src[0]); | |
} | |
void strided(char *dst, std::intptr_t dst_stride, char *const *src, const std::intptr_t *src_stride, | |
std::size_t count) | |
{ | |
char *src0 = src[0]; | |
std::intptr_t src0_stride = src_stride[0]; | |
for (std::size_t i = 0; i < count; ++i) { | |
*reinterpret_cast<dst_type *>(dst) += *reinterpret_cast<src0_type *>(src0); | |
dst += dst_stride; | |
src0 += src0_stride; | |
} | |
} | |
}; | |
template <typename DstType, typename Src0Type> | |
struct compound_add_kernel<DstType, Src0Type, true> | |
: base_strided_kernel<compound_add_kernel<DstType, Src0Type, true>, 1> { | |
typedef DstType dst_type; | |
typedef Src0Type src0_type; | |
void single(char *dst, char *const *src) | |
{ | |
*reinterpret_cast<dst_type *>(dst) = | |
static_cast<dst_type>(*reinterpret_cast<dst_type *>(dst) + *reinterpret_cast<src0_type *>(src[0])); | |
} | |
void strided(char *dst, std::intptr_t dst_stride, char *const *src, const std::intptr_t *src_stride, | |
std::size_t count) | |
{ | |
char *src0 = src[0]; | |
std::intptr_t src0_stride = src_stride[0]; | |
for (std::size_t i = 0; i < count; ++i) { | |
*reinterpret_cast<dst_type *>(dst) = | |
static_cast<dst_type>(*reinterpret_cast<dst_type *>(dst) + *reinterpret_cast<src0_type *>(src0)); | |
dst += dst_stride; | |
src0 += src0_stride; | |
} | |
} | |
}; | |
template <typename Src0Type> | |
struct compound_add_kernel<bool1, Src0Type, true> | |
: base_strided_kernel<compound_add_kernel<bool1, Src0Type, true>, 1> { | |
typedef bool1 dst_type; | |
typedef Src0Type src0_type; | |
void single(char *dst, char *const *src) | |
{ | |
*reinterpret_cast<dst_type *>(dst) = | |
*reinterpret_cast<dst_type *>(dst) + *reinterpret_cast<src0_type *>(src[0]) ? true : false; | |
} | |
void strided(char *dst, std::intptr_t dst_stride, char *const *src, const std::intptr_t *src_stride, | |
std::size_t count) | |
{ | |
char *src0 = src[0]; | |
std::intptr_t src0_stride = src_stride[0]; | |
for (std::size_t i = 0; i < count; ++i) { | |
*reinterpret_cast<dst_type *>(dst) = | |
*reinterpret_cast<dst_type *>(dst) + *reinterpret_cast<src0_type *>(src0) ? true : false; | |
dst += dst_stride; | |
src0 += src0_stride; | |
} | |
} | |
}; | |
template <type_id_t DstTypeID, type_id_t Src0TypeID> | |
struct compound_add_kernel_t | |
: compound_add_kernel<typename type_of<DstTypeID>::type, typename type_of<Src0TypeID>::type, | |
!is_lossless_assignable<DstTypeID, Src0TypeID>::value> { | |
}; | |
} | |
} | |
namespace dynd { | |
namespace nd { | |
template <type_id_t DstTypeID, type_id_t Src0TypeID> | |
class compound_add_callable : public default_instantiable_callable<compound_add_kernel_t<DstTypeID, Src0TypeID>> { | |
public: | |
compound_add_callable() | |
: default_instantiable_callable<compound_add_kernel_t<DstTypeID, Src0TypeID>>( | |
ndt::callable_type::make(ndt::type(DstTypeID), ndt::type(Src0TypeID))) | |
{ | |
} | |
}; | |
} | |
} | |
namespace dynd { | |
namespace nd { | |
class compound_arithmetic_dispatch_callable : public base_dispatch_callable { | |
dispatcher<callable> m_dispatcher; | |
public: | |
compound_arithmetic_dispatch_callable(const ndt::type &tp, const dispatcher<callable> &dispatcher) | |
: base_dispatch_callable(tp), m_dispatcher(dispatcher) | |
{ | |
} | |
void overload(const ndt::type &dst_tp, intptr_t , const ndt::type *src_tp, const callable &value) | |
{ | |
m_dispatcher.insert({{dst_tp.get_id(), src_tp[0].get_id()}, value}); | |
} | |
const callable &specialize(const ndt::type &dst_tp, intptr_t , const ndt::type *src_tp) | |
{ | |
return m_dispatcher(dst_tp.get_id(), src_tp[0].get_id()); | |
} | |
}; | |
} | |
} | |
namespace dynd { | |
namespace nd { | |
template <typename DstType, typename Src0Type, bool UseBinaryOperator> | |
struct compound_div_kernel; | |
template <typename DstType, typename Src0Type> | |
struct compound_div_kernel<DstType, Src0Type, false> | |
: base_strided_kernel<compound_div_kernel<DstType, Src0Type, false>, 1> { | |
typedef DstType dst_type; | |
typedef Src0Type src0_type; | |
void single(char *dst, char *const *src) | |
{ | |
*reinterpret_cast<dst_type *>(dst) /= *reinterpret_cast<src0_type *>(src[0]); | |
} | |
void strided(char *dst, std::intptr_t dst_stride, char *const *src, const std::intptr_t *src_stride, | |
std::size_t count) | |
{ | |
char *src0 = src[0]; | |
std::intptr_t src0_stride = src_stride[0]; | |
for (std::size_t i = 0; i < count; ++i) { | |
*reinterpret_cast<dst_type *>(dst) /= *reinterpret_cast<src0_type *>(src0); | |
dst += dst_stride; | |
src0 += src0_stride; | |
} | |
} | |
}; | |
template <typename DstType, typename Src0Type> | |
struct compound_div_kernel<DstType, Src0Type, true> | |
: base_strided_kernel<compound_div_kernel<DstType, Src0Type, true>, 1> { | |
typedef DstType dst_type; | |
typedef Src0Type src0_type; | |
void single(char *dst, char *const *src) | |
{ | |
*reinterpret_cast<dst_type *>(dst) = | |
static_cast<dst_type>(*reinterpret_cast<dst_type *>(dst) / *reinterpret_cast<src0_type *>(src[0])); | |
} | |
void strided(char *dst, std::intptr_t dst_stride, char *const *src, const std::intptr_t *src_stride, | |
std::size_t count) | |
{ | |
char *src0 = src[0]; | |
std::intptr_t src0_stride = src_stride[0]; | |
for (std::size_t i = 0; i < count; ++i) { | |
*reinterpret_cast<dst_type *>(dst) = | |
static_cast<dst_type>(*reinterpret_cast<dst_type *>(dst) / *reinterpret_cast<src0_type *>(src0)); | |
dst += dst_stride; | |
src0 += src0_stride; | |
} | |
} | |
}; | |
template <typename Src0Type> | |
struct compound_div_kernel<bool1, Src0Type, true> | |
: base_strided_kernel<compound_div_kernel<bool1, Src0Type, true>, 1> { | |
typedef bool1 dst_type; | |
typedef Src0Type src0_type; | |
void single(char *dst, char *const *src) | |
{ | |
*reinterpret_cast<dst_type *>(dst) = | |
*reinterpret_cast<dst_type *>(dst) / *reinterpret_cast<src0_type *>(src[0]) ? true : false; | |
} | |
void strided(char *dst, std::intptr_t dst_stride, char *const *src, const std::intptr_t *src_stride, | |
std::size_t count) | |
{ | |
char *src0 = src[0]; | |
std::intptr_t src0_stride = src_stride[0]; | |
for (std::size_t i = 0; i < count; ++i) { | |
*reinterpret_cast<dst_type *>(dst) = | |
*reinterpret_cast<dst_type *>(dst) / *reinterpret_cast<src0_type *>(src0) ? true : false; | |
dst += dst_stride; | |
src0 += src0_stride; | |
} | |
} | |
}; | |
template <type_id_t DstTypeID, type_id_t Src0TypeID> | |
struct compound_div_kernel_t | |
: compound_div_kernel<typename type_of<DstTypeID>::type, typename type_of<Src0TypeID>::type, | |
!is_lossless_assignable<DstTypeID, Src0TypeID>::value> { | |
}; | |
} | |
} | |
namespace dynd { | |
namespace nd { | |
template <type_id_t DstTypeID, type_id_t Src0TypeID> | |
class compound_div_callable : public default_instantiable_callable<compound_div_kernel_t<DstTypeID, Src0TypeID>> { | |
public: | |
compound_div_callable() | |
: default_instantiable_callable<compound_div_kernel_t<DstTypeID, Src0TypeID>>( | |
ndt::callable_type::make(ndt::type(DstTypeID), ndt::type(Src0TypeID))) | |
{ | |
} | |
}; | |
} | |
} | |
namespace dynd { | |
namespace nd { | |
template <type_id_t Arg0ID, type_id_t Arg1ID> | |
using divide_callable = functional::apply_function_callable<decltype(&detail::inline_divide<Arg0ID, Arg1ID>::f), | |
&detail::inline_divide<Arg0ID, Arg1ID>::f>; | |
} | |
} | |
namespace dynd { | |
namespace nd { | |
template <type_id_t Src0TypeID, type_id_t Src1TypeID> | |
using left_shift_callable = | |
functional::apply_function_callable<decltype(&detail::inline_left_shift<Src0TypeID, Src1TypeID>::f), | |
&detail::inline_left_shift<Src0TypeID, Src1TypeID>::f>; | |
} | |
} | |
namespace dynd { | |
namespace nd { | |
template <type_id_t Src0TypeID, type_id_t Src1TypeID> | |
using logical_and_callable = | |
functional::apply_function_callable<decltype(&detail::inline_logical_and<Src0TypeID, Src1TypeID>::f), | |
&detail::inline_logical_and<Src0TypeID, Src1TypeID>::f>; | |
} | |
} | |
namespace dynd { | |
namespace nd { | |
template <type_id_t Arg0ID> | |
using logical_not_callable = functional::apply_function_callable<decltype(&detail::inline_logical_not<Arg0ID>::f), | |
&detail::inline_logical_not<Arg0ID>::f>; | |
} | |
} | |
namespace dynd { | |
namespace nd { | |
template <type_id_t Src0TypeID, type_id_t Src1TypeID> | |
using logical_or_callable = | |
functional::apply_function_callable<decltype(&detail::inline_logical_or<Src0TypeID, Src1TypeID>::f), | |
&detail::inline_logical_or<Src0TypeID, Src1TypeID>::f>; | |
} | |
} | |
namespace dynd { | |
namespace nd { | |
template <type_id_t Src0TypeID, type_id_t Src1TypeID> | |
using logical_xor_callable = | |
functional::apply_function_callable<decltype(&detail::inline_logical_xor<Src0TypeID, Src1TypeID>::f), | |
&detail::inline_logical_xor<Src0TypeID, Src1TypeID>::f>; | |
} | |
} | |
namespace dynd { | |
namespace nd { | |
template <type_id_t Arg0ID, type_id_t Arg1ID> | |
using mod_callable = functional::apply_function_callable<decltype(&detail::inline_mod<Arg0ID, Arg1ID>::f), | |
&detail::inline_mod<Arg0ID, Arg1ID>::f>; | |
} | |
} | |
namespace dynd { | |
namespace nd { | |
template <type_id_t Arg0ID> | |
using minus_callable = | |
functional::apply_function_callable<decltype(&detail::inline_minus<Arg0ID>::f), &detail::inline_minus<Arg0ID>::f>; | |
} | |
} | |
namespace dynd { | |
namespace nd { | |
template <type_id_t Src0TypeID, type_id_t Src1TypeID> | |
using multiply_callable = | |
functional::apply_function_callable<decltype(&detail::inline_multiply<Src0TypeID, Src1TypeID>::f), | |
&detail::inline_multiply<Src0TypeID, Src1TypeID>::f>; | |
} | |
} | |
namespace dynd { | |
namespace nd { | |
template <type_id_t Arg0ID> | |
using plus_callable = | |
functional::apply_function_callable<decltype(&detail::inline_plus<Arg0ID>::f), &detail::inline_plus<Arg0ID>::f>; | |
} | |
} | |
namespace dynd { | |
namespace nd { | |
template <type_id_t Src0TypeID, type_id_t Src1TypeID> | |
using right_shift_callable = | |
functional::apply_function_callable<decltype(&detail::inline_right_shift<Src0TypeID, Src1TypeID>::f), | |
&detail::inline_right_shift<Src0TypeID, Src1TypeID>::f>; | |
} | |
} | |
namespace dynd { | |
namespace nd { | |
template <type_id_t Src0TypeID, type_id_t Src1TypeID> | |
using subtract_callable = | |
functional::apply_function_callable<decltype(&detail::inline_subtract<Src0TypeID, Src1TypeID>::f), | |
&detail::inline_subtract<Src0TypeID, Src1TypeID>::f>; | |
} | |
} | |
namespace dynd { | |
namespace nd { | |
template <type_id_t Src0TypeID> | |
struct __declspec(dllexport) sum_kernel : base_strided_kernel<sum_kernel<Src0TypeID>, 1> { | |
typedef typename type_of<Src0TypeID>::type src0_type; | |
typedef src0_type dst_type; | |
void single(char *dst, char *const *src) | |
{ | |
*reinterpret_cast<dst_type *>(dst) = *reinterpret_cast<dst_type *>(dst) + *reinterpret_cast<src0_type *>(src[0]); | |
} | |
void strided(char *dst, intptr_t dst_stride, char *const *src, const intptr_t *src_stride, size_t count) | |
{ | |
char *src0 = src[0]; | |
intptr_t src0_stride = src_stride[0]; | |
for (size_t i = 0; i < count; ++i) { | |
*reinterpret_cast<dst_type *>(dst) = *reinterpret_cast<dst_type *>(dst) + *reinterpret_cast<src0_type *>(src0); | |
dst += dst_stride; | |
src0 += src0_stride; | |
} | |
} | |
}; | |
} | |
} | |
namespace dynd { | |
namespace nd { | |
template <type_id_t Arg0ID> | |
class sum_callable : public default_instantiable_callable<sum_kernel<Arg0ID>> { | |
public: | |
sum_callable() | |
: default_instantiable_callable<sum_kernel<Arg0ID>>( | |
ndt::callable_type::make(ndt::make_type<typename nd::sum_kernel<Arg0ID>::dst_type>(), ndt::type(Arg0ID))) | |
{ | |
} | |
}; | |
} | |
} | |
namespace dynd { | |
namespace nd { | |
class sum_dispatch_callable : public base_dispatch_callable { | |
dispatcher<callable> m_dispatcher; | |
public: | |
sum_dispatch_callable(const ndt::type &tp, const dispatcher<callable> &dispatcher) | |
: base_dispatch_callable(tp), m_dispatcher(dispatcher) | |
{ | |
} | |
void overload(const ndt::type &, intptr_t , const ndt::type *src_tp, | |
const callable &value) | |
{ | |
m_dispatcher.insert({{src_tp[0].get_dtype().get_id()}, value}); | |
} | |
const callable &specialize(const ndt::type &, intptr_t , | |
const ndt::type *src_tp) | |
{ | |
return m_dispatcher(src_tp[0].get_dtype().get_id()); | |
} | |
}; | |
} | |
} | |
namespace dynd { | |
namespace nd { | |
namespace functional { | |
template <typename T, typename mem_func_type, int N> | |
class apply_member_function_callable : public base_callable { | |
T m_obj; | |
mem_func_type m_mem_func; | |
public: | |
template <typename... S> | |
apply_member_function_callable(T obj, mem_func_type mem_func, S &&... names) | |
: base_callable(ndt::make_type<mem_func_type>(std::forward<S>(names)...)), m_obj(obj), m_mem_func(mem_func) {} | |
ndt::type resolve(base_callable *, char *, call_graph &cg, | |
const ndt::type &dst_tp, size_t , const ndt::type *, | |
size_t nkwd, const array *kwds, const std::map<std::string, ndt::type> &) { | |
typedef apply_member_function_kernel<T, mem_func_type, N> kernel_type; | |
cg.emplace_back([ obj = m_obj, mem_func = m_mem_func, kwds = typename kernel_type::kwds_type(nkwd, kwds) ]( | |
kernel_builder &kb, kernel_request_t kernreq, const char *, | |
size_t , const char *const *src_arrmeta) { | |
kb.emplace_back<kernel_type>(kernreq, obj, mem_func, typename kernel_type::args_type(src_arrmeta, nullptr), | |
kwds); | |
}); | |
return dst_tp; | |
} | |
}; | |
} | |
} | |
} | |
namespace dynd { | |
namespace nd { | |
namespace functional { | |
template <typename func_type, typename... KwdTypes> | |
class construct_then_apply_callable_callable : public base_callable { | |
public: | |
template <typename... T> | |
construct_then_apply_callable_callable(T &&... names) | |
: base_callable( | |
ndt::make_type<typename funcproto_of<func_type, KwdTypes...>::type>(std::forward<T>(names)...)) {} | |
ndt::type resolve(base_callable *, char *, call_graph &cg, | |
const ndt::type &dst_tp, size_t , const ndt::type *, | |
size_t nkwd, const array *kwds, const std::map<std::string, ndt::type> &) { | |
typedef construct_then_apply_callable_kernel<func_type, KwdTypes...> kernel_type; | |
cg.emplace_back([kwds = typename kernel_type::kwds_type(nkwd, kwds)]( | |
kernel_builder &kb, kernel_request_t kernreq, const char *, | |
size_t , const char *const *src_arrmeta) { | |
kb.emplace_back<kernel_type>(kernreq, typename kernel_type::args_type(src_arrmeta, nullptr), kwds); | |
}); | |
return dst_tp; | |
} | |
}; | |
} | |
} | |
} | |
namespace dynd { | |
template <typename ValueType> | |
struct option { | |
ValueType value; | |
option() : value(ndt::traits<ValueType>::na()) {} | |
option(ValueType value) : value(value) {} | |
}; | |
template <typename ValueType> | |
option<ValueType> opt() | |
{ | |
return option<ValueType>(); | |
} | |
template <typename ValueType> | |
option<ValueType> opt(ValueType value) | |
{ | |
return option<ValueType>(value); | |
} | |
__declspec(dllimport) void assign_na_builtin(type_id_t value_id, char *data); | |
__declspec(dllimport) bool is_avail_builtin(type_id_t value_id, const char *data); | |
namespace ndt { | |
class __declspec(dllimport) option_type : public base_type { | |
type m_value_tp; | |
public: | |
option_type(const type &value_tp); | |
size_t get_default_data_size() const { return m_value_tp.get_default_data_size(); } | |
void get_vars(std::unordered_set<std::string> &vars) const; | |
const type &get_value_type() const { return m_value_tp.value_type(); } | |
void print_type(std::ostream &o) const; | |
void print_data(std::ostream &o, const char *arrmeta, const char *data) const; | |
bool is_expression() const; | |
bool is_unique_data_owner(const char *arrmeta) const; | |
void transform_child_types(type_transform_fn_t transform_fn, intptr_t arrmeta_offset, void *extra, | |
type &out_transformed_tp, bool &out_was_transformed) const; | |
type get_canonical_type() const; | |
type get_type_at_dimension(char **inout_arrmeta, intptr_t i, intptr_t total_ndim = 0) const; | |
bool is_lossless_assignment(const type &dst_tp, const type &src_tp) const; | |
bool operator==(const base_type &rhs) const; | |
void arrmeta_default_construct(char *arrmeta, bool blockref_alloc) const; | |
void arrmeta_copy_construct(char *dst_arrmeta, const char *src_arrmeta, | |
const intrusive_ptr<memory_block_data> &embedded_reference) const; | |
void arrmeta_reset_buffers(char *arrmeta) const; | |
void arrmeta_finalize_buffers(char *arrmeta) const; | |
void arrmeta_destruct(char *arrmeta) const; | |
void arrmeta_debug_print(const char *arrmeta, std::ostream &o, const std::string &indent) const; | |
void data_destruct(const char *arrmeta, char *data) const; | |
void data_destruct_strided(const char *arrmeta, char *data, intptr_t stride, size_t count) const; | |
bool match(const type &candidate_tp, std::map<std::string, type> &tp_vars) const; | |
std::map<std::string, std::pair<ndt::type, const char *>> get_dynamic_type_properties() const; | |
}; | |
template <typename ValueType> | |
struct traits<option<ValueType>> { | |
static const bool is_same_layout = true; | |
static type equivalent() { return make_type<option_type>(make_type<ValueType>()); } | |
}; | |
} | |
} | |
namespace dynd { | |
namespace nd { | |
extern __declspec(dllexport) callable assign_na; | |
extern __declspec(dllexport) callable is_na; | |
__declspec(dllexport) void old_assign_na(const ndt::type &option_tp, const char *arrmeta, char *data); | |
__declspec(dllexport) bool old_is_avail(const ndt::type &option_tp, const char *arrmeta, const char *data); | |
__declspec(dllexport) void set_option_from_utf8_string(const ndt::type &option_tp, const char *arrmeta, char *data, | |
const char *utf8_begin, const char *utf8_end, | |
const eval::eval_context *ectx); | |
inline void set_option_from_utf8_string(const ndt::type &option_tp, const char *arrmeta, char *data, | |
const std::string &utf8_str, const eval::eval_context *ectx) | |
{ | |
set_option_from_utf8_string(option_tp, arrmeta, data, utf8_str.data(), utf8_str.data() + utf8_str.size(), ectx); | |
} | |
} | |
} | |
namespace dynd { | |
namespace nd { | |
template <intptr_t... I> | |
struct forward_na_kernel : base_strided_kernel<forward_na_kernel<I...>, 2> { | |
size_t is_na_offset[2]; | |
size_t assign_na_offset; | |
void single(char *res, char *const *args) { | |
// Next non-comment line builds if replaced with: | |
// for (intptr_t i : std::array<intptr_t, sizeof...(I)>({I...})) { | |
for (intptr_t i : {I...}) { | |
bool1 is_na; | |
this->get_child(is_na_offset[i])->single(reinterpret_cast<char *>(&is_na), args + i); | |
if (is_na) { | |
return this->get_child(assign_na_offset)->single(res, nullptr); | |
} | |
} | |
this->get_child()->single(res, args); | |
} | |
}; | |
} | |
} | |
namespace dynd { | |
namespace nd { | |
typedef intptr_t index_t; | |
template <index_t... I> | |
class forward_na_callable : public base_callable { | |
callable m_child; | |
public: | |
forward_na_callable(const ndt::type &tp, const callable &child) : base_callable(tp), m_child(child) {} | |
ndt::type resolve(base_callable *caller, char *, call_graph &cg, const ndt::type &dst_tp, | |
size_t , const ndt::type *src_tp, size_t nkwd, const array *kwds, | |
const std::map<std::string, ndt::type> &tp_vars) { | |
cg.emplace_back([](kernel_builder &kb, kernel_request_t kernreq, const char *dst_arrmeta, size_t nsrc, | |
const char *const *src_arrmeta) { | |
size_t self_offset = kb.size(); | |
kb.emplace_back<forward_na_kernel<I...>>(kernreq); | |
kb(kernel_request_single, dst_arrmeta, nsrc, src_arrmeta); | |
for (intptr_t i : std::array<index_t, sizeof...(I)>({I...})) { | |
size_t is_na_offset = kb.size() - self_offset; | |
kb(kernel_request_single, nullptr, 1, src_arrmeta + i); | |
kb.get_at<forward_na_kernel<I...>>(self_offset)->is_na_offset[i] = is_na_offset; | |
} | |
size_t assign_na_offset = kb.size() - self_offset; | |
kb(kernel_request_single, nullptr, 0, nullptr); | |
kb.get_at<forward_na_kernel<I...>>(self_offset)->assign_na_offset = assign_na_offset; | |
}); | |
ndt::type src_value_tp[2]; | |
for (intptr_t i = 0; i < 2; ++i) { | |
src_value_tp[i] = src_tp[i]; | |
} | |
for (intptr_t i : std::array<index_t, sizeof...(I)>({I...})) { | |
src_value_tp[i] = src_value_tp[i].extended<ndt::option_type>()->get_value_type(); | |
} | |
base_callable *child; | |
if (m_child.is_null()) { | |
child = caller; | |
} else { | |
child = m_child.get(); | |
} | |
ndt::type res_value_tp = | |
child->resolve(this, nullptr, cg, dst_tp.is_symbolic() ? child->get_return_type() : dst_tp, 2, src_value_tp, | |
nkwd, kwds, tp_vars); | |
for (index_t i : std::array<index_t, sizeof...(I)>({I...})) { | |
is_na->resolve(this, nullptr, cg, ndt::make_type<bool>(), 1, src_tp + i, 0, nullptr, tp_vars); | |
} | |
return assign_na->resolve(this, nullptr, cg, ndt::make_type<ndt::option_type>(res_value_tp), 0, nullptr, nkwd, | |
kwds, tp_vars); | |
} | |
}; | |
} | |
} | |
namespace dynd { | |
namespace nd { | |
namespace functional { | |
__declspec(dllexport) callable adapt(const ndt::type &value_tp, const callable &forward); | |
template <typename func_type, func_type func, typename... T> | |
callable apply(T &&... names) { | |
return make_callable<apply_function_callable<func_type, func, arity_of<func_type>::value - sizeof...(T)>>( | |
std::forward<T>(names)...); | |
} | |
template <typename func_type, typename... T> | |
typename std::enable_if<!is_function_pointer<func_type>::value, callable>::type apply(func_type func, | |
T &&... names) { | |
static_assert(all_char_string_params<T...>::value, "All the names must be strings"); | |
return make_callable<apply_callable_callable<func_type, arity_of<func_type>::value - sizeof...(T)>>( | |
func, std::forward<T>(names)...); | |
} | |
template <typename func_type, typename... T> | |
callable apply(func_type *func, T &&... names) { | |
return make_callable<apply_callable_callable<func_type *, arity_of<func_type>::value - sizeof...(T)>>( | |
func, std::forward<T>(names)...); | |
} | |
template <typename func_type, typename... KwdTypes, typename... T> | |
callable apply(T &&... names) { | |
return make_callable<construct_then_apply_callable_callable<func_type, KwdTypes...>>(std::forward<T>(names)...); | |
} | |
template <typename T, typename R, typename... A, typename... S> | |
callable apply(T *obj, R (T::*mem_func)(A...), S &&... names) { | |
return make_callable<apply_member_function_callable<T *, R (T::*)(A...), sizeof...(A) - sizeof...(S)>>( | |
obj, mem_func, std::forward<S>(names)...); | |
} | |
__declspec(dllexport) callable compose(const callable &first, const callable &second, const ndt::type &buf_tp = ndt::type()); | |
__declspec(dllexport) callable constant(const array &val); | |
__declspec(dllexport) callable left_compound(const callable &child); | |
__declspec(dllexport) callable right_compound(const callable &child); | |
__declspec(dllexport) callable elwise(const callable &child); | |
__declspec(dllexport) callable elwise(const ndt::type &tp); | |
__declspec(dllexport) callable elwise(const ndt::type &self_tp, const callable &child); | |
__declspec(dllexport) ndt::type elwise_make_type(const ndt::callable_type *child_tp); | |
template <int... I> | |
callable forward_na(const ndt::type &ret_tp) { | |
ndt::type tp = | |
ndt::callable_type::make(ndt::make_type<ndt::option_type>(ret_tp), {ndt::type("Any"), ndt::type("Any")}); | |
return make_callable<forward_na_callable<I...>>(tp, callable()); | |
} | |
template <int... I> | |
callable forward_na(const callable &child) { | |
ndt::type tp = ndt::callable_type::make(ndt::make_type<ndt::option_type>(child.get_ret_type()), | |
{ndt::type("Any"), ndt::type("Any")}); | |
return make_callable<forward_na_callable<I...>>(tp, child); | |
} | |
__declspec(dllexport) callable outer(const callable &child); | |
__declspec(dllexport) ndt::type outer_make_type(const ndt::callable_type *child_tp); | |
__declspec(dllexport) callable neighborhood(const callable &child, const callable &boundary_child = callable()); | |
__declspec(dllexport) callable reduction(const callable &child); | |
__declspec(dllexport) callable reduction(const callable &child, | |
const std::initializer_list<std::pair<const char *, array>> &kwds); | |
} | |
} | |
} | |
namespace dynd { | |
namespace ndt { | |
class __declspec(dllimport) scalar_kind_type : public base_type { | |
public: | |
scalar_kind_type(); | |
bool operator==(const base_type &rhs) const; | |
bool match(const type &candidate_tp, std::map<std::string, type> &tp_vars) const; | |
void print_type(std::ostream &o) const; | |
static type make() { return type(new scalar_kind_type(), false); } | |
}; | |
} | |
} | |
using namespace std; | |
using namespace dynd; | |
namespace { | |
typedef type_id_sequence<uint8_id, uint16_id, uint32_id, uint64_id, int8_id, int16_id, int32_id, int64_id, float32_id, | |
float64_id, complex_float32_id, complex_float64_id> | |
binop_ids; | |
typedef type_id_sequence<uint8_id, uint16_id, uint32_id, uint64_id, int8_id, int16_id, int32_id, int64_id, float32_id, | |
float64_id> | |
binop_real_ids; | |
template <template <type_id_t> class CallableType, template <type_id_t> class Condition, typename TypeIDSequence> | |
nd::callable make_unary_arithmetic() { | |
dispatcher<nd::callable> dispatcher = nd::callable::make_all_if<CallableType, Condition, TypeIDSequence>(); | |
const ndt::type &tp = ndt::type("(Any) -> Any"); | |
for (type_id_t i0 : i2a<dim_ids>()) { | |
dispatcher.insert({{i0}, nd::functional::elwise(tp)}); | |
} | |
return nd::make_callable<nd::arithmetic_dispatch_callable<1>>(tp, dispatcher); | |
} | |
template <template <type_id_t, type_id_t> class KernelType, template <type_id_t, type_id_t> class Condition, | |
typename TypeIDSequence> | |
nd::callable make_binary_arithmetic() { | |
const ndt::type &tp = ndt::type("(Any, Any) -> Any"); | |
auto dispatcher = nd::callable::make_all_if<KernelType, Condition, TypeIDSequence, TypeIDSequence>(); | |
dispatcher.insert({{{option_id, any_kind_id}, nd::functional::forward_na<0>(ndt::type("Any"))}, | |
{{any_kind_id, option_id}, nd::functional::forward_na<1>(ndt::type("Any"))}, | |
{{option_id, option_id}, nd::functional::forward_na<0, 1>(ndt::type("Any"))}, | |
{{dim_kind_id, scalar_kind_id}, nd::functional::elwise(tp)}, | |
{{scalar_kind_id, dim_kind_id}, nd::functional::elwise(tp)}, | |
{{dim_kind_id, dim_kind_id}, nd::functional::elwise(tp)}}); | |
return nd::make_callable<nd::arithmetic_dispatch_callable<2>>(tp, dispatcher); | |
} | |
template <template <type_id_t, type_id_t> class KernelType, typename TypeIDSequence> | |
nd::callable make_compound_arithmetic() { | |
const ndt::type &tp = ndt::type("(Any, Any) -> Any"); | |
auto dispatcher = nd::callable::new_make_all<KernelType, TypeIDSequence, TypeIDSequence>(); | |
for (type_id_t i0 : i2a<TypeIDSequence>()) { | |
for (type_id_t i1 : i2a<dim_ids>()) { | |
dispatcher.insert({{i0, i1}, nd::functional::elwise(tp)}); | |
} | |
} | |
for (type_id_t i0 : i2a<dim_ids>()) { | |
typedef typename join<TypeIDSequence, dim_ids>::type broadcast_ids; | |
for (type_id_t i1 : i2a<broadcast_ids>()) { | |
dispatcher.insert({{i0, i1}, nd::functional::elwise(tp)}); | |
} | |
} | |
return nd::make_callable<nd::compound_arithmetic_dispatch_callable>(tp, dispatcher); | |
} | |
} | |
__declspec(dllexport) nd::callable nd::plus = make_unary_arithmetic<nd::plus_callable, dynd::detail::isdef_plus, arithmetic_ids>(); | |
__declspec(dllexport) nd::callable nd::minus = | |
make_unary_arithmetic<nd::minus_callable, dynd::detail::isdef_minus, arithmetic_ids>(); | |
__declspec(dllexport) nd::callable nd::logical_not = | |
make_unary_arithmetic<nd::logical_not_callable, dynd::detail::isdef_logical_not, arithmetic_ids>(); | |
__declspec(dllexport) nd::callable nd::bitwise_not = | |
make_unary_arithmetic<nd::bitwise_not_callable, dynd::detail::isdef_bitwise_not, integral_ids>(); | |
__declspec(dllexport) nd::callable nd::add = make_binary_arithmetic<nd::add_callable, dynd::detail::isdef_add, binop_ids>(); | |
__declspec(dllexport) nd::callable nd::subtract = | |
make_binary_arithmetic<nd::subtract_callable, dynd::detail::isdef_subtract, binop_ids>(); | |
__declspec(dllexport) nd::callable nd::multiply = | |
make_binary_arithmetic<nd::multiply_callable, dynd::detail::isdef_multiply, binop_ids>(); | |
__declspec(dllexport) nd::callable nd::divide = make_binary_arithmetic<nd::divide_callable, dynd::detail::isdef_divide, binop_ids>(); | |
__declspec(dllexport) nd::callable nd::logical_and = | |
make_binary_arithmetic<nd::logical_and_callable, dynd::detail::isdef_logical_and, binop_real_ids>(); | |
__declspec(dllexport) nd::callable nd::logical_or = | |
make_binary_arithmetic<nd::logical_or_callable, dynd::detail::isdef_logical_or, binop_real_ids>(); | |
__declspec(dllexport) nd::callable nd::compound_add = make_compound_arithmetic<nd::compound_add_callable, binop_ids>(); | |
__declspec(dllexport) nd::callable nd::compound_div = make_compound_arithmetic<nd::compound_div_callable, binop_ids>(); | |
__declspec(dllexport) nd::callable nd::sum = nd::functional::reduction(nd::make_callable<nd::sum_dispatch_callable>( | |
ndt::callable_type::make(ndt::scalar_kind_type::make(), ndt::scalar_kind_type::make()), | |
nd::callable::new_make_all< | |
nd::sum_callable, | |
type_id_sequence<int8_id, int16_id, int32_id, int64_id, uint8_id, uint16_id, uint32_id, uint64_id, float16_id, | |
float32_id, float64_id, complex_float32_id, complex_float64_id>>())); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment