/** * Gets the number of dimensions at index 0, including tuple * and struct as dimensions. */ static intptr_t get_leading_dim_count(const dynd::ndt::type &tp) { intptr_t ndim = tp.get_ndim(); if (ndim) { return ndim + get_leading_dim_count(tp.get_dtype()); } else if (tp.get_kind() == expr_kind) { return get_leading_dim_count(tp.value_type()); } else if (tp.get_kind() == tuple_kind || tp.get_kind() == struct_kind) { if (tp.extended<ndt::tuple_type>()->get_field_count() == 0) { return 1; } else { return 1 + get_leading_dim_count( tp.extended<ndt::tuple_type>()->get_field_type(0)); } } else { return 0; } }
intptr_t pydynd::nd::copy_from_numpy_kernel::instantiate( char *DYND_UNUSED(static_data), size_t DYND_UNUSED(data_size), char *DYND_UNUSED(data), void *ckb, intptr_t ckb_offset, const dynd::ndt::type &dst_tp, const char *dst_arrmeta, intptr_t DYND_UNUSED(nsrc), const dynd::ndt::type *src_tp, const char *const *src_arrmeta, dynd::kernel_request_t kernreq, const dynd::eval::eval_context *ectx, intptr_t nkwd, const dynd::nd::array *kwds, const std::map<std::string, dynd::ndt::type> &tp_vars) { if (src_tp[0].get_type_id() != dynd::void_type_id) { stringstream ss; ss << "Cannot instantiate dynd::nd::callable copy_from_numpy with " "signature ("; ss << src_tp[0] << ") -> " << dst_tp; throw dynd::type_error(ss.str()); } PyArray_Descr *dtype = *reinterpret_cast<PyArray_Descr *const *>(src_arrmeta[0]); uintptr_t src_alignment = reinterpret_cast<const uintptr_t *>(src_arrmeta[0])[1]; if (!PyDataType_FLAGCHK(dtype, NPY_ITEM_HASOBJECT)) { // If there is no object type in the numpy type, get the dynd equivalent // type and use it to do the copying dynd::ndt::type src_view_tp = _type_from_numpy_dtype(dtype, src_alignment); return dynd::make_assignment_kernel(ckb, ckb_offset, dst_tp, dst_arrmeta, src_view_tp, NULL, kernreq, ectx); } else if (PyDataType_ISOBJECT(dtype)) { dynd::callable_type_data *af = copy_from_pyobject::get().get(); return af->instantiate(af->static_data, 0, NULL, ckb, ckb_offset, dst_tp, dst_arrmeta, 1, src_tp, src_arrmeta, kernreq, ectx, nkwd, kwds, tp_vars); } else if (PyDataType_HASFIELDS(dtype)) { if (dst_tp.get_kind() != dynd::struct_kind && dst_tp.get_kind() != dynd::tuple_kind) { stringstream ss; ss << "Cannot assign from numpy type " << pyobject_repr((PyObject *)dtype) << " to dynd type " << dst_tp; throw invalid_argument(ss.str()); } // Get the fields out of the numpy dtype vector<PyArray_Descr *> field_dtypes_orig; vector<std::string> field_names_orig; vector<size_t> field_offsets_orig; pydynd::extract_fields_from_numpy_struct( dtype, field_dtypes_orig, field_names_orig, field_offsets_orig); intptr_t field_count = field_dtypes_orig.size(); if (field_count != dst_tp.extended<dynd::ndt::base_tuple_type>()->get_field_count()) { stringstream ss; ss << "Cannot assign from numpy type " << pyobject_repr((PyObject *)dtype) << " to dynd type " << dst_tp; throw invalid_argument(ss.str()); } // Permute the numpy fields to match with the dynd fields vector<PyArray_Descr *> field_dtypes; vector<size_t> field_offsets; if (dst_tp.get_kind() == dynd::struct_kind) { field_dtypes.resize(field_count); field_offsets.resize(field_count); for (intptr_t i = 0; i < field_count; ++i) { intptr_t src_i = dst_tp.extended<dynd::ndt::base_struct_type>()->get_field_index( field_names_orig[i]); if (src_i >= 0) { field_dtypes[src_i] = field_dtypes_orig[i]; field_offsets[src_i] = field_offsets_orig[i]; } else { stringstream ss; ss << "Cannot assign from numpy type " << pyobject_repr((PyObject *)dtype) << " to dynd type " << dst_tp; throw invalid_argument(ss.str()); } } } else { // In the tuple case, use position instead of name field_dtypes.swap(field_dtypes_orig); field_offsets.swap(field_offsets_orig); } vector<dynd::ndt::type> src_fields_tp(field_count, dynd::ndt::type::make<void>()); vector<copy_from_numpy_arrmeta> src_arrmeta_values(field_count); vector<const char *> src_fields_arrmeta(field_count); for (intptr_t i = 0; i < field_count; ++i) { src_arrmeta_values[i].src_dtype = field_dtypes[i]; src_arrmeta_values[i].src_alignment = src_alignment | field_offsets[i]; src_fields_arrmeta[i] = reinterpret_cast<const char *>(&src_arrmeta_values[i]); } const uintptr_t *dst_arrmeta_offsets = dst_tp.extended<dynd::ndt::base_tuple_type>() ->get_arrmeta_offsets_raw(); dynd::shortvector<const char *> dst_fields_arrmeta(field_count); for (intptr_t i = 0; i != field_count; ++i) { dst_fields_arrmeta[i] = dst_arrmeta + dst_arrmeta_offsets[i]; } // Todo: Remove this line dynd::nd::callable af = dynd::nd::callable::make<copy_from_numpy_kernel>( dynd::ndt::type("(void, broadcast: bool) -> T"), 0); return make_tuple_unary_op_ckernel( af.get(), af.get_type(), ckb, ckb_offset, field_count, dst_tp.extended<dynd::ndt::base_tuple_type>()->get_data_offsets( dst_arrmeta), dst_tp.extended<dynd::ndt::base_tuple_type>()->get_field_types_raw(), dst_fields_arrmeta.get(), &field_offsets[0], &src_fields_tp[0], &src_fields_arrmeta[0], kernreq, ectx); } else { stringstream ss; ss << "TODO: implement assign from numpy type " << pyobject_repr((PyObject *)dtype) << " to dynd type " << dst_tp; throw invalid_argument(ss.str()); } }