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); }
/** * 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; } }