std::shared_ptr tensor_from_numpy()

in source/neuropod/bindings/python_bindings.cc [102:139]


std::shared_ptr<NeuropodTensor> tensor_from_numpy(NeuropodTensorAllocator &allocator, py::array array)
{
    // Make sure the array is contiguous and aligned
    // NOLINTNEXTLINE(readability-implicit-bool-conversion, hicpp-signed-bitwise)
    if (!(array.flags() & py::detail::npy_api::constants::NPY_ARRAY_C_CONTIGUOUS_) ||
        !(array.flags() & py::detail::npy_api::constants::NPY_ARRAY_ALIGNED_))
    {
        SPDLOG_WARN("Expected numpy array to be contiguous and aligned; converting...");
        array = py::array::ensure(array,
                                  py::detail::npy_api::constants::NPY_ARRAY_C_CONTIGUOUS_ |
                                      py::detail::npy_api::constants::NPY_ARRAY_ALIGNED_);
    }

    auto ndims = array.ndim();
    auto dims  = array.shape();
    auto dtype = get_array_type(array);
    auto data  = array.mutable_data();

    // Capture the array in our deleter so it doesn't get deallocated
    // until we're done
    auto to_delete = std::make_shared<py::array>(array);
    auto deleter   = [to_delete](void *unused) mutable {
        py::gil_scoped_acquire gil;
        to_delete.reset();
    };

    // Create a vector with the shape info
    std::vector<int64_t> shape(&dims[0], &dims[ndims]);

    // Handle string tensors
    if (dtype == STRING_TENSOR)
    {
        return tensor_from_string_numpy(allocator, array, shape);
    }

    // Wrap the data from the numpy array
    return allocator.tensor_from_memory(shape, dtype, data, deleter);
}