static void as_numpy_analysis(pyobject_ownref *out_numpy_dtype, bool *out_requires_copy, intptr_t ndim, const ndt::type &dt, const char *arrmeta) { if (dt.is_builtin()) { // DyND builtin types out_numpy_dtype->reset((PyObject *)PyArray_DescrFromType( dynd_to_numpy_type_id[dt.get_type_id()])); return; } else if (dt.get_type_id() == view_type_id && dt.operand_type().get_type_id() == fixed_bytes_type_id) { // View operation for alignment as_numpy_analysis(out_numpy_dtype, out_requires_copy, ndim, dt.value_type(), NULL); return; } switch (dt.get_type_id()) { case fixed_string_type_id: { const ndt::fixed_string_type *fsd = dt.extended<ndt::fixed_string_type>(); PyArray_Descr *result; switch (fsd->get_encoding()) { case string_encoding_ascii: result = PyArray_DescrNewFromType(NPY_STRING); result->elsize = (int)fsd->get_data_size(); out_numpy_dtype->reset((PyObject *)result); return; case string_encoding_utf_32: result = PyArray_DescrNewFromType(NPY_UNICODE); result->elsize = (int)fsd->get_data_size(); out_numpy_dtype->reset((PyObject *)result); return; default: out_numpy_dtype->clear(); *out_requires_copy = true; return; } break; } case string_type_id: { // Convert to numpy object type, requires copy out_numpy_dtype->clear(); *out_requires_copy = true; return; } case date_type_id: { #if NPY_API_VERSION >= 6 // At least NumPy 1.6 out_numpy_dtype->clear(); *out_requires_copy = true; return; #else throw runtime_error("NumPy >= 1.6 is required for dynd date type interop"); #endif } case datetime_type_id: { #if NPY_API_VERSION >= 6 // At least NumPy 1.6 out_numpy_dtype->clear(); *out_requires_copy = true; return; #else throw runtime_error("NumPy >= 1.6 is required for dynd date type interop"); #endif } case property_type_id: { const ndt::property_type *pd = dt.extended<ndt::property_type>(); // Special-case of 'int64 as date' property type, which is binary // compatible with NumPy's "M8[D]" if (pd->is_reversed_property() && pd->get_value_type().get_type_id() == date_type_id && pd->get_operand_type().get_type_id() == int64_type_id) { PyArray_Descr *datedt = NULL; #if PY_VERSION_HEX >= 0x03000000 pyobject_ownref M8str(PyUnicode_FromString("M8[D]")); #else pyobject_ownref M8str(PyString_FromString("M8[D]")); #endif if (!PyArray_DescrConverter(M8str.get(), &datedt)) { throw dynd::type_error("Failed to create NumPy datetime64[D] dtype"); } out_numpy_dtype->reset((PyObject *)datedt); return; } break; } case byteswap_type_id: { const ndt::base_expr_type *bed = dt.extended<ndt::base_expr_type>(); // Analyze the unswapped version as_numpy_analysis(out_numpy_dtype, out_requires_copy, ndim, bed->get_value_type(), arrmeta); pyobject_ownref swapdt(out_numpy_dtype->release()); // Byteswap the numpy dtype out_numpy_dtype->reset((PyObject *)PyArray_DescrNewByteorder( (PyArray_Descr *)swapdt.get(), NPY_SWAP)); return; } case fixed_dim_type_id: { const ndt::base_dim_type *bdt = dt.extended<ndt::base_dim_type>(); if (ndim > 0) { // If this is one of the array dimensions, it simply // becomes one of the numpy _array dimensions as_numpy_analysis(out_numpy_dtype, out_requires_copy, ndim - 1, bdt->get_element_type(), arrmeta + sizeof(fixed_dim_type_arrmeta)); return; } else { // If this isn't one of the array dimensions, it maps into // a numpy dtype with a shape out_numpy_dtype->clear(); *out_requires_copy = true; return; } break; } /* case cfixed_dim_type_id: { const cfixed_dim_type *fad = dt.extended<cfixed_dim_type>(); if (ndim > 0) { // If this is one of the array dimensions, it simply // becomes one of the numpy _array dimensions as_numpy_analysis(out_numpy_dtype, out_requires_copy, ndim - 1, fad->get_element_type(), arrmeta + sizeof(cfixed_dim_type_arrmeta)); return; } else { // If this isn't one of the array dimensions, it maps into // a numpy dtype with a shape // Build up the shape of the array for NumPy pyobject_ownref shape(PyList_New(0)); ndt::type element_tp = dt; while (ndim > 0) { size_t dim_size = 0; if (dt.get_type_id() == cfixed_dim_type_id) { const cfixed_dim_type *cfd = element_tp.extended<cfixed_dim_type>(); element_tp = cfd->get_element_type(); if (cfd->get_data_size() != element_tp.get_data_size() * dim_size) { // If it's not C-order, a copy is required out_numpy_dtype->clear(); *out_requires_copy = true; return; } } else { stringstream ss; ss << "dynd as_numpy could not convert dynd type "; ss << dt; ss << " to a numpy dtype"; throw dynd::type_error(ss.str()); } --ndim; if (PyList_Append(shape.get(), PyLong_FromSize_t(dim_size)) < 0) { throw runtime_error("propagating python error"); } } // Get the numpy dtype of the element pyobject_ownref child_numpy_dtype; as_numpy_analysis(&child_numpy_dtype, out_requires_copy, 0, element_tp, arrmeta); if (*out_requires_copy) { // If the child required a copy, stop right away out_numpy_dtype->clear(); return; } // Create the result numpy dtype pyobject_ownref tuple_obj(PyTuple_New(2)); PyTuple_SET_ITEM(tuple_obj.get(), 0, child_numpy_dtype.release()); PyTuple_SET_ITEM(tuple_obj.get(), 1, shape.release()); PyArray_Descr *result = NULL; if (!PyArray_DescrConverter(tuple_obj, &result)) { throw dynd::type_error( "failed to convert dynd type into numpy subarray dtype"); } // Put the final numpy dtype reference in the output out_numpy_dtype->reset((PyObject *)result); return; } break; } */ case struct_type_id: { if (dt.get_type_id() == struct_type_id && arrmeta == NULL) { // If it's a struct type with no arrmeta, a copy is required out_numpy_dtype->clear(); *out_requires_copy = true; return; } const ndt::base_struct_type *bs = dt.extended<ndt::base_struct_type>(); const uintptr_t *offsets = bs->get_data_offsets(arrmeta); size_t field_count = bs->get_field_count(); pyobject_ownref names_obj(PyList_New(field_count)); for (size_t i = 0; i < field_count; ++i) { const dynd::string &fn = bs->get_field_name_raw(i); #if PY_VERSION_HEX >= 0x03000000 pyobject_ownref name_str( PyUnicode_FromStringAndSize(fn.begin(), fn.end() - fn.begin())); #else pyobject_ownref name_str( PyString_FromStringAndSize(fn.begin(), fn.end() - fn.begin())); #endif PyList_SET_ITEM(names_obj.get(), i, name_str.release()); } pyobject_ownref formats_obj(PyList_New(field_count)); for (size_t i = 0; i < field_count; ++i) { // Get the numpy dtype of the element pyobject_ownref field_numpy_dtype; as_numpy_analysis(&field_numpy_dtype, out_requires_copy, 0, bs->get_field_type(i), arrmeta); if (*out_requires_copy) { // If the field required a copy, stop right away out_numpy_dtype->clear(); return; } PyList_SET_ITEM(formats_obj.get(), i, field_numpy_dtype.release()); } pyobject_ownref offsets_obj(PyList_New(field_count)); for (size_t i = 0; i < field_count; ++i) { PyList_SET_ITEM((PyObject *)offsets_obj, i, PyLong_FromSize_t(offsets[i])); } pyobject_ownref dict_obj(PyDict_New()); PyDict_SetItemString(dict_obj, "names", names_obj); PyDict_SetItemString(dict_obj, "formats", formats_obj); PyDict_SetItemString(dict_obj, "offsets", offsets_obj); if (dt.get_data_size() > 0) { pyobject_ownref itemsize_obj(PyLong_FromSize_t(dt.get_data_size())); PyDict_SetItemString(dict_obj, "itemsize", itemsize_obj); } PyArray_Descr *result = NULL; if (!PyArray_DescrConverter(dict_obj, &result)) { stringstream ss; ss << "failed to convert dynd type " << dt << " into numpy dtype via dict"; throw dynd::type_error(ss.str()); } out_numpy_dtype->reset((PyObject *)result); return; } default: { break; } } if (dt.get_kind() == expr_kind) { // If none of the prior checks caught this expression, // a copy is required. out_numpy_dtype->clear(); *out_requires_copy = true; return; } // Anything which fell through is an error stringstream ss; ss << "dynd as_numpy could not convert dynd type "; ss << dt; ss << " to a numpy dtype"; throw dynd::type_error(ss.str()); }
void dynd::make_ckernel_deferred_from_assignment( const ndt::type& dst_tp, const ndt::type& src_tp, const ndt::type& src_expr_tp, deferred_ckernel_funcproto_t funcproto, assign_error_mode errmode, ckernel_deferred& out_ckd, const dynd::eval::eval_context *ectx) { if (src_tp.operand_type() != src_expr_tp.operand_type()) { stringstream ss; ss << "make_ckernel_deferred_from_assignment: src_tp " << src_tp; ss << " and src_expr_tp " << src_expr_tp; ss << " must have matching operand types"; throw type_error(ss.str()); } memset(&out_ckd, 0, sizeof(ckernel_deferred)); if (funcproto == unary_operation_funcproto) { // Since a unary operation was requested, it's a straightforward unary assignment ckernel unary_assignment_ckernel_deferred_data *data = new unary_assignment_ckernel_deferred_data; out_ckd.data_ptr = data; out_ckd.free_func = &delete_unary_assignment_ckernel_deferred_data; data->data_types[0] = dst_tp; data->data_types[1] = src_tp; data->data_types[2] = src_expr_tp; data->errmode = errmode; data->ectx = *ectx; out_ckd.instantiate_func = &instantiate_unary_assignment_ckernel; out_ckd.ckernel_funcproto = unary_operation_funcproto; out_ckd.data_types_size = 2; out_ckd.data_dynd_types = data->data_types; } else if (funcproto == expr_operation_funcproto) { if (src_tp.get_type_id() == expr_type_id && (&src_tp == &src_expr_tp)) { const expr_type *etp = static_cast<const expr_type *>(src_tp.extended()); const base_struct_type *operands_type = static_cast<const base_struct_type *>(etp->get_operand_type().extended()); const ndt::type *operand_types = operands_type->get_field_types(); // Expose the expr type's expression intptr_t nargs = operands_type->get_field_count(); size_t sizeof_data_mem = sizeof(expr_ckernel_deferred_data) + sizeof(void *) * nargs; void *data_mem = malloc(sizeof_data_mem); memset(data_mem, 0, sizeof_data_mem); expr_ckernel_deferred_data *data = reinterpret_cast<expr_ckernel_deferred_data *>(data_mem); out_ckd.data_ptr = data; out_ckd.free_func = &delete_expr_ckernel_deferred_data; data->data_types_size = nargs + 1; ndt::type *data_types_arr = &data->data_types[0]; data_types_arr[0] = dst_tp; for (intptr_t i = 0; i < nargs; ++i) { // Dereference the pointer type in each field const pointer_type *field_ptr_type = static_cast<const pointer_type *>(operand_types[i].extended()); data_types_arr[i+1] = field_ptr_type->get_target_type(); } data->expr_type = static_cast<const expr_type *>(ndt::type(etp, true).release()); data->errmode = errmode; data->ectx = *ectx; out_ckd.instantiate_func = &instantiate_expr_ckernel; out_ckd.ckernel_funcproto = expr_operation_funcproto; out_ckd.data_types_size = nargs + 1; out_ckd.data_dynd_types = data->data_types; } else { // Adapt the assignment to an expr kernel unary_assignment_ckernel_deferred_data *data = new unary_assignment_ckernel_deferred_data; out_ckd.data_ptr = data; out_ckd.free_func = &delete_unary_assignment_ckernel_deferred_data; data->data_types[0] = dst_tp; data->data_types[1] = src_tp; data->data_types[2] = src_expr_tp; data->errmode = errmode; data->ectx = *ectx; out_ckd.instantiate_func = &instantiate_adapted_expr_assignment_ckernel; out_ckd.ckernel_funcproto = expr_operation_funcproto; out_ckd.data_types_size = 2; out_ckd.data_dynd_types = data->data_types; } } else { stringstream ss; ss << "unrecognized ckernel function prototype enum value " << funcproto; throw runtime_error(ss.str()); } }