| Server IP : 217.160.0.135 / Your IP : 216.73.217.117 Web Server : Apache System : Linux www 6.18.52-i1-ampere #1203 SMP Mon Sep 14 18:29:59 CEST 2026 aarch64 User : sws1074145052 ( 1074145052) PHP Version : 8.3.32 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : OFF | Sudo : OFF | Pkexec : OFF Directory : /lib/python3/dist-packages/pythran/pythonic/include/types/ |
Upload File : |
#ifndef PYTHONIC_INCLUDE_TYPES_TUPLE_HPP
#define PYTHONIC_INCLUDE_TYPES_TUPLE_HPP
#include "pythonic/include/types/assignable.hpp"
#include "pythonic/include/types/traits.hpp"
#include "pythonic/include/types/nditerator.hpp"
#include "pythonic/include/utils/int_.hpp"
#include "pythonic/include/utils/seq.hpp"
#include "pythonic/include/utils/nested_container.hpp"
#include <tuple>
#include <algorithm>
#if !defined(HAVE_SSIZE_T) || !HAVE_SSIZE_T
#if defined(_MSC_VER)
#include <BaseTsd.h>
typedef SSIZE_T ssize_t;
#endif
#endif
// Equality comparison between pair && tuple
namespace std
{
template <class F0, class S0, class F1, class S1>
bool operator==(pair<F0, S0> const &self, tuple<F1, S1> const &other);
template <class F0, class S0, class F1, class S1>
bool operator==(pair<const F0, S0> const &self, tuple<F1, S1> const &other);
}
// Tuple concatenation with operator+
template <class... Types0, class... Types1>
std::tuple<Types0..., Types1...> operator+(std::tuple<Types0...> const &t0,
std::tuple<Types1...> const &t1);
template <class... Types0, class... Types1>
std::tuple<Types0..., Types1...> operator+(std::tuple<Types0...> &&t0,
std::tuple<Types1...> const &t1);
template <class... Types0, class... Types1>
std::tuple<Types0..., Types1...> operator+(std::tuple<Types0...> const &t0,
std::tuple<Types1...> &&t1);
template <class... Types0, class... Types1>
std::tuple<Types0..., Types1...> operator+(std::tuple<Types0...> &&t0,
std::tuple<Types1...> &&t1);
PYTHONIC_NS_BEGIN
namespace types
{
template <class T>
struct iterator {
using type = T;
};
template <typename T>
struct dynamic_tuple;
template <typename T, size_t N, class V>
struct array_base;
struct tuple_version {
};
struct list_version {
};
template <class T, size_t N>
using array = array_base<T, N, tuple_version>;
template <class T, size_t N>
using static_list = array_base<T, N, list_version>;
template <class T>
struct is_pod_array {
static constexpr bool value = false;
};
template <typename T, size_t N, class V>
struct is_pod_array<types::array_base<T, N, V>> {
static constexpr bool value = true;
};
template <class... Tys>
struct pshape;
template <class T, class pS>
struct ndarray;
class str;
struct slice;
struct contiguous_slice;
/* helper to extract the tail of a tuple, && pop the head */
template <int Offset, class T, size_t... N>
auto make_tuple_tail(T const &t, utils::index_sequence<N...>)
-> decltype(std::make_tuple(std::get<Offset + 1 + N>(t)...))
{
return std::make_tuple(std::get<Offset + 1 + N>(t)...);
}
template <class S, class... Stail>
std::tuple<Stail...> tuple_tail(std::tuple<S, Stail...> const &t);
template <class... S>
struct count_trailing_long : std::integral_constant<size_t, 0> {
};
template <class... S>
struct count_trailing_long<long, S...>
: std::integral_constant<size_t, 1 + count_trailing_long<S...>::value> {
};
template <class S, class... Stail>
auto tuple_pop(std::tuple<S, Stail...> const &t)
-> decltype(make_tuple_tail<count_trailing_long<Stail...>::value>(
t, utils::make_index_sequence<
sizeof...(Stail)-count_trailing_long<Stail...>::value>{}))
{
return make_tuple_tail<count_trailing_long<Stail...>::value>(
t, utils::make_index_sequence<sizeof...(
Stail)-count_trailing_long<Stail...>::value>{});
}
template <class A, size_t... I, class... Types>
std::tuple<Types...> array_to_tuple(A const &a, utils::index_sequence<I...>,
utils::type_sequence<Types...>)
{
return std::tuple<Types...>(a[I]...);
}
template <class... Tys>
struct pshape;
template <class... Tys>
struct iterator<pshape<Tys...>> {
using type = array<long, sizeof...(Tys)>;
};
template <long N>
long check_type(long, std::integral_constant<long, N>)
{
return N;
}
long check_type(long, long value)
{
return value;
}
template <long N, long P>
std::integral_constant<long, N> check_type(std::integral_constant<long, N>,
std::integral_constant<long, P>)
{
assert(N == P && "consistent init");
return {};
}
template <long N>
std::integral_constant<long, N> check_type(std::integral_constant<long, N>,
long v)
{
assert(N == v && "consistent init");
return {};
}
template <class T>
struct is_pshape_element : std::is_integral<T> {
};
template <long N>
struct is_pshape_element<std::integral_constant<long, N>> : std::true_type {
};
template <class... Tys>
struct pshape {
static_assert(utils::all_of<is_pshape_element<Tys>::value...>::value,
"valid pshape");
std::tuple<Tys...> values;
template <class... Args, size_t... Is>
pshape(std::tuple<Args...> const &v, utils::index_sequence<Is...>)
: values{check_type(std::get<Is>(values), std::get<Is>(v))...}
{
}
template <class... Args>
pshape(std::tuple<Args...> const &v)
: pshape(v, utils::make_index_sequence<sizeof...(Args)>())
{
}
template <class... Args>
pshape(long arg, Args... args)
: pshape(std::make_tuple(arg, args...),
utils::make_index_sequence<1 + sizeof...(args)>())
{
}
template <class T, T N, class... Args>
pshape(std::integral_constant<T, N> arg, Args... args)
: pshape(std::make_tuple(arg, args...),
utils::make_index_sequence<1 + sizeof...(args)>())
{
}
template <class S, size_t... Is>
pshape(S const *buffer, utils::index_sequence<Is...>)
: values{check_type(std::get<Is>(values), buffer[Is])...}
{
}
template <class S>
pshape(S const *buffer)
: pshape(buffer, utils::make_index_sequence<sizeof...(Tys)>())
{
}
template <class... TyOs>
pshape(pshape<TyOs...> other)
: pshape(other.values, utils::make_index_sequence<sizeof...(TyOs)>())
{
static_assert(sizeof...(TyOs) == sizeof...(Tys), "compatible sizes");
}
template <class S, class V>
pshape(pythonic::types::array_base<S, sizeof...(Tys), V> data)
: pshape(data.data())
{
}
pshape() = default;
pshape(pshape const &) = default;
pshape(pshape &&) = default;
pshape &operator=(pshape const &) = default;
pshape &operator=(pshape &&) = default;
template <size_t... Is>
types::array<long, sizeof...(Tys)> array(utils::index_sequence<Is...>) const
{
return {{get<Is>()...}};
}
types::array<long, sizeof...(Tys)> array() const
{
return array(utils::make_index_sequence<sizeof...(Tys)>());
}
operator types::array<long, sizeof...(Tys)>() const
{
return array();
}
template <size_t I>
long get() const
{
return std::get<I>(values);
}
template <size_t I>
auto get() -> decltype(std::get<I>(values))
{
return std::get<I>(values);
}
};
template <class P, size_t M, class... Ss>
struct shape_builder;
template <class P, size_t I, class V, size_t M, class... Ss>
struct shape_builder<array_base<P, I, V>, M, Ss...>
: shape_builder<P, M - 1, Ss..., std::integral_constant<long, I>> {
};
template <class P, class... Ss>
struct shape_builder<P, 0, Ss...> {
using type = pshape<Ss...>;
};
template <class P, size_t M, class... Ss>
struct shape_builder
: shape_builder<typename P::value_type, M - 1, Ss..., long> {
};
struct array_base_slicer {
template <class T, size_t N>
dynamic_tuple<T> operator()(array<T, N> const &b, slice const &s);
template <class T, size_t N>
dynamic_tuple<T> operator()(array<T, N> const &b,
contiguous_slice const &s);
template <class T, size_t N>
dynamic_tuple<T> operator()(array<T, N> const &b,
fast_contiguous_slice const &s);
template <class T, size_t N, class S>
typename std::enable_if<is_slice<S>::value, sliced_list<T, S>>::type
operator()(static_list<T, N> const &b, S const &s)
{
return {b, s};
}
};
namespace details
{
template <class E>
auto extract_shape(E const &e, utils::int_<0>) -> decltype(e.size())
{
return e.size();
}
template <class E, size_t L>
auto extract_shape(E const &e, utils::int_<L>)
-> decltype(extract_shape(e[0], utils::int_<L - 1>{}))
{
return extract_shape(e[0], utils::int_<L - 1>{});
}
}
/* inspired by std::array implementation */
template <typename T, size_t N, typename Version>
struct array_base {
using value_type = T;
using pointer = value_type *;
using const_pointer = const value_type *;
using reference = value_type &;
using const_reference = const value_type &;
using iterator = value_type *;
using const_iterator = const value_type *;
using size_type = std::size_t;
using difference_type = std::ptrdiff_t;
using reverse_iterator = std::reverse_iterator<iterator>;
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
// minimal ndarray interface
using dtype = typename utils::nested_container_value_type<array_base>::type;
static const size_t value =
utils::nested_container_depth<array_base>::value;
static const bool is_vectorizable = true;
static const bool is_strided = false;
// flat_size implementation
template <class E>
long _flat_size(E const &e, utils::int_<1>) const;
template <class E, size_t L>
long _flat_size(E const &e, utils::int_<L>) const;
long flat_size() const;
// Support for zero-sized arrays mandatory.
value_type buffer[N ? N : 1];
// No explicit construct/copy/destroy for aggregate type.
void fill(const value_type &__u);
long count(value_type const &u) const
{
return std::count(begin(), end(), u);
}
// Iterators.
iterator begin() noexcept;
const_iterator begin() const noexcept;
iterator end() noexcept;
const_iterator end() const noexcept;
reverse_iterator rbegin() noexcept;
const_reverse_iterator rbegin() const noexcept;
reverse_iterator rend() noexcept;
const_reverse_iterator rend() const noexcept;
const_iterator cbegin() const noexcept;
const_iterator cend() const noexcept;
const_reverse_iterator crbegin() const noexcept;
const_reverse_iterator crend() const noexcept;
// Capacity.
constexpr size_type size() const noexcept;
constexpr size_type max_size() const noexcept;
constexpr bool empty() const noexcept;
intptr_t id() const;
// Element access.
reference fast(long n);
const_reference fast(long n) const noexcept;
#ifdef USE_XSIMD
using simd_iterator = const_simd_nditerator<array_base>;
using simd_iterator_nobroadcast = simd_iterator;
template <class vectorizer>
simd_iterator vbegin(vectorizer) const;
template <class vectorizer>
simd_iterator vend(vectorizer) const;
#endif
template <class... Indices>
dtype load(long index0, long index1, Indices... indices) const
{
return fast(index0).load(index1, indices...);
}
dtype load(long index) const
{
return fast(index);
}
reference operator[](long __n);
const_reference operator[](long __n) const noexcept;
template <class S>
auto operator[](S s) const
-> decltype(array_base_slicer{}(*this, (s.lower, s)))
{
return array_base_slicer{}(*this, s);
}
reference front();
const_reference front() const;
reference back();
const_reference back() const;
pointer data() noexcept;
const_pointer data() const noexcept;
// operator
// for conversion to dict item type
template <class K, class V>
operator std::pair<const K, V>() const
{
static_assert(std::is_same<K, T>::value && std::is_same<V, T>::value &&
N == 2,
"compatible conversion");
return {data()[0], data()[1]};
}
template <size_t M>
bool operator==(array_base<T, M, Version> const &other) const;
template <size_t M>
bool operator!=(array_base<T, M, Version> const &other) const;
template <size_t M>
bool operator<(array_base<T, M, Version> const &other) const;
template <class Tp, size_t M>
array_base<typename __combined<T, Tp>::type, N + M, Version>
operator+(array_base<Tp, M, Version> const &other) const;
// tuple conversion
template <class... Types>
operator std::tuple<Types...>() const;
template <class Tp>
operator array_base<Tp, N, Version>() const;
auto to_tuple() const
-> decltype(array_to_tuple(*this, utils::make_index_sequence<N>{},
utils::make_repeated_type<T, N>()));
template <class W>
array_base<T, N, W> to_array() const;
template <class W>
explicit operator array_base<T, N, W>() const
{
return to_array<W>();
}
template <class S>
auto operator()(S const &s) const -> decltype((*this)[s])
{
return (*this)[s];
}
bool operator!() const
{
return N == 0;
}
/* array */
template <class T1, size_t N1, class Version1>
friend std::ostream &
operator<<(std::ostream &os, types::array_base<T1, N1, Version1> const &v);
using shape_t = typename shape_builder<array_base, value>::type;
template <size_t I>
auto shape() const
-> decltype(details::extract_shape(*this, utils::int_<I>{}))
{
return details::extract_shape(*this, utils::int_<I>{});
}
};
// Implementation for detection of "same type".
// With this information, we know if we must create a real tuple || a
// static sized array
namespace details
{
template <class... Types>
struct alike;
template <>
struct alike<> {
static bool const value = false;
using type = void;
};
template <class T>
struct alike<T> {
static bool const value = true;
using type = typename std::remove_cv<
typename std::remove_reference<T>::type>::type;
};
template <class A, class... S>
struct alike<numpy_gexpr<A, S...>, numpy_gexpr<A const &, S...>> {
static bool const value = true;
using type = numpy_gexpr<A, S...>;
};
template <class T0, class T1>
struct alike<T0, T1> {
static bool const value = std::is_same<T0, T1>::value;
using type = typename std::conditional<value, T0, void>::type;
};
// specialization to make static string alike types::str
template <size_t N>
struct alike<char[N], str> {
static bool const value = true;
using type = str;
};
template <size_t N>
struct alike<str, char[N]> {
static bool const value = true;
using type = str;
};
template <size_t N, size_t M>
struct alike<char[M], char[N]> {
static bool const value = true;
using type = str;
};
template <class T, size_t N, class V, class... Types>
struct alike<std::tuple<Types...>, array_base<T, N, V>> {
static bool const value =
sizeof...(Types) == N &&
alike<T, typename std::remove_cv<typename std::remove_reference<
Types>::type>::type...>::value;
using type = typename std::conditional<
value, typename alike<
T, typename std::remove_cv<typename std::remove_reference<
Types>::type>::type...>::type,
void>::type;
};
template <class T, size_t N, class V, class... Types>
struct alike<array_base<T, N, V>, std::tuple<Types...>>
: alike<std::tuple<Types...>, array_base<T, N, V>> {
};
template <class T, class... Types>
struct alike<T, Types...> {
static bool const value = alike<Types...>::value &&
alike<T, typename alike<Types...>::type>::value;
using type = typename alike<T, typename alike<Types...>::type>::type;
};
}
template <class... Types>
struct alike : details::alike<typename std::remove_cv<
typename std::remove_reference<Types>::type>::type...> {
};
// Pythonic implementation for make_tuple to have the best return type
// (static array for sames types || real tuple otherwise)
template <bool Same, class... Types>
struct _make_tuple {
auto operator()(Types &&... types)
-> decltype(std::make_tuple(std::forward<Types>(types)...))
{
return std::make_tuple(std::forward<Types>(types)...);
}
};
template <class... Types>
struct _make_tuple<true, Types...> {
types::array<typename alike<Types...>::type, sizeof...(Types)>
operator()(Types &&... types)
{
return {{std::forward<Types>(types)...}};
}
};
template <class... Types>
auto make_tuple(Types &&... types)
#if !_MSC_VER || __clang__
-> decltype(_make_tuple<alike<Types...>::value, Types...>()(
std::forward<Types>(types)...))
#endif
{
return _make_tuple<alike<Types...>::value, Types...>()(
std::forward<Types>(types)...);
}
template <class... Tys>
using make_tuple_t = decltype(types::make_tuple(std::declval<Tys>()...));
template <class T, class Tuple, size_t... S>
types::array<T, sizeof...(S)> _to_array(Tuple const &t,
utils::index_sequence<S...>)
{
return {{static_cast<T>(std::get<S>(t))...}};
}
template <class T, class... Tys>
types::array<T, sizeof...(Tys)> to_array(std::tuple<Tys...> const &t)
{
return _to_array<T>(t, utils::make_index_sequence<sizeof...(Tys)>());
}
// Tuple concatenation for array && tuple
template <class T, size_t N, class V, class... Types>
auto operator+(std::tuple<Types...> const &t,
types::array_base<T, N, V> const <)
-> decltype(std::tuple_cat(t, lt.to_tuple()));
template <class T, size_t N, class V, class... Types>
auto operator+(types::array_base<T, N, V> const <,
std::tuple<Types...> const &t)
-> decltype(std::tuple_cat(lt.to_tuple(), t));
}
template <class... Types>
struct assignable<std::tuple<Types...>> {
using type = std::tuple<typename assignable<Types>::type...>;
};
template <typename T, size_t N, class V>
struct assignable<pythonic::types::array_base<T, N, V>> {
using type = pythonic::types::array_base<typename assignable<T>::type, N, V>;
};
template <class... Types>
struct returnable<std::tuple<Types...>> {
using type = std::tuple<typename returnable<Types>::type...>;
};
template <typename T, size_t N, class V>
struct returnable<pythonic::types::array_base<T, N, V>> {
using type = pythonic::types::array_base<typename returnable<T>::type, N, V>;
};
PYTHONIC_NS_END
/* specialize std::get */
namespace std
{
template <size_t I, class T, size_t N, class V>
typename pythonic::types::array_base<T, N, V>::reference
get(pythonic::types::array_base<T, N, V> &t)
{
return t[I];
}
template <size_t I, class T, size_t N, class V>
typename pythonic::types::array_base<T, N, V>::const_reference
get(pythonic::types::array_base<T, N, V> const &t)
{
return t[I];
}
template <size_t I, class T, size_t N, class V>
struct tuple_element<I, pythonic::types::array_base<T, N, V>> {
using type = typename pythonic::types::array_base<T, N, V>::value_type;
};
template <typename T, size_t N, class V>
struct tuple_size<pythonic::types::array_base<T, N, V>> {
static const size_t value = N;
};
}
/* hashable tuples, as proposed in
* http://stackoverflow.com/questions/7110301/generic-hash-for-tuples-in-unordered-map-unordered-set
*/
namespace
{
inline size_t hash_combiner(size_t left, size_t right); // replacable
template <size_t index, class... types>
struct hash_impl {
size_t operator()(size_t a, const std::tuple<types...> &t) const;
};
template <class... types>
struct hash_impl<0, types...> {
size_t operator()(size_t a, const std::tuple<types...> &t) const;
};
}
/* specialize std::hash */
namespace std
{
template <class... Types>
struct hash<std::tuple<Types...>> {
size_t operator()(std::tuple<Types...> const &t) const;
};
template <typename T, size_t N, class V>
struct hash<pythonic::types::array_base<T, N, V>> {
size_t operator()(pythonic::types::array_base<T, N, V> const &l) const;
};
}
/* type inference stuff {*/
#include "pythonic/include/types/combined.hpp"
template <class K, class... Types>
struct __combined<indexable<K>, std::tuple<Types...>> {
using type = std::tuple<Types...>;
};
template <class K, class... Types>
struct __combined<std::tuple<Types...>, indexable<K>> {
using type = std::tuple<Types...>;
};
template <class T, size_t N>
struct __combined<pythonic::types::static_list<T, N>,
pythonic::types::static_list<T, N>> {
using type = pythonic::types::static_list<T, N>;
};
template <class T, size_t N>
struct __combined<pythonic::types::array<T, N>, pythonic::types::array<T, N>> {
using type = pythonic::types::array<T, N>;
};
template <class T0, class T1, size_t N, class V>
struct __combined<pythonic::types::array_base<T0, N, V>,
pythonic::types::array_base<T1, N, V>> {
using type =
pythonic::types::array_base<typename __combined<T0, T1>::type, N, V>;
};
template <class T0, class T1, size_t N>
struct __combined<pythonic::types::static_list<T0, N>,
pythonic::types::static_list<T1, N>> {
using type =
pythonic::types::static_list<typename __combined<T0, T1>::type, N>;
};
template <class T0, class T1, size_t N0, size_t N1>
struct __combined<pythonic::types::static_list<T0, N0>,
pythonic::types::static_list<T1, N1>> {
using type = pythonic::types::list<typename __combined<T0, T1>::type>;
};
template <class K, class T, size_t N, class V>
struct __combined<indexable<K>, pythonic::types::array_base<T, N, V>> {
using type = pythonic::types::array_base<T, N, V>;
};
template <class K, class T, size_t N, class V>
struct __combined<pythonic::types::array_base<T, N, V>, indexable<K>> {
using type = pythonic::types::array_base<T, N, V>;
};
template <class K, class T, size_t N, class V>
struct __combined<container<K>, pythonic::types::array_base<T, N, V>> {
using type =
pythonic::types::array_base<typename __combined<T, K>::type, N, V>;
};
template <class K, class T, size_t N, class V>
struct __combined<pythonic::types::array_base<T, N, V>, container<K>> {
using type =
pythonic::types::array_base<typename __combined<T, K>::type, N, V>;
};
template <class K, class V, class T, size_t N, class AV>
struct __combined<indexable_container<K, V>,
pythonic::types::array_base<T, N, AV>> {
using type =
pythonic::types::array_base<typename __combined<V, T>::type, N, AV>;
};
template <class K, class V, class T, size_t N, class AV>
struct __combined<pythonic::types::array_base<T, N, AV>,
indexable_container<K, V>> {
using type =
pythonic::types::array_base<typename __combined<T, V>::type, N, AV>;
};
template <class... t0, class... t1>
struct __combined<std::tuple<t0...>, std::tuple<t1...>> {
using type = std::tuple<typename __combined<t0, t1>::type...>;
};
template <class t, class... t0>
struct __combined<std::tuple<t0...>, container<t>> {
using type = std::tuple<t0...>;
};
template <class t, class... t0>
struct __combined<container<t>, std::tuple<t0...>> {
using type = std::tuple<t0...>;
};
PYTHONIC_NS_BEGIN
namespace details
{
template <class T, class P, bool Same>
struct pick_combined;
template <class T, class P>
struct pick_combined<T, P, true> {
using type = typename __combined<T, P>::type;
};
template <class T, class P>
struct pick_combined<T, P, false> {
using type = P;
};
}
PYTHONIC_NS_END
template <long I, class t, class... t0>
struct __combined<std::tuple<t0...>,
indexable_container<std::integral_constant<long, I>, t>> {
using holder = std::tuple<t0...>;
template <size_t... Is>
static std::tuple<typename pythonic::details::pick_combined<
t, typename std::tuple_element<Is, holder>::type, I == Is>::type...>
make_type(pythonic::utils::index_sequence<Is...>);
static auto make_type() -> decltype(
make_type(pythonic::utils::make_index_sequence<sizeof...(t0)>()));
using type = decltype(make_type());
};
template <class k, class t, class... t0>
struct __combined<indexable_container<k, t>, std::tuple<t0...>>
: __combined<std::tuple<t0...>, indexable_container<k, t>> {
};
template <class t, size_t n, class... types>
struct __combined<pythonic::types::array<t, n>, std::tuple<types...>> {
using type = std::tuple<typename __combined<t, types>::type...>;
};
template <class t, size_t n, class... types>
struct __combined<pythonic::types::array<t, n>,
pythonic::types::pshape<types...>> {
using type = pythonic::types::array<t, n>;
};
template <class t, size_t n, class... types>
struct __combined<pythonic::types::pshape<types...>,
pythonic::types::array<t, n>> {
using type = pythonic::types::array<t, n>;
};
template <class t, size_t n, class... types>
struct __combined<std::tuple<types...>, pythonic::types::array<t, n>> {
using type = std::tuple<typename __combined<types, t>::type...>;
};
template <class t00, class t01, class t10, class t11>
struct __combined<std::pair<t00, t01>, std::pair<t10, t11>> {
using type =
std::pair<typename __combined<t00, t10>::type,
typename __combined<t01, t11>::type>; // no further combination
};
/* } */
PYTHONIC_NS_BEGIN
namespace types
{
template <class Tuple, size_t I>
void print_tuple(std::ostream &os, Tuple const &t, utils::int_<I>);
template <class Tuple>
void print_tuple(std::ostream &os, Tuple const &t, utils::int_<0>);
template <typename T, size_t N, class V>
struct len_of<array_base<T, N, V>> {
static constexpr long value = N;
};
template <typename T, long I, class... Is>
struct len_of<ndarray<T, pshape<std::integral_constant<long, I>, Is...>>> {
static constexpr long value = I;
};
template <class... Types>
struct len_of<std::tuple<Types...>> {
static constexpr long value = sizeof...(Types);
};
}
PYTHONIC_NS_END
namespace std
{
template <class... Args>
ostream &operator<<(ostream &os, tuple<Args...> const &t);
template <size_t I, class... Tys>
long get(pythonic::types::pshape<Tys...> const &s)
{
return s.template get<I>();
}
template <size_t I, class... Tys>
auto get(pythonic::types::pshape<Tys...> &s) -> decltype(s.template get<I>())
{
return s.template get<I>();
}
template <size_t I, class T>
auto get(T *s) -> decltype(s[I])
{
return s[I];
}
template <size_t I, class T>
long get(T const *s)
{
return s[I];
}
template <class... Tys>
struct tuple_size<pythonic::types::pshape<Tys...>>
: public std::integral_constant<std::size_t, sizeof...(Tys)> {
};
template <size_t I, class... Tys>
struct tuple_element<I, pythonic::types::pshape<Tys...>> {
using type = typename std::tuple_element < I < sizeof...(Tys) ? I : 0,
std::tuple<Tys...>> ::type;
};
}
PYTHONIC_NS_BEGIN
namespace sutils
{
template <class T>
struct make_shape {
using type = T;
};
template <typename T, size_t N, class V>
struct make_shape<types::array_base<T, N, V>> {
using type = types::array<long, N>;
};
template <class T>
using shape_t = typename std::enable_if<!std::is_integral<T>::value,
typename make_shape<T>::type>::type;
template <class Curr, class... Ss>
struct shape_merger;
template <class Curr>
struct shape_merger<Curr> {
using type = Curr;
};
template <class Curr, class... Ss>
struct shape_merger<Curr, long, Ss...> {
using type = long;
};
template <long N0, long N1, class... Ss>
struct shape_merger<std::integral_constant<long, N0>,
std::integral_constant<long, N1>, Ss...>
: shape_merger<std::integral_constant<long, (N0 > N1 ? N0 : N1)>, Ss...> {
};
template <long N, class... Ss>
struct shape_merger<long, std::integral_constant<long, N>, Ss...> {
using type = long;
};
template <size_t I, class Ss>
struct shape_selecter
: std::conditional<
(I < std::tuple_size<Ss>::value),
typename std::tuple_element<
(I < std::tuple_size<Ss>::value ? I : 0L), Ss>::type,
std::integral_constant<long, 1>> {
};
template <size_t I, class Ss>
struct merge_shape;
template <size_t I, class... Ss>
struct merge_shape<I, std::tuple<Ss...>> {
using type =
typename shape_merger<typename shape_selecter<I, Ss>::type...>::type;
};
template <class Ss, class T>
struct merged_shapes;
template <class Ss, size_t... Is>
struct merged_shapes<Ss, utils::index_sequence<Is...>> {
using type = types::pshape<typename merge_shape<Is, Ss>::type...>;
};
template <size_t N, class... Ss>
using merged_shapes_t =
typename merged_shapes<std::tuple<Ss...>,
utils::make_index_sequence<N>>::type;
template <class... Ss>
struct shape_commonifier;
template <class Ss>
struct shape_commonifier<Ss> {
using type = Ss;
};
template <class S1, class... Ss>
struct shape_commonifier<long, S1, Ss...> {
using type = long;
};
template <long N, class... Ss>
struct shape_commonifier<std::integral_constant<long, N>, long, Ss...> {
using type = long;
};
template <long N0, long N1, class... Ss>
struct shape_commonifier<std::integral_constant<long, N0>,
std::integral_constant<long, N1>, Ss...> {
using type = typename std::conditional<
N0 == N1, typename shape_commonifier<std::integral_constant<long, N0>,
Ss...>::type,
long>::type;
};
template <size_t I, class Ss>
struct common_shape;
template <size_t I, class... Ss>
struct common_shape<I, std::tuple<Ss...>> {
using type = typename shape_commonifier<
typename std::tuple_element<I, Ss>::type...>::type;
};
template <class Ss, class T>
struct common_shapes;
template <class Ss, size_t... Is>
struct common_shapes<Ss, utils::index_sequence<Is...>> {
using type = types::pshape<typename common_shape<Is, Ss>::type...>;
};
template <size_t N, class... Ss>
using common_shapes_t =
typename common_shapes<std::tuple<Ss...>,
utils::make_index_sequence<N>>::type;
template <class T>
struct transpose;
template <class T>
struct transpose<types::array<T, 2>> {
using type = types::array<T, 2>;
};
template <class T0, class T1>
struct transpose<types::pshape<T0, T1>> {
using type = types::pshape<T1, T0>;
};
template <class T>
using transpose_t = typename transpose<T>::type;
template <class T0, class T1>
void assign(T0 &t0, T1 t1)
{
t0 = (T0)t1;
}
template <class T0, T0 N, class T1>
void assign(std::integral_constant<T0, N> &t0, T1 t1)
{
assert((long)t0 == (long)t1 && "consistent");
}
template <size_t Start, ssize_t Offset, class T0, class T1, size_t... Is>
void copy_shape(T0 &shape0, T1 const &shape1, utils::index_sequence<Is...>)
{
(void)std::initializer_list<int>{
(assign(std::get<Start + Is>(shape0),
shape1.template shape<Is + Start + Offset>()),
1)...};
}
template <size_t Start, ssize_t Offset, class T0, class T1, size_t... Is>
void scopy_shape(T0 &shape0, T1 const &shape1, utils::index_sequence<Is...>)
{
(void)std::initializer_list<int>{
(assign(std::get<Start + Is>(shape0),
std::get<Is + Start + Offset>(shape1)),
1)...};
}
template <size_t Start, ssize_t Offset, class T0, class T1, size_t... Is>
void copy_strides(T0 &stride0, T1 const &stride1,
utils::index_sequence<Is...>)
{
(void)std::initializer_list<int>{
(assign(std::get<Start + Is>(stride0),
stride1.template strides<Is + Start + Offset>()),
1)...};
}
template <class P, class... Tys>
struct pop_type;
template <class... Ps, class Ty>
struct pop_type<types::pshape<Ps...>, Ty> {
using type = types::pshape<Ps...>;
};
template <class... Ps, class Ty, class... Tys>
struct pop_type<types::pshape<Ps...>, Ty, Tys...>
: pop_type<types::pshape<Ps..., Ty>, Tys...> {
};
template <class T>
struct pop_tail;
template <class... Tys>
struct pop_tail<types::pshape<Tys...>> {
using type = typename pop_type<types::pshape<>, Tys...>::type;
};
template <typename T, size_t N, class V>
struct pop_tail<types::array_base<T, N, V>> {
using type = types::array<T, N - 1>;
};
template <class T>
struct pop_head;
template <class Ty, class... Tys>
struct pop_head<types::pshape<Ty, Tys...>> {
using type = types::pshape<Tys...>;
};
template <typename T, size_t N, class V>
struct pop_head<types::array_base<T, N, V>> {
using type = types::array<T, N - 1>;
};
template <class T>
struct head;
template <class Ty, class... Tys>
struct head<types::pshape<Ty, Tys...>> {
using type = Ty;
};
template <typename T, size_t N, class V>
struct head<types::array_base<T, N, V>> {
using type = T;
};
template <class T>
using pop_head_t = typename pop_head<T>::type;
template <class T>
using pop_tail_t = typename pop_tail<T>::type;
template <class T>
using head_t = typename head<T>::type;
template <class... Tys>
types::array<long, sizeof...(Tys)> array(types::pshape<Tys...> const &pS)
{
return pS.array();
}
template <typename T, size_t N, class V>
types::array_base<T, N, V> array(types::array_base<T, N, V> const &pS)
{
return pS;
}
template <class E, size_t... Is>
types::array<long, sizeof...(Is)> getshape(E const &e,
utils::index_sequence<Is...>)
{
return {(long)(e.template shape<Is>())...};
}
template <class E>
auto getshape(E const &e)
-> decltype(getshape(e, utils::make_index_sequence<E::value>()))
{
return getshape(e, utils::make_index_sequence<E::value>());
}
template <class pS0, class pS1>
struct concat;
template <class... Ty0s, class... Ty1s>
struct concat<types::pshape<Ty0s...>, types::pshape<Ty1s...>> {
using type = types::pshape<Ty0s..., Ty1s...>;
};
template <class... Tys>
struct concat<types::pshape<Tys...>, types::array<long, 0>> {
using type = types::pshape<Tys...>;
};
template <class... Tys, size_t N>
struct concat<types::pshape<Tys...>, types::array<long, N>>
: concat<types::pshape<Tys..., long>, types::array<long, N - 1>> {
};
template <class... Ty1s>
struct concat<types::array<long, 0>, types::pshape<Ty1s...>> {
using type = types::pshape<Ty1s...>;
};
template <size_t N, class... Ty1s>
struct concat<types::array<long, N>, types::pshape<Ty1s...>>
: concat<types::array<long, N - 1>, types::pshape<long, Ty1s...>> {
};
template <class... Tys>
using concat_t = typename concat<Tys...>::type;
template <class P, class T>
using push_front_t = concat_t<types::pshape<T>, P>;
template <class S>
long find(S &s, long v, std::integral_constant<size_t, 0>, long start,
bool comp(long, long))
{
return comp(s.template shape<0>(), v) && 0 < start ? 0 : -1;
}
template <class S, size_t I>
long find(S &s, long v, std::integral_constant<size_t, I>, long start,
bool comp(long, long))
{
return comp(s.template shape<I>(), v) && I < start
? I
: find(s, v, std::integral_constant<size_t, I - 1>(), start,
comp);
}
template <class S>
long find(S &s, long v, long start = S::value,
bool comp(long, long) = [](long a, long b) { return (a == b); })
{
return find(s, v, std::integral_constant<size_t, S::value - 1>(), start,
comp);
}
template <class S>
long sfind(S &s, long v, std::integral_constant<size_t, 0>, long start,
bool comp(long, long))
{
return comp(std::get<0>(s), v) && 0 < start ? 0 : -1;
}
template <class S, size_t I>
long sfind(S &s, long v, std::integral_constant<size_t, I>, long start,
bool comp(long, long))
{
return comp(std::get<I>(s), v) && (long)I < start
? (long)I
: sfind(s, v, std::integral_constant<size_t, I - 1>(), start,
comp);
}
template <class S>
long sfind(S &s, long v, long start = std::tuple_size<S>::value,
bool comp(long, long) = [](long a, long b) { return (a == b); })
{
return sfind(
s, v, std::integral_constant<size_t, std::tuple_size<S>::value - 1>(),
start, comp);
}
template <class S, class B>
bool equals(S const &s, B const &other, std::integral_constant<size_t, 0>)
{
return std::get<0>(other) == s.template shape<0>();
}
template <class S, class B, size_t I>
bool equals(S const &s, B const &other, std::integral_constant<size_t, I>)
{
return std::get<I>(other) == s.template shape<I>() &&
equals(s, other, std::integral_constant<size_t, I - 1>());
}
template <class S, class B>
typename std::enable_if<S::value == std::tuple_size<B>::value, bool>::type
equals(S const &s, B const &other)
{
return equals(s, other, std::integral_constant<size_t, S::value - 1>());
}
template <class S, class B>
typename std::enable_if<
std::tuple_size<S>::value != std::tuple_size<B>::value, bool>::type
equals(S const &s, B const &other)
{
return false;
}
template <class S, class B>
bool equals(S const &s, B *other)
{
return equals(s, other, std::integral_constant<size_t, S::value - 1>());
}
template <class S, class B>
bool requals(S const &s, B const *other, std::integral_constant<size_t, 0>)
{
return other[S::value - 1] == s.template shape<0>();
}
template <class S, class B, size_t I>
bool requals(S const &s, B const *other, std::integral_constant<size_t, I>)
{
return other[S::value - I - 1] == s.template shape<I>() &&
requals(s, other, std::integral_constant<size_t, I - 1>());
}
template <class S, class B>
bool requals(S const &s, B const *other)
{
return requals(s, other, std::integral_constant<size_t, S::value - 1>());
}
template <class S, class P>
bool any_of(S const &s, P pred, std::integral_constant<size_t, 0>)
{
return pred(s.template shape<0>());
}
template <class S, class P, size_t I>
bool any_of(S const &s, P pred, std::integral_constant<size_t, I>)
{
return pred(s.template shape<I>()) ||
any_of(s, pred, std::integral_constant<size_t, I - 1>());
}
template <class S, class Pred>
bool any_of(S const &s, Pred pred)
{
return any_of(s, pred, std::integral_constant<size_t, S::value - 1>());
}
template <class S>
long min(long curr, S const &s, std::integral_constant<size_t, 0>)
{
return std::min(curr, s.template shape<0>());
}
template <class S, size_t I>
long min(long curr, S const &s, std::integral_constant<size_t, I>)
{
return min(std::min(curr, s.template shape<I>()), s,
std::integral_constant<size_t, I - 1>());
}
template <class S>
long min(S const &s)
{
return min(s.template shape<S::value - 1>(), s,
std::integral_constant<size_t, S::value - 1>());
}
template <class S>
long prod(S const &s, std::integral_constant<size_t, 0>)
{
return s.template shape<0>();
}
template <class S, size_t I>
long prod(S const &s, std::integral_constant<size_t, I>)
{
return s.template shape<I>() *
prod(s, std::integral_constant<size_t, I - 1>());
}
template <class S>
long prod(S const &s)
{
return prod(s, std::integral_constant<size_t, S::value - 1>());
}
template <class S>
long sprod(S const &s, std::integral_constant<size_t, 0>)
{
return std::get<0>(s);
}
template <class S, size_t I>
long sprod(S const &s, std::integral_constant<size_t, I>)
{
return std::get<I>(s) * sprod(s, std::integral_constant<size_t, I - 1>());
}
template <class S>
long sprod(S const &s)
{
return sprod(
s, std::integral_constant<size_t, std::tuple_size<S>::value - 1>());
}
template <class S>
long prod_tail(S, std::integral_constant<size_t, 0>)
{
return 1;
}
template <class S, size_t I>
long prod_tail(S const &s, std::integral_constant<size_t, I>)
{
return s.template shape<I>() *
prod_tail(s, std::integral_constant<size_t, I - 1>());
}
template <class S>
long prod_tail(S const &s)
{
return prod_tail(s, std::integral_constant<size_t, S::value - 1>());
}
template <class S>
long prod_head(S, std::integral_constant<size_t, 0>)
{
return 1;
}
template <class S, size_t I>
long prod_head(S const &s, std::integral_constant<size_t, I>)
{
return s.template shape<S::value - 1 - I>() *
prod_head(s, std::integral_constant<size_t, I - 1>());
}
template <class S>
long prod_head(S const &s)
{
return prod_head(s, std::integral_constant<size_t, S::value - 1>());
}
template <size_t I, class P>
struct safe_tuple_element {
using type =
typename std::tuple_element<(I < std::tuple_size<P>::value ? I : 0),
P>::type;
};
template <size_t I>
struct copy_new_axis_helper;
template <>
struct copy_new_axis_helper<0> {
template <class S0, class S1, class S2, size_t J>
typename std::enable_if<
(0 != std::tuple_size<S2>::value) &&
std::tuple_element<0, S2>::type::value,
sutils::push_front_t<S0, std::integral_constant<long, 1>>>::type
doit(S0 s, S1 const &shape, S2 const &new_axis,
std::integral_constant<size_t, J>)
{
return {std::tuple_cat(std::tuple<std::integral_constant<long, 1>>(),
s.values)};
}
template <class S0, class S1, class S2, size_t J>
typename std::enable_if<
(0 != std::tuple_size<S2>::value) &&
!std::tuple_element<0, S2>::type::value,
sutils::push_front_t<S0, typename std::tuple_element<
0, typename S1::shape_t>::type>>::type
doit(S0 s, S1 const &shape, S2 const &new_axis,
std::integral_constant<size_t, J>)
{
return {
std::tuple_cat(std::make_tuple(shape.template shape<0>()), s.values)};
}
template <class S0, class S1, class S2, size_t J>
typename std::enable_if<
(0 == std::tuple_size<S2>::value),
sutils::push_front_t<S0, typename std::tuple_element<
J, typename S1::shape_t>::type>>::type
doit(S0 s, S1 const &shape, S2 const &new_axis,
std::integral_constant<size_t, J>)
{
return {
std::tuple_cat(std::make_tuple(shape.template shape<J>()), s.values)};
}
};
template <size_t I>
struct copy_new_axis_helper {
template <class S0, class S1, class S2, size_t J>
auto doit(S0 s, S1 const &shape, S2 const &new_axis,
std::integral_constant<size_t, J>) ->
typename std::enable_if<
(I < std::tuple_size<S2>::value) &&
safe_tuple_element<I, S2>::type::value,
decltype(copy_new_axis_helper<I - 1>{}.doit(
sutils::push_front_t<S0, std::integral_constant<long, 1>>(),
shape, new_axis, std::integral_constant<size_t, J>()))>::type
{
return copy_new_axis_helper<I - 1>{}.doit(
sutils::push_front_t<S0, std::integral_constant<long, 1>>(
std::tuple_cat(std::tuple<std::integral_constant<long, 1>>(),
s.values)),
shape, new_axis, std::integral_constant<size_t, J>());
}
template <class S0, class S1, class S2, size_t J>
auto doit(S0 s, S1 const &shape, S2 const &new_axis,
std::integral_constant<size_t, J>) ->
typename std::enable_if<
(I >= std::tuple_size<S2>::value),
decltype(copy_new_axis_helper<I - 1>{}.doit(
sutils::push_front_t<S0, typename std::tuple_element<
J, typename S1::shape_t>::type>(),
shape, new_axis, std::integral_constant < size_t,
J == 0 ? J : J - 1 > ()))>::type
{
return copy_new_axis_helper<I - 1>{}.doit(
sutils::push_front_t<
S0, typename std::tuple_element<J, typename S1::shape_t>::type>(
std::tuple_cat(std::make_tuple(shape.template shape<J>()),
s.values)),
shape, new_axis, std::integral_constant < size_t,
J == 0 ? J : J - 1 > ());
}
template <class S0, class S1, class S2, size_t J>
auto doit(S0 s, S1 const &shape, S2 const &new_axis,
std::integral_constant<size_t, J>) ->
typename std::enable_if<
(I < std::tuple_size<S2>::value) &&
!safe_tuple_element<I, S2>::type::value,
decltype(copy_new_axis_helper<I - 1>{}.doit(
sutils::push_front_t<S0, typename std::tuple_element<
J, typename S1::shape_t>::type>(),
shape, new_axis, std::integral_constant < size_t,
J == 0 ? J : J - 1 > ()))>::type
{
return copy_new_axis_helper<I - 1>{}.doit(
sutils::push_front_t<
S0, typename std::tuple_element<J, typename S1::shape_t>::type>(
std::tuple_cat(std::make_tuple(shape.template shape<J>()),
s.values)),
shape, new_axis, std::integral_constant < size_t,
J == 0 ? J : J - 1 > ());
}
};
template <size_t N, class S1, class S2>
auto copy_new_axis(S1 const &shape, S2 const &new_axis)
-> decltype(copy_new_axis_helper<N - 1>{}.doit(
types::pshape<>(), shape, new_axis,
std::integral_constant<size_t, S1::value - 1>()))
{
return copy_new_axis_helper<N - 1>{}.doit(
types::pshape<>(), shape, new_axis,
std::integral_constant<size_t, S1::value - 1>());
}
}
namespace types
{
namespace details
{
template <class E, class S>
void init_shape(S &res, E const &e, utils::int_<1>)
{
sutils::assign(std::get<std::tuple_size<S>::value - 1>(res), e.size());
}
template <class E, class S, size_t L>
void init_shape(S &res, E const &e, utils::int_<L>)
{
sutils::assign(std::get<std::tuple_size<S>::value - L>(res), e.size());
init_shape(res, e[0], utils::int_<L - 1>{});
}
}
template <class T, class... Tys>
bool operator==(T const &self, pshape<Tys...> const &other)
{
return sutils::equals(self, other);
}
template <class T, class... Tys>
bool operator==(pshape<Tys...> const &self, T const &other)
{
return sutils::equals(self, other);
}
template <class... Ty0s, class... Ty1s>
bool operator==(pshape<Ty0s...> const &self, pshape<Ty1s...> const &other)
{
return sutils::equals(self, other);
}
template <class T, class... Tys>
bool operator!=(T const &self, pshape<Tys...> const &other)
{
return !sutils::equals(self, other);
}
template <class T, class... Tys>
bool operator!=(pshape<Tys...> const &self, T const &other)
{
return !sutils::equals(self, other);
}
template <class... Ty0s, class... Ty1s>
bool operator!=(pshape<Ty0s...> const &self, pshape<Ty1s...> const &other)
{
return !sutils::equals(self, other);
}
}
PYTHONIC_NS_END
#ifdef ENABLE_PYTHON_MODULE
#include "pythonic/include/utils/seq.hpp"
#include "pythonic/include/utils/fwd.hpp"
#include "pythonic/python/core.hpp"
PYTHONIC_NS_BEGIN
template <typename K, typename V>
struct to_python<std::pair<K, V>> {
static PyObject *convert(std::pair<K, V> const &t);
};
template <typename... Tys>
struct to_python<types::pshape<Tys...>> {
static PyObject *convert(types::pshape<Tys...> const &t);
};
template <typename... Types>
struct to_python<std::tuple<Types...>> {
template <size_t... S>
static PyObject *do_convert(std::tuple<Types...> const &t,
utils::index_sequence<S...>);
static PyObject *convert(std::tuple<Types...> const &t);
};
template <typename T, size_t N>
struct to_python<types::array<T, N>> {
template <size_t... S>
static PyObject *do_convert(types::array<T, N> const &t,
utils::index_sequence<S...>);
static PyObject *convert(types::array<T, N> const &t);
};
template <typename T, size_t N>
struct to_python<types::static_list<T, N>> {
template <size_t... S>
static PyObject *do_convert(types::static_list<T, N> const &t,
utils::index_sequence<S...>);
static PyObject *convert(types::static_list<T, N> const &t);
};
template <typename... Types>
struct from_python<std::tuple<Types...>> {
template <size_t... S>
static bool do_is_convertible(PyObject *obj,
typename utils::index_sequence<S...>);
static bool is_convertible(PyObject *obj);
template <size_t... S>
static std::tuple<Types...> do_convert(PyObject *obj,
typename utils::index_sequence<S...>);
static std::tuple<Types...> convert(PyObject *obj);
};
template <typename T, size_t N>
struct from_python<types::array<T, N>> {
static bool is_convertible(PyObject *obj);
template <size_t... S>
static types::array<T, N> do_convert(PyObject *obj,
typename utils::index_sequence<S...>);
static types::array<T, N> convert(PyObject *obj);
};
PYTHONIC_NS_END
#endif
#endif