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
{
21 #if PY_VERSION_HEX >= 0x03000000
22 PyLongObject base_object
;
24 PyIntObject base_object
;
29 static PyMemberDef enum_members
[] = {
30 {const_cast<char*>("name"), T_OBJECT_EX
, offsetof(enum_object
,name
),READONLY
, 0},
38 enum_dealloc(enum_object
* self
)
40 Py_XDECREF(self
->name
);
41 Py_TYPE(self
)->tp_free((PyObject
*)self
);
44 static PyObject
* enum_repr(PyObject
* self_
)
46 PyObject
*mod
= PyObject_GetAttrString( self_
, "__module__");
47 object
auto_free(handle
<>(mod
));
48 enum_object
* self
= downcast
<enum_object
>(self_
);
52 #if PY_VERSION_HEX >= 0x03000000
53 PyUnicode_FromFormat("%S.%s(%ld)", mod
, self_
->ob_type
->tp_name
, PyLong_AsLong(self_
));
55 PyString_FromFormat("%s.%s(%ld)", PyString_AsString(mod
), self_
->ob_type
->tp_name
, PyInt_AS_LONG(self_
));
60 PyObject
* name
= self
->name
;
65 #if PY_VERSION_HEX >= 0x03000000
66 PyUnicode_FromFormat("%S.%s.%S", mod
, self_
->ob_type
->tp_name
, name
);
68 PyString_FromFormat("%s.%s.%s",
69 PyString_AsString(mod
), self_
->ob_type
->tp_name
, PyString_AsString(name
));
74 static PyObject
* enum_str(PyObject
* self_
)
76 enum_object
* self
= downcast
<enum_object
>(self_
);
79 #if PY_VERSION_HEX >= 0x03000000
80 return PyLong_Type
.tp_str(self_
);
82 return PyInt_Type
.tp_str(self_
);
87 return incref(self
->name
);
92 static PyTypeObject enum_type_object
= {
93 PyVarObject_HEAD_INIT(NULL
, 0) // &PyType_Type
94 const_cast<char*>("Boost.Python.enum"),
95 sizeof(enum_object
), /* tp_basicsize */
97 (destructor
) enum_dealloc
, /* tp_dealloc */
102 enum_repr
, /* tp_repr */
103 0, /* tp_as_number */
104 0, /* tp_as_sequence */
105 0, /* tp_as_mapping */
108 enum_str
, /* tp_str */
111 0, /* tp_as_buffer */
113 #if PY_VERSION_HEX < 0x03000000
114 | Py_TPFLAGS_CHECKTYPES
117 | Py_TPFLAGS_BASETYPE
, /* tp_flags */
121 0, /* tp_richcompare */
122 0, /* tp_weaklistoffset */
126 enum_members
, /* tp_members */
128 0, //&PyInt_Type, /* tp_base */
130 0, /* tp_descr_get */
131 0, /* tp_descr_set */
132 0, /* tp_dictoffset */
141 0, /* tp_subclasses */
143 #if PYTHON_API_VERSION >= 1012
148 object
module_prefix();
152 object
new_enum_type(char const* name
, char const *doc
)
154 if (enum_type_object
.tp_dict
== 0)
156 Py_TYPE(&enum_type_object
) = incref(&PyType_Type
);
157 #if PY_VERSION_HEX >= 0x03000000
158 enum_type_object
.tp_base
= &PyLong_Type
;
160 enum_type_object
.tp_base
= &PyInt_Type
;
162 if (PyType_Ready(&enum_type_object
))
163 throw_error_already_set();
166 type_handle
metatype(borrowed(&PyType_Type
));
167 type_handle
base(borrowed(&enum_type_object
));
169 // suppress the instance __dict__ in these enum objects. There
170 // may be a slicker way, but this'll do for now.
172 d
["__slots__"] = tuple();
173 d
["values"] = dict();
176 object module_name
= module_prefix();
178 d
["__module__"] = module_name
;
182 object result
= (object(metatype
))(name
, make_tuple(base
), d
);
184 scope().attr(name
) = result
;
190 enum_base::enum_base(
192 , converter::to_python_function_t to_python
193 , converter::convertible_function convertible
194 , converter::constructor_function construct
198 : object(new_enum_type(name
, doc
))
200 converter::registration
& converters
201 = const_cast<converter::registration
&>(
202 converter::registry::lookup(id
));
204 converters
.m_class_object
= downcast
<PyTypeObject
>(this->ptr());
205 converter::registry::insert(to_python
, id
);
206 converter::registry::insert(convertible
, construct
, id
);
209 void enum_base::add_value(char const* name_
, long value
)
211 // Convert name to Python string
214 // Create a new enum instance by calling the class with a value
215 object x
= (*this)(value
);
217 // Store the object in the enum class
218 (*this).attr(name_
) = x
;
220 dict d
= extract
<dict
>(this->attr("values"))();
223 // Set the name field in the new enum instanec
224 enum_object
* p
= downcast
<enum_object
>(x
.ptr());
226 p
->name
= incref(name
.ptr());
228 dict names_dict
= extract
<dict
>(this->attr("names"))();
229 names_dict
[x
.attr("name")] = x
;
232 void enum_base::export_values()
234 dict d
= extract
<dict
>(this->attr("names"))();
235 list items
= d
.items();
238 for (unsigned i
= 0, max
= len(items
); i
< max
; ++i
)
239 api::setattr(current
, items
[i
][0], items
[i
][1]);
242 PyObject
* enum_base::to_python(PyTypeObject
* type_
, long x
)
244 object
type((type_handle(borrowed(type_
))));
246 dict d
= extract
<dict
>(type
.attr("values"))();
247 object v
= d
.get(x
, object());
249 (v
== object() ? type(x
) : v
).ptr());
252 }}} // namespace boost::python::object