bool pydynd::broadcast_as_scalar(const dynd::ndt::type &tp, PyObject *obj) { intptr_t obj_ndim = 0; // Estimate the number of dimensions in ``obj`` by repeatedly indexing // along zero pyobject_ownref v(obj); Py_INCREF(v); for (;;) { // Don't treat these types as sequences if (PyDict_Check(v)) { if (tp.get_dtype().get_kind() == struct_kind) { // If the object to assign to a dynd struct ends in a dict, apply // the dict as the struct's value return (tp.get_ndim() > obj_ndim); } break; } else if (PyUnicode_Check(v) || PyBytes_Check(v)) { break; } PyObject *iter = PyObject_GetIter(v); if (iter != NULL) { ++obj_ndim; if (iter == v.get()) { // This was already an iterator, don't do any broadcasting, // because we have no visibility into it. Py_DECREF(iter); return false; } else { pyobject_ownref iter_owner(iter); PyObject *item = PyIter_Next(iter); if (item == NULL) { if (PyErr_ExceptionMatches(PyExc_StopIteration)) { PyErr_Clear(); break; } else { throw exception(); } } else { v.reset(item); } } } else { PyErr_Clear(); break; } } return (get_leading_dim_count(tp) > obj_ndim); }
void pydynd::array_copy_to_numpy(PyArrayObject *dst_arr, const dynd::ndt::type &src_tp, const char *src_arrmeta, const char *src_data) { intptr_t dst_ndim = PyArray_NDIM(dst_arr); intptr_t src_ndim = src_tp.get_ndim(); uintptr_t dst_alignment = reinterpret_cast<uintptr_t>(PyArray_DATA(dst_arr)); strided_of_numpy_arrmeta dst_am_holder; const char *dst_am = reinterpret_cast<const char *>( &dst_am_holder.sdt[NPY_MAXDIMS - dst_ndim]); // Fill in metadata for a multi-dim strided array, corresponding // to the numpy array, with a void type at the end for the numpy // specific data. for (intptr_t i = 0; i < dst_ndim; ++i) { dynd::fixed_dim_type_arrmeta &am = dst_am_holder.sdt[NPY_MAXDIMS - dst_ndim + i]; am.stride = PyArray_STRIDE(dst_arr, (int)i); dst_alignment |= static_cast<uintptr_t>(am.stride); am.dim_size = PyArray_DIM(dst_arr, (int)i); } dynd::ndt::type dst_tp = dynd::ndt::make_type( dst_ndim, PyArray_SHAPE(dst_arr), dynd::ndt::make_type<void>()); dst_am_holder.am.dst_dtype = PyArray_DTYPE(dst_arr); dst_am_holder.am.dst_alignment = dst_alignment; // TODO: This is a hack, need a proper way to pass this dst param intptr_t tmp_dst_arrmeta_size = dst_ndim * sizeof(dynd::fixed_dim_type_arrmeta) + sizeof(copy_to_numpy_arrmeta); dynd::nd::array tmp_dst( reinterpret_cast<dynd::array_preamble *>( dynd::make_array_memory_block(tmp_dst_arrmeta_size).get()), true); tmp_dst.get()->tp = dst_tp; tmp_dst.get()->flags = dynd::nd::read_access_flag | dynd::nd::write_access_flag; if (dst_tp.get_arrmeta_size() > 0) { memcpy(tmp_dst.get()->metadata(), dst_am, tmp_dst_arrmeta_size); } tmp_dst.get()->data = (char *)PyArray_DATA(dst_arr); char *src_data_nonconst = const_cast<char *>(src_data); copy_to_numpy::get()->call(tmp_dst.get_type(), tmp_dst.get()->metadata(), tmp_dst.data(), 1, &src_tp, &src_arrmeta, &src_data_nonconst, 1, NULL, std::map<std::string, dynd::ndt::type>()); }
/** * 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; } }