#ifndef PYTHONIC_NUMPY_CONCATENATE_HPP #define PYTHONIC_NUMPY_CONCATENATE_HPP #include "pythonic/include/numpy/concatenate.hpp" #include "pythonic/utils/functor.hpp" #include "pythonic/types/ndarray.hpp" #include "pythonic/builtins/sum.hpp" #include "pythonic/builtins/ValueError.hpp" PYTHONIC_NS_BEGIN namespace numpy { namespace details { template struct concatenate_helper { // list version template void operator()(Out &&out, A const &from, long axis) const { if (axis == 0) { auto out_iter = out.begin(); for (auto &&ifrom : from) out_iter = std::copy(ifrom.begin(), ifrom.end(), out_iter); } else { std::vector::type> ifroms; for (auto &&ifrom : from) ifroms.emplace_back(ifrom.begin()); std::vector::type> difroms; for (auto &&iout : out) { difroms.clear(); for (auto &&ifrom : ifroms) difroms.emplace_back(*ifrom); concatenate_helper()(iout, difroms, axis - 1); for (auto &ifrom : ifroms) ++ifrom; } } } // array version template void operator()(Out &&out, A const &from, long axis, utils::index_sequence) const { if (axis == 0) { auto out_iter = out.begin(); (void)std::initializer_list{ (out_iter = std::copy(std::get(from).begin(), std::get(from).end(), out_iter), 1)...}; } else { types::array ifroms = {std::get(from).begin()...}; for (auto &&iout : out) { types::array< typename std::iterator_traits< typename A::value_type::const_iterator>::value_type, sizeof...(I)> difroms = {*std::get(ifroms)...}; concatenate_helper()(iout, difroms, axis - 1, utils::index_sequence{}); (void)std::initializer_list{(++std::get(ifroms), 0)...}; } } } // tuple version template void operator()(Out &&out, std::tuple const &from, long axis, utils::index_sequence) const { if (axis == 0) { auto out_iter = out.begin(); (void)std::initializer_list{ (out_iter = std::copy(std::get(from).begin(), std::get(from).end(), out_iter), 1)...}; } else { auto ifroms = std::make_tuple(std::get(from).begin()...); for (auto &&iout : out) { auto difroms = std::make_tuple(*std::get(ifroms)...); concatenate_helper()(iout, difroms, axis - 1, utils::index_sequence{}); (void)std::initializer_list{(++std::get(ifroms), 0)...}; } } } }; template <> struct concatenate_helper<0> { // list version - sentinel template void operator()(Out &&buffer, A const &from, long axis) const { } // array version template void operator()(Out &&, E const &, long, utils::index_sequence) const { } // tuple version - sentinel template void operator()(Out &&, std::tuple const &, long, utils::index_sequence) const { } }; template long concatenate_axis_size(A const &from, long axis, utils::index_sequence) { long sizes[] = {sutils::getshape(std::get(from))[axis]...}; return std::accumulate(std::begin(sizes), std::end(sizes), 0L, std::plus()); } } template auto concatenate(std::tuple const &args, long axis) -> types::ndarray< typename __combined::type::dtype...>::type, types::array< long, std::tuple_element<0, std::tuple>::type::value>> { using T = typename __combined::type::dtype...>::type; auto constexpr N = std::decay(args))>::type::value; auto shape = sutils::getshape(std::get<0>(args)); shape[axis] = details::concatenate_axis_size( args, axis, utils::make_index_sequence{}); types::ndarray< typename __combined::type::dtype...>::type, types::array< long, std::decay(args))>::type::value>> result{ shape, types::none_type{}}; details::concatenate_helper()( result, args, axis, utils::make_index_sequence{}); return result; } template types::ndarray> concatenate(types::array_base const &args, long axis) { using T = typename E::dtype; auto constexpr N = E::value; auto shape = sutils::getshape(std::get<0>(args)); shape[axis] = details::concatenate_axis_size( args, axis, utils::make_index_sequence{}); types::ndarray> out( shape, types::none_type{}); details::concatenate_helper()(out, args, axis, utils::make_index_sequence{}); return out; } template types::ndarray> concatenate(types::list const &ai, long axis) { using return_type = types::ndarray>; using T = typename return_type::dtype; auto constexpr N = return_type::value; auto shape = sutils::getshape(ai[0]); shape[axis] = std::accumulate(ai.begin(), ai.end(), 0L, [axis](long v, E const &from) { return v + sutils::getshape(from)[axis]; }); return_type out{shape, types::none_type{}}; details::concatenate_helper()(out, ai, axis); return out; ; } } PYTHONIC_NS_END #endif