aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/python/matplotlib/py2/src/py_adaptors.h
diff options
context:
space:
mode:
authorzverevgeny <zverevgeny@yandex-team.com>2025-05-13 19:00:02 +0300
committerzverevgeny <zverevgeny@yandex-team.com>2025-05-13 19:13:54 +0300
commit92e06374736aa28637dc0e706455b65c8268a5e6 (patch)
tree3df370c199ae25d308e542f02af20f43eab78f8a /contrib/python/matplotlib/py2/src/py_adaptors.h
parentdc63d5794da99c2ebe3f32914d0351d9707660b0 (diff)
downloadydb-92e06374736aa28637dc0e706455b65c8268a5e6.tar.gz
Import matplotlib
commit_hash:d59c2338025ef8fd1e1f961ed9d8d5fd52d0bd96
Diffstat (limited to 'contrib/python/matplotlib/py2/src/py_adaptors.h')
-rw-r--r--contrib/python/matplotlib/py2/src/py_adaptors.h251
1 files changed, 251 insertions, 0 deletions
diff --git a/contrib/python/matplotlib/py2/src/py_adaptors.h b/contrib/python/matplotlib/py2/src/py_adaptors.h
new file mode 100644
index 00000000000..3d0dbdab45b
--- /dev/null
+++ b/contrib/python/matplotlib/py2/src/py_adaptors.h
@@ -0,0 +1,251 @@
+/* -*- mode: c++; c-basic-offset: 4 -*- */
+
+#ifndef __PY_ADAPTORS_H__
+#define __PY_ADAPTORS_H__
+#define PY_SSIZE_T_CLEAN
+/***************************************************************************
+ * This module contains a number of C++ classes that adapt Python data
+ * structures to C++ and Agg-friendly interfaces.
+ */
+
+#include <Python.h>
+
+#include "numpy/arrayobject.h"
+
+#include "py_exceptions.h"
+
+extern "C" {
+int convert_path(PyObject *obj, void *pathp);
+}
+
+namespace py
+{
+
+/************************************************************
+ * py::PathIterator acts as a bridge between Numpy and Agg. Given a
+ * pair of Numpy arrays, vertices and codes, it iterates over
+ * those vertices and codes, using the standard Agg vertex source
+ * interface:
+ *
+ * unsigned vertex(double* x, double* y)
+ */
+class PathIterator
+{
+ /* We hold references to the Python objects, not just the
+ underlying data arrays, so that Python reference counting
+ can work.
+ */
+ PyArrayObject *m_vertices;
+ PyArrayObject *m_codes;
+
+ unsigned m_iterator;
+ unsigned m_total_vertices;
+
+ /* This class doesn't actually do any simplification, but we
+ store the value here, since it is obtained from the Python
+ object.
+ */
+ bool m_should_simplify;
+ double m_simplify_threshold;
+
+ public:
+ inline PathIterator()
+ : m_vertices(NULL),
+ m_codes(NULL),
+ m_iterator(0),
+ m_total_vertices(0),
+ m_should_simplify(false),
+ m_simplify_threshold(1.0 / 9.0)
+ {
+ }
+
+ inline PathIterator(PyObject *vertices,
+ PyObject *codes,
+ bool should_simplify,
+ double simplify_threshold)
+ : m_vertices(NULL), m_codes(NULL), m_iterator(0)
+ {
+ if (!set(vertices, codes, should_simplify, simplify_threshold))
+ throw py::exception();
+ }
+
+ inline PathIterator(PyObject *vertices, PyObject *codes)
+ : m_vertices(NULL), m_codes(NULL), m_iterator(0)
+ {
+ if (!set(vertices, codes))
+ throw py::exception();
+ }
+
+ inline PathIterator(const PathIterator &other)
+ {
+ Py_XINCREF(other.m_vertices);
+ m_vertices = other.m_vertices;
+
+ Py_XINCREF(other.m_codes);
+ m_codes = other.m_codes;
+
+ m_iterator = 0;
+ m_total_vertices = other.m_total_vertices;
+
+ m_should_simplify = other.m_should_simplify;
+ m_simplify_threshold = other.m_simplify_threshold;
+ }
+
+ ~PathIterator()
+ {
+ Py_XDECREF(m_vertices);
+ Py_XDECREF(m_codes);
+ }
+
+ inline int
+ set(PyObject *vertices, PyObject *codes, bool should_simplify, double simplify_threshold)
+ {
+ m_should_simplify = should_simplify;
+ m_simplify_threshold = simplify_threshold;
+
+ Py_XDECREF(m_vertices);
+ m_vertices = (PyArrayObject *)PyArray_FromObject(vertices, NPY_DOUBLE, 2, 2);
+
+ if (!m_vertices || PyArray_DIM(m_vertices, 1) != 2) {
+ PyErr_SetString(PyExc_ValueError, "Invalid vertices array");
+ return 0;
+ }
+
+ Py_XDECREF(m_codes);
+ m_codes = NULL;
+
+ if (codes != NULL && codes != Py_None) {
+ m_codes = (PyArrayObject *)PyArray_FromObject(codes, NPY_UINT8, 1, 1);
+
+ if (!m_codes || PyArray_DIM(m_codes, 0) != PyArray_DIM(m_vertices, 0)) {
+ PyErr_SetString(PyExc_ValueError, "Invalid codes array");
+ return 0;
+ }
+ }
+
+ m_total_vertices = (unsigned)PyArray_DIM(m_vertices, 0);
+ m_iterator = 0;
+
+ return 1;
+ }
+
+ inline int set(PyObject *vertices, PyObject *codes)
+ {
+ return set(vertices, codes, false, 0.0);
+ }
+
+ inline unsigned vertex(double *x, double *y)
+ {
+ if (m_iterator >= m_total_vertices) {
+ *x = 0.0;
+ *y = 0.0;
+ return agg::path_cmd_stop;
+ }
+
+ const size_t idx = m_iterator++;
+
+ char *pair = (char *)PyArray_GETPTR2(m_vertices, idx, 0);
+ *x = *(double *)pair;
+ *y = *(double *)(pair + PyArray_STRIDE(m_vertices, 1));
+
+ if (m_codes != NULL) {
+ return (unsigned)(*(char *)PyArray_GETPTR1(m_codes, idx));
+ } else {
+ return idx == 0 ? agg::path_cmd_move_to : agg::path_cmd_line_to;
+ }
+ }
+
+ inline void rewind(unsigned path_id)
+ {
+ m_iterator = path_id;
+ }
+
+ inline unsigned total_vertices() const
+ {
+ return m_total_vertices;
+ }
+
+ inline bool should_simplify() const
+ {
+ return m_should_simplify;
+ }
+
+ inline double simplify_threshold() const
+ {
+ return m_simplify_threshold;
+ }
+
+ inline bool has_curves() const
+ {
+ return m_codes != NULL;
+ }
+
+ inline void *get_id()
+ {
+ return (void *)m_vertices;
+ }
+};
+
+class PathGenerator
+{
+ PyObject *m_paths;
+ Py_ssize_t m_npaths;
+
+ public:
+ typedef PathIterator path_iterator;
+
+ PathGenerator(PyObject *obj) : m_paths(NULL), m_npaths(0)
+ {
+ if (!set(obj)) {
+ throw py::exception();
+ }
+ }
+
+ ~PathGenerator()
+ {
+ Py_XDECREF(m_paths);
+ }
+
+ int set(PyObject *obj)
+ {
+ if (!PySequence_Check(obj)) {
+ return 0;
+ }
+
+ m_paths = obj;
+ Py_INCREF(m_paths);
+
+ m_npaths = PySequence_Size(m_paths);
+
+ return 1;
+ }
+
+ Py_ssize_t num_paths() const
+ {
+ return m_npaths;
+ }
+
+ Py_ssize_t size() const
+ {
+ return m_npaths;
+ }
+
+ path_iterator operator()(size_t i)
+ {
+ path_iterator path;
+ PyObject *item;
+
+ item = PySequence_GetItem(m_paths, i % m_npaths);
+ if (item == NULL) {
+ throw py::exception();
+ }
+ if (!convert_path(item, &path)) {
+ throw py::exception();
+ }
+ Py_DECREF(item);
+ return path;
+ }
+};
+}
+
+#endif