summaryrefslogtreecommitdiff
path: root/libs/python/src/object/enum.cpp
diff options
context:
space:
mode:
authorLorry Tar Creator <lorry-tar-importer@baserock.org>2013-06-25 22:59:01 +0000
committer <>2013-09-27 11:49:28 +0000
commit8c4528713d907ee2cfd3bfcbbad272c749867f84 (patch)
treec09e2ce80f47b90c85cc720f5139089ad9c8cfff /libs/python/src/object/enum.cpp
downloadboost-tarball-baserock/morph.tar.gz
Imported from /home/lorry/working-area/delta_boost-tarball/boost_1_54_0.tar.bz2.boost_1_54_0baserock/morph
Diffstat (limited to 'libs/python/src/object/enum.cpp')
-rw-r--r--libs/python/src/object/enum.cpp246
1 files changed, 246 insertions, 0 deletions
diff --git a/libs/python/src/object/enum.cpp b/libs/python/src/object/enum.cpp
new file mode 100644
index 000000000..3063320cb
--- /dev/null
+++ b/libs/python/src/object/enum.cpp
@@ -0,0 +1,246 @@
+// Copyright David Abrahams 2002.
+// Distributed under the Boost Software License, Version 1.0. (See
+// accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#include <boost/python/object/enum_base.hpp>
+#include <boost/python/cast.hpp>
+#include <boost/python/scope.hpp>
+#include <boost/python/object.hpp>
+#include <boost/python/tuple.hpp>
+#include <boost/python/dict.hpp>
+#include <boost/python/str.hpp>
+#include <boost/python/extract.hpp>
+#include <boost/python/object_protocol.hpp>
+#include <structmember.h>
+
+namespace boost { namespace python { namespace objects {
+
+struct enum_object
+{
+#if PY_VERSION_HEX >= 0x03000000
+ PyLongObject base_object;
+#else
+ PyIntObject base_object;
+#endif
+ PyObject* name;
+};
+
+static PyMemberDef enum_members[] = {
+ {const_cast<char*>("name"), T_OBJECT_EX, offsetof(enum_object,name),READONLY, 0},
+ {0, 0, 0, 0, 0}
+};
+
+
+extern "C"
+{
+ static PyObject* enum_repr(PyObject* self_)
+ {
+ // XXX(bhy) Potentional memory leak here since PyObject_GetAttrString returns a new reference
+ // const char *mod = PyString_AsString(PyObject_GetAttrString( self_, const_cast<char*>("__module__")));
+ PyObject *mod = PyObject_GetAttrString( self_, "__module__");
+ enum_object* self = downcast<enum_object>(self_);
+ if (!self->name)
+ {
+ return
+#if PY_VERSION_HEX >= 0x03000000
+ PyUnicode_FromFormat("%S.%s(%ld)", mod, self_->ob_type->tp_name, PyLong_AsLong(self_));
+#else
+ PyString_FromFormat("%s.%s(%ld)", PyString_AsString(mod), self_->ob_type->tp_name, PyInt_AS_LONG(self_));
+#endif
+ }
+ else
+ {
+ PyObject* name = self->name;
+ if (name == 0)
+ return 0;
+
+ return
+#if PY_VERSION_HEX >= 0x03000000
+ PyUnicode_FromFormat("%S.%s.%S", mod, self_->ob_type->tp_name, name);
+#else
+ PyString_FromFormat("%s.%s.%s",
+ PyString_AsString(mod), self_->ob_type->tp_name, PyString_AsString(name));
+#endif
+ }
+ }
+
+ static PyObject* enum_str(PyObject* self_)
+ {
+ enum_object* self = downcast<enum_object>(self_);
+ if (!self->name)
+ {
+#if PY_VERSION_HEX >= 0x03000000
+ return PyLong_Type.tp_str(self_);
+#else
+ return PyInt_Type.tp_str(self_);
+#endif
+ }
+ else
+ {
+ return incref(self->name);
+ }
+ }
+}
+
+static PyTypeObject enum_type_object = {
+ PyVarObject_HEAD_INIT(NULL, 0) // &PyType_Type
+ const_cast<char*>("Boost.Python.enum"),
+ sizeof(enum_object), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_compare */
+ enum_repr, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ enum_str, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT
+#if PY_VERSION_HEX < 0x03000000
+ | Py_TPFLAGS_CHECKTYPES
+#endif
+ | Py_TPFLAGS_HAVE_GC
+ | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ 0, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ enum_members, /* tp_members */
+ 0, /* tp_getset */
+ 0, //&PyInt_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ 0, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+ 0, /* tp_free */
+ 0, /* tp_is_gc */
+ 0, /* tp_bases */
+ 0, /* tp_mro */
+ 0, /* tp_cache */
+ 0, /* tp_subclasses */
+ 0, /* tp_weaklist */
+#if PYTHON_API_VERSION >= 1012
+ 0 /* tp_del */
+#endif
+};
+
+object module_prefix();
+
+namespace
+{
+ object new_enum_type(char const* name, char const *doc)
+ {
+ if (enum_type_object.tp_dict == 0)
+ {
+ Py_TYPE(&enum_type_object) = incref(&PyType_Type);
+#if PY_VERSION_HEX >= 0x03000000
+ enum_type_object.tp_base = &PyLong_Type;
+#else
+ enum_type_object.tp_base = &PyInt_Type;
+#endif
+ if (PyType_Ready(&enum_type_object))
+ throw_error_already_set();
+ }
+
+ type_handle metatype(borrowed(&PyType_Type));
+ type_handle base(borrowed(&enum_type_object));
+
+ // suppress the instance __dict__ in these enum objects. There
+ // may be a slicker way, but this'll do for now.
+ dict d;
+ d["__slots__"] = tuple();
+ d["values"] = dict();
+ d["names"] = dict();
+
+ object module_name = module_prefix();
+ if (module_name)
+ d["__module__"] = module_name;
+ if (doc)
+ d["__doc__"] = doc;
+
+ object result = (object(metatype))(name, make_tuple(base), d);
+
+ scope().attr(name) = result;
+
+ return result;
+ }
+}
+
+enum_base::enum_base(
+ char const* name
+ , converter::to_python_function_t to_python
+ , converter::convertible_function convertible
+ , converter::constructor_function construct
+ , type_info id
+ , char const *doc
+ )
+ : object(new_enum_type(name, doc))
+{
+ converter::registration& converters
+ = const_cast<converter::registration&>(
+ converter::registry::lookup(id));
+
+ converters.m_class_object = downcast<PyTypeObject>(this->ptr());
+ converter::registry::insert(to_python, id);
+ converter::registry::insert(convertible, construct, id);
+}
+
+void enum_base::add_value(char const* name_, long value)
+{
+ // Convert name to Python string
+ object name(name_);
+
+ // Create a new enum instance by calling the class with a value
+ object x = (*this)(value);
+
+ // Store the object in the enum class
+ (*this).attr(name_) = x;
+
+ dict d = extract<dict>(this->attr("values"))();
+ d[value] = x;
+
+ // Set the name field in the new enum instanec
+ enum_object* p = downcast<enum_object>(x.ptr());
+ Py_XDECREF(p->name);
+ p->name = incref(name.ptr());
+
+ dict names_dict = extract<dict>(this->attr("names"))();
+ names_dict[x.attr("name")] = x;
+}
+
+void enum_base::export_values()
+{
+ dict d = extract<dict>(this->attr("names"))();
+ list items = d.items();
+ scope current;
+
+ for (unsigned i = 0, max = len(items); i < max; ++i)
+ api::setattr(current, items[i][0], items[i][1]);
+ }
+
+PyObject* enum_base::to_python(PyTypeObject* type_, long x)
+{
+ object type((type_handle(borrowed(type_))));
+
+ dict d = extract<dict>(type.attr("values"))();
+ object v = d.get(x, object());
+ return incref(
+ (v == object() ? type(x) : v).ptr());
+}
+
+}}} // namespace boost::python::object