aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/python/matplotlib/py2/src/py_adaptors.h
diff options
context:
space:
mode:
authorshumkovnd <shumkovnd@yandex-team.com>2023-11-10 14:39:34 +0300
committershumkovnd <shumkovnd@yandex-team.com>2023-11-10 16:42:24 +0300
commit77eb2d3fdcec5c978c64e025ced2764c57c00285 (patch)
treec51edb0748ca8d4a08d7c7323312c27ba1a8b79a /contrib/python/matplotlib/py2/src/py_adaptors.h
parentdd6d20cadb65582270ac23f4b3b14ae189704b9d (diff)
downloadydb-77eb2d3fdcec5c978c64e025ced2764c57c00285.tar.gz
KIKIMR-19287: add task_stats_drawing script
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 0000000000..8eaa7ad6c7
--- /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__
+
+/***************************************************************************
+ * 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