Improve vacpp support.
[boost.git] / boost / libs / python / src / object / enum.cpp
bloba96cc8196570251e9f28d03819f37a12d9550d19
1 // Copyright David Abrahams 2002.
2 // Distributed under the Boost Software License, Version 1.0. (See
3 // accompanying file LICENSE_1_0.txt or copy at
4 // http://www.boost.org/LICENSE_1_0.txt)
6 #include <boost/python/object/enum_base.hpp>
7 #include <boost/python/cast.hpp>
8 #include <boost/python/scope.hpp>
9 #include <boost/python/object.hpp>
10 #include <boost/python/tuple.hpp>
11 #include <boost/python/dict.hpp>
12 #include <boost/python/str.hpp>
13 #include <boost/python/extract.hpp>
14 #include <boost/python/object_protocol.hpp>
15 #include <structmember.h>
17 namespace boost { namespace python { namespace objects {
19 struct enum_object
21 PyIntObject base_object;
22 PyObject* name;
25 static PyMemberDef enum_members[] = {
26 {"name", T_OBJECT_EX, offsetof(enum_object,name),READONLY, 0},
27 {0, 0, 0, 0, 0}
31 extern "C"
33 static PyObject* enum_repr(PyObject* self_)
35 enum_object* self = downcast<enum_object>(self_);
36 if (!self->name)
38 return PyString_FromFormat("%s(%ld)", self_->ob_type->tp_name, PyInt_AS_LONG(self_));
40 else
42 char* name = PyString_AsString(self->name);
43 if (name == 0)
44 return 0;
46 return PyString_FromFormat("%s.%s", self_->ob_type->tp_name, name);
50 static PyObject* enum_str(PyObject* self_)
52 enum_object* self = downcast<enum_object>(self_);
53 if (!self->name)
55 return PyInt_Type.tp_str(self_);
57 else
59 return incref(self->name);
64 static PyTypeObject enum_type_object = {
65 PyObject_HEAD_INIT(0) // &PyType_Type
67 "Boost.Python.enum",
68 sizeof(enum_object), /* tp_basicsize */
69 0, /* tp_itemsize */
70 0, /* tp_dealloc */
71 0, /* tp_print */
72 0, /* tp_getattr */
73 0, /* tp_setattr */
74 0, /* tp_compare */
75 enum_repr, /* tp_repr */
76 0, /* tp_as_number */
77 0, /* tp_as_sequence */
78 0, /* tp_as_mapping */
79 0, /* tp_hash */
80 0, /* tp_call */
81 enum_str, /* tp_str */
82 0, /* tp_getattro */
83 0, /* tp_setattro */
84 0, /* tp_as_buffer */
85 Py_TPFLAGS_DEFAULT
86 | Py_TPFLAGS_CHECKTYPES
87 | Py_TPFLAGS_HAVE_GC
88 | Py_TPFLAGS_BASETYPE, /* tp_flags */
89 0, /* tp_doc */
90 0, /* tp_traverse */
91 0, /* tp_clear */
92 0, /* tp_richcompare */
93 0, /* tp_weaklistoffset */
94 0, /* tp_iter */
95 0, /* tp_iternext */
96 0, /* tp_methods */
97 enum_members, /* tp_members */
98 0, /* tp_getset */
99 0, //&PyInt_Type, /* tp_base */
100 0, /* tp_dict */
101 0, /* tp_descr_get */
102 0, /* tp_descr_set */
103 0, /* tp_dictoffset */
104 0, /* tp_init */
105 0, /* tp_alloc */
106 0, /* tp_new */
107 0, /* tp_free */
108 0, /* tp_is_gc */
109 0, /* tp_bases */
110 0, /* tp_mro */
111 0, /* tp_cache */
112 0, /* tp_subclasses */
113 0, /* tp_weaklist */
114 #if PYTHON_API_VERSION >= 1012
115 0 /* tp_del */
116 #endif
119 object module_prefix();
121 namespace
123 object new_enum_type(char const* name)
125 if (enum_type_object.tp_dict == 0)
127 enum_type_object.ob_type = incref(&PyType_Type);
128 enum_type_object.tp_base = &PyInt_Type;
129 if (PyType_Ready(&enum_type_object))
130 throw_error_already_set();
133 type_handle metatype(borrowed(&PyType_Type));
134 type_handle base(borrowed(&enum_type_object));
136 // suppress the instance __dict__ in these enum objects. There
137 // may be a slicker way, but this'll do for now.
138 dict d;
139 d["__slots__"] = tuple();
140 d["values"] = dict();
142 object module_name = module_prefix();
143 if (module_name)
144 module_name += '.';
146 object result = (object(metatype))(
147 module_name + name, make_tuple(base), d);
149 scope().attr(name) = result;
151 return result;
155 enum_base::enum_base(
156 char const* name
157 , converter::to_python_function_t to_python
158 , converter::convertible_function convertible
159 , converter::constructor_function construct
160 , type_info id
162 : object(new_enum_type(name))
164 converter::registration& converters
165 = const_cast<converter::registration&>(
166 converter::registry::lookup(id));
168 converters.m_class_object = downcast<PyTypeObject>(this->ptr());
169 converter::registry::insert(to_python, id);
170 converter::registry::insert(convertible, construct, id);
173 void enum_base::add_value(char const* name_, long value)
175 // Convert name to Python string
176 object name(name_);
178 // Create a new enum instance by calling the class with a value
179 object x = (*this)(value);
181 // Store the object in the enum class
182 (*this).attr(name_) = x;
184 dict d = extract<dict>(this->attr("values"))();
185 d[value] = x;
187 // Set the name field in the new enum instanec
188 enum_object* p = downcast<enum_object>(x.ptr());
189 Py_XDECREF(p->name);
190 p->name = incref(name.ptr());
193 void enum_base::export_values()
195 dict d = extract<dict>(this->attr("values"))();
196 list values = d.values();
197 scope current;
199 for (unsigned i = 0, max = len(values); i < max; ++i)
201 api::setattr(current, object(values[i].attr("name")), values[i]);
205 PyObject* enum_base::to_python(PyTypeObject* type_, long x)
207 object type((type_handle(borrowed(type_))));
209 dict d = extract<dict>(type.attr("values"))();
210 object v = d.get(x, object());
211 return incref(
212 (v == object() ? type(x) : v).ptr());
215 }}} // namespace boost::python::object