diff options
Diffstat (limited to 'third_party/immer/extra/python/src/immer-raw.cpp')
-rw-r--r-- | third_party/immer/extra/python/src/immer-raw.cpp | 402 |
1 files changed, 402 insertions, 0 deletions
diff --git a/third_party/immer/extra/python/src/immer-raw.cpp b/third_party/immer/extra/python/src/immer-raw.cpp new file mode 100644 index 000000000000..283f973c8d0f --- /dev/null +++ b/third_party/immer/extra/python/src/immer-raw.cpp @@ -0,0 +1,402 @@ +// +// immer: immutable data structures for C++ +// Copyright (C) 2016, 2017, 2018 Juan Pedro Bolivar Puente +// +// This software is distributed under the Boost Software License, Version 1.0. +// See accompanying file LICENSE or copy at http://boost.org/LICENSE_1_0.txt +// + +extern "C" { +#include <Python.h> +#include <structmember.h> +} + +#include <immer/vector.hpp> +#include <immer/algorithm.hpp> +#include <immer/refcount/unsafe_refcount_policy.hpp> + +#include <iostream> + +namespace { + +struct heap_t +{ + template <typename ...Tags> + static void* allocate(std::size_t size, Tags...) + { + return PyMem_Malloc(size); + } + + template <typename ...Tags> + static void deallocate(std::size_t, void* obj, Tags...) + { + PyMem_Free(obj); + } +}; + +struct object_t +{ + struct wrap_t {}; + struct adopt_t {}; + + PyObject* ptr_ = nullptr; + + object_t() = delete; + ~object_t() { Py_XDECREF(ptr_); } + + explicit object_t(PyObject* p, wrap_t) : ptr_{p} {} + explicit object_t(PyObject* p, adopt_t) : ptr_{p} + { + assert(p); + Py_INCREF(p); + } + + static object_t wrap(PyObject* p) { return object_t{p, wrap_t{}}; } + static object_t adopt(PyObject* p) { return object_t{p, adopt_t{}}; } + + object_t(const object_t& o) : ptr_(o.ptr_) { Py_INCREF(ptr_); } + object_t(object_t&& o) { std::swap(ptr_, o.ptr_); } + + object_t& operator=(const object_t& o) + { + Py_XINCREF(o.ptr_); + Py_XDECREF(ptr_); + ptr_ = o.ptr_; + return *this; + } + object_t& operator=(object_t&& o) + { + std::swap(ptr_, o.ptr_); + return *this; + } + + PyObject* release() + { + auto p = ptr_; + ptr_ = nullptr; + return p; + } + + PyObject* get() const { return ptr_; } +}; + +using memory_t = immer::memory_policy< + immer::unsafe_free_list_heap_policy<heap_t>, + immer::unsafe_refcount_policy>; + +using vector_impl_t = immer::vector<object_t, memory_t>; + +struct vector_t +{ + PyObject_HEAD + vector_impl_t impl; + PyObject* in_weakreflist; + + static PyTypeObject type; +}; + +vector_t* empty_vector = nullptr; + +vector_t* make_vector() +{ + auto* v = PyObject_GC_New(vector_t, &vector_t::type); + new (&v->impl) vector_impl_t{}; + v->in_weakreflist = nullptr; + PyObject_GC_Track((PyObject*)v); + return v; +} + +vector_t* make_vector(vector_impl_t&& impl) +{ + auto v = PyObject_GC_New(vector_t, &vector_t::type); + new (&v->impl) vector_impl_t{std::move(impl)}; + v->in_weakreflist = nullptr; + PyObject_GC_Track((PyObject*)v); + return v; +} + +auto todo() +{ + PyErr_SetString(PyExc_RuntimeError, "immer: todo!"); + return nullptr; +} + +void vector_dealloc(vector_t* self) +{ + if (self->in_weakreflist != nullptr) + PyObject_ClearWeakRefs((PyObject*)self); + + PyObject_GC_UnTrack((PyObject*)self); + Py_TRASHCAN_SAFE_BEGIN(self); + + self->impl.~vector_impl_t(); + + PyObject_GC_Del(self); + Py_TRASHCAN_SAFE_END(self); +} + +PyObject* vector_to_list(vector_t* self) +{ + auto list = PyList_New(self->impl.size()); + auto idx = 0; + immer::for_each(self->impl, [&] (auto&& obj) { + auto o = obj.get(); + Py_INCREF(o); + PyList_SET_ITEM(list, idx, o); + ++idx; + }); + return list; +} + +PyObject* vector_repr(vector_t *self) +{ + auto list = vector_to_list(self); + auto list_repr = PyObject_Repr(list); + Py_DECREF(list); + + if (!list_repr) return nullptr; + +#if PY_MAJOR_VERSION >= 3 + auto s = PyUnicode_FromFormat("%s%U%s", "immer.vector(", list_repr, ")"); + Py_DECREF(list_repr); +#else + auto s = PyString_FromString("immer.vector("); + PyString_ConcatAndDel(&s, list_repr); + PyString_ConcatAndDel(&s, PyString_FromString(")")); +#endif + return s; +} + +Py_ssize_t vector_len(vector_t* self) +{ + return self->impl.size(); +} + +PyObject* vector_extend(vector_t* self, PyObject* iterable) +{ + return todo(); +} + +vector_t* vector_append(vector_t* self, PyObject *obj) +{ + assert(obj != nullptr); + return make_vector(self->impl.push_back(object_t::adopt(obj))); +} + +vector_t* vector_set(vector_t* self, PyObject* args) +{ + PyObject* obj = nullptr; + Py_ssize_t pos; + // the n parses for size, the O parses for a Python object + if(!PyArg_ParseTuple(args, "nO", &pos, &obj)) { + return nullptr; + } + if (pos < 0) + pos += self->impl.size(); + if (pos < 0 || pos > (Py_ssize_t)self->impl.size()) { + PyErr_Format(PyExc_IndexError, "Index out of range: %zi", pos); + return nullptr; + } + return make_vector(self->impl.set(pos, object_t::adopt(obj))); +} + +PyObject* vector_new(PyTypeObject* subtype, PyObject *args, PyObject *kwds) +{ + Py_INCREF(empty_vector); + return (PyObject*)empty_vector; +} + +long vector_hash(vector_t* self) +{ + todo(); + return 0; +} + +PyObject* vector_get_item(vector_t* self, Py_ssize_t pos) +{ + if (pos < 0) + pos += self->impl.size(); + if (pos < 0 || pos >= (Py_ssize_t)self->impl.size()) { + PyErr_Format(PyExc_IndexError, "Index out of range: %zi", pos); + return nullptr; + } + auto r = self->impl[pos]; + return r.release(); +} + +PyObject* vector_subscript(vector_t* self, PyObject* item) +{ + if (PyIndex_Check(item)) { + auto i = PyNumber_AsSsize_t(item, PyExc_IndexError); + if (i == -1 && PyErr_Occurred()) + return nullptr; + return vector_get_item(self, i); + } else if (PySlice_Check(item)) { + return todo(); + } else { + PyErr_Format(PyExc_TypeError, + "vector indices must be integers, not %.200s", + Py_TYPE(item)->tp_name); + return nullptr; + } +} + +PyObject* vector_repeat(vector_t* self, Py_ssize_t n) +{ + return todo(); +} + +int vector_traverse(vector_t* self, visitproc visit, void* arg) +{ + auto result = 0; + immer::all_of(self->impl, [&] (auto&& o) { + return 0 == (result = [&] { + Py_VISIT(o.get()); + return 0; + }()); + }); + return result; +} + +PyObject* vector_richcompare(PyObject* v, PyObject* w, int op) +{ + return todo(); +} + +PyObject* vector_iter(PyObject* self) +{ + return todo(); +} + +PyMethodDef vector_methods[] = +{ + {"append", (PyCFunction)vector_append, METH_O, "Appends an element"}, + {"set", (PyCFunction)vector_set, METH_VARARGS, "Inserts an element at the specified position"}, + {"extend", (PyCFunction)vector_extend, METH_O|METH_COEXIST, "Extend"}, + {"tolist", (PyCFunction)vector_to_list, METH_NOARGS, "Convert to list"}, + {0} +}; + +PyMemberDef vector_members[] = +{ + {0} /* sentinel */ +}; + +PySequenceMethods vector_sequence_methods = +{ + (lenfunc)vector_len, /* sq_length */ + (binaryfunc)vector_extend, /* sq_concat */ + (ssizeargfunc)vector_repeat, /* sq_repeat */ + (ssizeargfunc)vector_get_item, /* sq_item */ + 0, /* sq_slice */ + 0, /* sq_ass_item */ + 0, /* sq_ass_slice */ + 0, /* sq_contains */ + 0, /* sq_inplace_concat */ + 0, /* sq_inplace_repeat */ +}; + +PyMappingMethods vector_mapping_methods = +{ + (lenfunc)vector_len, + (binaryfunc)vector_subscript, + 0 +}; + +PyTypeObject vector_t::type = +{ + PyVarObject_HEAD_INIT(NULL, 0) + "immer.Vector", /* tp_name */ + sizeof(vector_t), /* tp_basicsize */ + 0, /* tp_itemsize */ + (destructor)vector_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + (reprfunc)vector_repr, /* tp_repr */ + 0, /* tp_as_number */ + &vector_sequence_methods, /* tp_as_sequence */ + &vector_mapping_methods, /* tp_as_mapping */ + (hashfunc)vector_hash, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */ + "", /* tp_doc */ + (traverseproc)vector_traverse, /* tp_traverse */ + 0, /* tp_clear */ + vector_richcompare, /* tp_richcompare */ + offsetof(vector_t, in_weakreflist), /* tp_weaklistoffset */ + vector_iter, /* tp_iter */ + 0, /* tp_iternext */ + vector_methods, /* tp_methods */ + vector_members, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + vector_new, /* tp_new */ +}; + +#if PY_MAJOR_VERSION >= 3 +struct PyModuleDef module_def = +{ + PyModuleDef_HEAD_INIT, + "immer_python_module", /* m_name */ + "", /* m_doc */ + -1, /* m_size */ + /module_methods, /* m_methods */ + 0, /* m_reload */ + 0, /* m_traverse */ + 0, /* m_clear */ + 0, /* m_free */ +}; +#endif + +PyMethodDef module_methods[] = { + {0, 0, 0, 0} +}; + +PyObject* module_init() +{ + if (PyType_Ready(&vector_t::type) < 0) + return nullptr; + +#if PY_MAJOR_VERSION >= 3 + auto m = PyModule_Create(&module_def); +#else + auto m = Py_InitModule3("immer_python_module", module_methods, ""); +#endif + if (!m) + return nullptr; + + if (!empty_vector) + empty_vector = make_vector(); + + Py_INCREF(&vector_t::type); + PyModule_AddObject(m, "Vector", (PyObject*) &vector_t::type); + return m; +} + +} // anonymous namespace + +extern "C" { +#if PY_MAJOR_VERSION >= 3 +PyMODINIT_FUNC PyInit_immer_python_module() +{ + return module_init(); +} +#else +PyMODINIT_FUNC initimmer_python_module() +{ + module_init(); +} +#endif +} |