← Back
Editing: tuple.hpp
#ifndef PYTHONIC_TYPES_TUPLE_HPP #define PYTHONIC_TYPES_TUPLE_HPP #include "pythonic/include/types/tuple.hpp" #include "pythonic/types/assignable.hpp" #include "pythonic/types/traits.hpp" #include "pythonic/types/nditerator.hpp" #include "pythonic/types/dynamic_tuple.hpp" #include "pythonic/utils/int_.hpp" #include "pythonic/utils/seq.hpp" #include "pythonic/utils/nested_container.hpp" #include "pythonic/types/ndarray.hpp" #include <tuple> #include <algorithm> namespace std { template <class F0, class S0, class F1, class S1> bool operator==(pair<F0, S0> const &self, tuple<F1, S1> const &other) { return self.first == get<0>(other) && self.second == get<1>(other); } template <class F0, class S0, class F1, class S1> bool operator==(pair<const F0, S0> const &self, tuple<F1, S1> const &other) { return self.first == get<0>(other) && self.second == get<1>(other); } } template <class... Types0, class... Types1> std::tuple<Types0..., Types1...> operator+(std::tuple<Types0...> const &t0, std::tuple<Types1...> const &t1) { return std::tuple_cat(t0, t1); } template <class... Types0, class... Types1> std::tuple<Types0..., Types1...> operator+(std::tuple<Types0...> &&t0, std::tuple<Types1...> const &t1) { return std::tuple_cat(std::forward<Types0...>(t0), t1); } template <class... Types0, class... Types1> std::tuple<Types0..., Types1...> operator+(std::tuple<Types0...> const &t0, std::tuple<Types1...> &&t1) { return std::tuple_cat(t0, std::forward<Types1...>(t1)); } template <class... Types0, class... Types1> std::tuple<Types0..., Types1...> operator+(std::tuple<Types0...> &&t0, std::tuple<Types1...> &&t1) { return std::tuple_cat(std::forward<Types0...>(t0), std::forward<Types1...>(t1)); } PYTHONIC_NS_BEGIN namespace types { /* helper to extract the tail of a tuple, && pop the head */ template <class S, class... Stail> std::tuple<Stail...> tuple_tail(std::tuple<S, Stail...> const &t) { return make_tuple_tail<0>(t, utils::make_index_sequence<sizeof...(Stail)>{}); } template <class T, size_t N, class V, class A, size_t... I> array_base<T, N, V> array_to_array(A const &a, utils::index_sequence<I...>) { return {(T)std::get<I>(a)...}; } /* inspired by std::array implementation */ template <typename T, size_t N, class V> template <class E> long array_base<T, N, V>::_flat_size(E const &e, utils::int_<1>) const { return N; } template <typename T, size_t N, class V> template <class E, size_t L> long array_base<T, N, V>::_flat_size(E const &e, utils::int_<L>) const { return N * _flat_size(e[0], utils::int_<L - 1>{}); } template <typename T, size_t N, class V> long array_base<T, N, V>::flat_size() const { return _flat_size(*this, utils::int_<value>{}); } template <typename T, size_t N, class V> intptr_t array_base<T, N, V>::id() const { return reinterpret_cast<intptr_t>(&(buffer[0])); } template <typename T, size_t N, class V> void array_base<T, N, V>::fill(const value_type &__u) { std::fill_n(begin(), size(), __u); } // Iterators. template <typename T, size_t N, class V> typename array_base<T, N, V>::iterator array_base<T, N, V>::begin() noexcept { return {data()}; } template <typename T, size_t N, class V> typename array_base<T, N, V>::const_iterator array_base<T, N, V>::begin() const noexcept { return {data()}; } template <typename T, size_t N, class V> typename array_base<T, N, V>::iterator array_base<T, N, V>::end() noexcept { return {data() + N}; } template <typename T, size_t N, class V> typename array_base<T, N, V>::const_iterator array_base<T, N, V>::end() const noexcept { return {data() + N}; } template <typename T, size_t N, class V> typename array_base<T, N, V>::reverse_iterator array_base<T, N, V>::rbegin() noexcept { return reverse_iterator(end()); } template <typename T, size_t N, class V> typename array_base<T, N, V>::const_reverse_iterator array_base<T, N, V>::rbegin() const noexcept { return const_reverse_iterator(end()); } template <typename T, size_t N, class V> typename array_base<T, N, V>::reverse_iterator array_base<T, N, V>::rend() noexcept { return reverse_iterator(begin()); } template <typename T, size_t N, class V> typename array_base<T, N, V>::const_reverse_iterator array_base<T, N, V>::rend() const noexcept { return const_reverse_iterator(begin()); } template <typename T, size_t N, class V> typename array_base<T, N, V>::const_iterator array_base<T, N, V>::cbegin() const noexcept { return {&(buffer[0])}; } template <typename T, size_t N, class V> typename array_base<T, N, V>::const_iterator array_base<T, N, V>::cend() const noexcept { return {&(buffer[N])}; } template <typename T, size_t N, class V> typename array_base<T, N, V>::const_reverse_iterator array_base<T, N, V>::crbegin() const noexcept { return const_reverse_iterator(end()); } template <typename T, size_t N, class V> typename array_base<T, N, V>::const_reverse_iterator array_base<T, N, V>::crend() const noexcept { return const_reverse_iterator(begin()); } // Capacity. template <typename T, size_t N, class V> constexpr typename array_base<T, N, V>::size_type array_base<T, N, V>::size() const noexcept { return N; } template <typename T, size_t N, class V> constexpr typename array_base<T, N, V>::size_type array_base<T, N, V>::max_size() const noexcept { return N; } template <typename T, size_t N, class V> constexpr bool array_base<T, N, V>::empty() const noexcept { return size() == 0; } // Element access. template <typename T, size_t N, class V> typename array_base<T, N, V>::reference array_base<T, N, V>::fast(long n) { assert(n < (long)size()); return buffer[n]; } template <typename T, size_t N, class V> typename array_base<T, N, V>::const_reference array_base<T, N, V>::fast(long n) const noexcept { assert(n < (long)size()); return buffer[n]; } #ifdef USE_XSIMD template <typename T, size_t N, class V> template <class vectorizer> typename array_base<T, N, V>::simd_iterator array_base<T, N, V>::vbegin(vectorizer) const { return {&buffer[0]}; } template <typename T, size_t N, class V> template <class vectorizer> typename array_base<T, N, V>::simd_iterator array_base<T, N, V>::vend(vectorizer) const { using vector_type = typename xsimd::batch<dtype>; static const std::size_t vector_size = vector_type::size; return {&buffer[long(size() / vector_size * vector_size)]}; } #endif template <typename T, size_t N, class V> typename array_base<T, N, V>::reference array_base<T, N, V>:: operator[](long __n) { auto const index = __n < 0 ? (__n + size()) : __n; assert(0 <= index && index < size()); return buffer[index]; } template <typename T, size_t N, class V> typename array_base<T, N, V>::const_reference array_base<T, N, V>:: operator[](long __n) const noexcept { auto const index = __n < 0 ? (__n + size()) : __n; assert(0 <= index && index < size()); return buffer[index]; } template <typename T, size_t N, class V> typename array_base<T, N, V>::reference array_base<T, N, V>::front() { return *begin(); } template <typename T, size_t N, class V> typename array_base<T, N, V>::const_reference array_base<T, N, V>::front() const { return *begin(); } template <typename T, size_t N, class V> typename array_base<T, N, V>::reference array_base<T, N, V>::back() { return N ? *(end() - 1) : *end(); } template <typename T, size_t N, class V> typename array_base<T, N, V>::const_reference array_base<T, N, V>::back() const { return N ? *(end() - 1) : *end(); } template <typename T, size_t N, class V> typename array_base<T, N, V>::pointer array_base<T, N, V>::data() noexcept { return &(buffer[0]); } template <typename T, size_t N, class V> typename array_base<T, N, V>::const_pointer array_base<T, N, V>::data() const noexcept { return &(buffer[0]); } template <typename T, size_t N, class V> template <size_t M> bool array_base<T, N, V>::operator==(array_base<T, M, V> const &other) const { return N == M && std::equal(begin(), end(), other.begin()); } template <typename T, size_t N, class V> template <size_t M> bool array_base<T, N, V>::operator!=(array_base<T, M, V> const &other) const { return !(*this == other); } template <typename T, size_t N, class V> template <size_t M> bool array_base<T, N, V>::operator<(array_base<T, M, V> const &other) const { return std::lexicographical_compare(begin(), end(), other.begin(), other.end()); } template <typename T, size_t N, class V> template <class Tp, size_t M> array_base<typename __combined<T, Tp>::type, N + M, V> array_base<T, N, V>:: operator+(array_base<Tp, M, V> const &other) const { array_base<typename __combined<T, Tp>::type, N + M, V> result; auto next = std::copy(begin(), end(), result.begin()); std::copy(other.begin(), other.end(), next); return result; } template <typename T, size_t N, class V> template <class... Types> array_base<T, N, V>::operator std::tuple<Types...>() const { return array_to_tuple(*this, utils::make_index_sequence<N>{}, typename utils::type_sequence<Types...>{}); } template <typename T, size_t N, class V> template <typename Tp> array_base<T, N, V>::operator array_base<Tp, N, V>() const { return array_to_array<Tp, N, V>(*this, utils::make_index_sequence<N>{}); } template <typename T, size_t N, class V> auto array_base<T, N, V>::to_tuple() const -> decltype(array_to_tuple(*this, utils::make_index_sequence<N>{}, utils::make_repeated_type<T, N>())) { return array_to_tuple(*this, utils::make_index_sequence<N>{}, utils::make_repeated_type<T, N>()); } template <typename T, size_t N, class V> template <class W> array_base<T, N, W> array_base<T, N, V>::to_array() const { return reinterpret_cast<array_base<T, N, W> const &>(*this); } /* array */ template <typename T, size_t N, class V> std::ostream &operator<<(std::ostream &os, types::array_base<T, N, V> const &v) { os << "(["[std::is_same<V, types::list_version>::value]; auto iter = v.begin(); if (iter != v.end()) { while (iter + 1 != v.end()) os << *iter++ << ", "; os << *iter; } return os << ")]"[std::is_same<V, types::list_version>::value]; } 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())) { return 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)) { return std::tuple_cat(lt.to_tuple(), t); } template <class T, size_t N> dynamic_tuple<T> array_base_slicer::operator()(array<T, N> const &b, slice const &s) { normalized_slice ns = s.normalize(b.size()); array<T, N> tmp; for (long j = 0; j < ns.size(); ++j) tmp[j] = b[ns.lower + j * ns.step]; return {&tmp[0], &tmp[ns.size()]}; } template <class T, size_t N> dynamic_tuple<T> array_base_slicer::operator()(array<T, N> const &b, contiguous_slice const &s) { contiguous_normalized_slice cns = s.normalize(b.size()); return {&b[cns.lower], &b[cns.upper]}; } template <class T, size_t N> dynamic_tuple<T> array_base_slicer::operator()(array<T, N> const &b, fast_contiguous_slice const &s) { contiguous_normalized_slice cns = s.normalize(b.size()); return {&b[cns.lower], &b[cns.upper]}; } } PYTHONIC_NS_END /* 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 { return left ^ right; } template <size_t index, class... types> size_t hash_impl<index, types...>:: operator()(size_t a, const std::tuple<types...> &t) const { using nexttype = typename std::tuple_element<index, std::tuple<types...>>::type; hash_impl<index - 1, types...> next; size_t b = std::hash<nexttype>()(std::get<index>(t)); return next(hash_combiner(a, b), t); } template <class... types> size_t hash_impl<0, types...>::operator()(size_t a, const std::tuple<types...> &t) const { using nexttype = typename std::tuple_element<0, std::tuple<types...>>::type; size_t b = std::hash<nexttype>()(std::get<0>(t)); return hash_combiner(a, b); } } /* specialize std::hash */ namespace std { template <class... Types> size_t hash<std::tuple<Types...>>:: operator()(std::tuple<Types...> const &t) const { const size_t begin = std::tuple_size<std::tuple<Types...>>::value - 1; return hash_impl<begin, Types...>()(1, t); // 1 should be some largervalue } template <typename T, size_t N, class V> size_t hash<pythonic::types::array_base<T, N, V>>:: operator()(pythonic::types::array_base<T, N, V> const &l) const { size_t seed = 0; hash<T> h; for (auto const &iter : l) seed ^= h(iter) + 0x9e3779b9 + (seed << 6) + (seed >> 2); return seed; } } PYTHONIC_NS_BEGIN namespace types { template <class Tuple, size_t I> void print_tuple(std::ostream &os, Tuple const &t, utils::int_<I>) { print_tuple(os, t, utils::int_<I - 1>()); os << ", " << std::get<I>(t); } template <class Tuple> void print_tuple(std::ostream &os, Tuple const &t, utils::int_<0>) { os << std::get<0>(t); } } PYTHONIC_NS_END namespace std { template <class... Args> ostream &operator<<(ostream &os, tuple<Args...> const &t) { os << '('; pythonic::types::print_tuple(os, t, pythonic::utils::int_<sizeof...(Args)-1>()); return os << ')'; } } #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> PyObject *to_python<std::pair<K, V>>::convert(std::pair<K, V> const &t) { PyObject *out = PyTuple_New(2); PyTuple_SET_ITEM(out, 0, ::to_python(std::get<0>(t))); PyTuple_SET_ITEM(out, 1, ::to_python(std::get<1>(t))); return out; } template <typename... Tys> PyObject * to_python<types::pshape<Tys...>>::convert(types::pshape<Tys...> const &t) { return ::to_python(t.array()); } template <typename... Types> template <size_t... S> PyObject *to_python<std::tuple<Types...>>:: do_convert(std::tuple<Types...> const &t, utils::index_sequence<S...>) { PyObject *out = PyTuple_New(sizeof...(Types)); (void)std::initializer_list<bool>{ (PyTuple_SET_ITEM(out, S, ::to_python(std::get<S>(t))), true)...}; return out; } template <typename... Types> PyObject * to_python<std::tuple<Types...>>::convert(std::tuple<Types...> const &t) { return do_convert(t, utils::make_index_sequence<sizeof...(Types)>()); } template <typename T, size_t N> template <size_t... S> PyObject *to_python<types::array<T, N>>::do_convert(types::array<T, N> const &t, utils::index_sequence<S...>) { PyObject *out = PyTuple_New(N); (void)std::initializer_list<bool>{ (PyTuple_SET_ITEM(out, S, ::to_python(std::get<S>(t))), true)...}; return out; } template <typename T, size_t N> template <size_t... S> PyObject *to_python<types::static_list<T, N>>::do_convert( types::static_list<T, N> const &t, utils::index_sequence<S...>) { PyObject *out = PyList_New(N); (void)std::initializer_list<bool>{ (PyList_SET_ITEM(out, S, ::to_python(std::get<S>(t))), true)...}; return out; } template <typename T, size_t N> PyObject *to_python<types::array<T, N>>::convert(types::array<T, N> const &t) { return do_convert(t, utils::make_index_sequence<N>()); } template <typename T, size_t N> PyObject * to_python<types::static_list<T, N>>::convert(types::static_list<T, N> const &t) { return do_convert(t, utils::make_index_sequence<N>()); } template <typename... Types> template <size_t... S> bool from_python<std::tuple<Types...>> ::do_is_convertible(PyObject *obj, typename utils::index_sequence<S...>) { bool checks[] = {::is_convertible< typename std::tuple_element<S, std::tuple<Types...>>::type>( PyTuple_GET_ITEM(obj, S))...}; return std::find(std::begin(checks), std::end(checks), false) == std::end(checks); } template <typename... Types> bool from_python<std::tuple<Types...>>::is_convertible(PyObject *obj) { if (PyTuple_Check(obj)) { auto n = PyTuple_GET_SIZE(obj); if (n == sizeof...(Types)) { return do_is_convertible(obj, utils::make_index_sequence<sizeof...(Types)>()); } } return false; } template <typename... Types> template <size_t... S> std::tuple<Types...> from_python<std::tuple<Types...>>::do_convert( PyObject *obj, typename utils::index_sequence<S...>) { return std::tuple<Types...>{ ::from_python<typename std::tuple_element<S, std::tuple<Types...>>::type>( PyTuple_GET_ITEM(obj, S))...}; } template <typename... Types> std::tuple<Types...> from_python<std::tuple<Types...>>::convert(PyObject *obj) { return do_convert(obj, utils::make_index_sequence<sizeof...(Types)>()); } template <typename T, size_t N> bool from_python<types::array<T, N>>:: is_convertible(PyObject *obj) { if (PyTuple_Check(obj)) { auto n = PyTuple_GET_SIZE(obj); if (n == N) { return ::is_convertible<T>(PyTuple_GET_ITEM(obj, 0)); } } return false; } template <typename T, size_t N> template <size_t... S> types::array<T, N> from_python<types::array<T, N>>::do_convert( PyObject *obj, typename utils::index_sequence<S...>) { return {::from_python<T>(PyTuple_GET_ITEM(obj, S))...}; } template <typename T, size_t N> types::array<T, N> from_python<types::array<T, N>>:: convert(PyObject *obj) { return do_convert(obj, utils::make_index_sequence<N>()); } PYTHONIC_NS_END #endif #endif
Save File
Cancel