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},
37 static PyObject
* enum_repr(PyObject
* self_
)
39 // XXX(bhy) Potentional memory leak here since PyObject_GetAttrString returns a new reference
40 // const char *mod = PyString_AsString(PyObject_GetAttrString( self_, const_cast<char*>("__module__")));
41 PyObject
*mod
= PyObject_GetAttrString( self_
, "__module__");
42 enum_object
* self
= downcast
<enum_object
>(self_
);
46 #if PY_VERSION_HEX >= 0x03000000
47 PyUnicode_FromFormat("%S.%s(%ld)", mod
, self_
->ob_type
->tp_name
, PyLong_AsLong(self_
));
49 PyString_FromFormat("%s.%s(%ld)", PyString_AsString(mod
), self_
->ob_type
->tp_name
, PyInt_AS_LONG(self_
));
54 PyObject
* name
= self
->name
;
59 #if PY_VERSION_HEX >= 0x03000000
60 PyUnicode_FromFormat("%S.%s.%S", mod
, self_
->ob_type
->tp_name
, name
);
62 PyString_FromFormat("%s.%s.%s",
63 PyString_AsString(mod
), self_
->ob_type
->tp_name
, PyString_AsString(name
));
68 static PyObject
* enum_str(PyObject
* self_
)
70 enum_object
* self
= downcast
<enum_object
>(self_
);
73 #if PY_VERSION_HEX >= 0x03000000
74 return PyLong_Type
.tp_str(self_
);
76 return PyInt_Type
.tp_str(self_
);
81 return incref(self
->name
);
86 static PyTypeObject enum_type_object
= {
87 PyVarObject_HEAD_INIT(NULL
, 0) // &PyType_Type
88 const_cast<char*>("Boost.Python.enum"),
89 sizeof(enum_object
), /* tp_basicsize */
96 enum_repr
, /* tp_repr */
98 0, /* tp_as_sequence */
99 0, /* tp_as_mapping */
102 enum_str
, /* tp_str */
105 0, /* tp_as_buffer */
107 #if PY_VERSION_HEX < 0x03000000
108 | Py_TPFLAGS_CHECKTYPES
111 | Py_TPFLAGS_BASETYPE
, /* tp_flags */
115 0, /* tp_richcompare */
116 0, /* tp_weaklistoffset */
120 enum_members
, /* tp_members */
122 0, //&PyInt_Type, /* tp_base */
124 0, /* tp_descr_get */
125 0, /* tp_descr_set */
126 0, /* tp_dictoffset */
135 0, /* tp_subclasses */
137 #if PYTHON_API_VERSION >= 1012
142 object
module_prefix();
146 object
new_enum_type(char const* name
, char const *doc
)
148 if (enum_type_object
.tp_dict
== 0)
150 Py_TYPE(&enum_type_object
) = incref(&PyType_Type
);
151 #if PY_VERSION_HEX >= 0x03000000
152 enum_type_object
.tp_base
= &PyLong_Type
;
154 enum_type_object
.tp_base
= &PyInt_Type
;
156 if (PyType_Ready(&enum_type_object
))
157 throw_error_already_set();
160 type_handle
metatype(borrowed(&PyType_Type
));
161 type_handle
base(borrowed(&enum_type_object
));
163 // suppress the instance __dict__ in these enum objects. There
164 // may be a slicker way, but this'll do for now.
166 d
["__slots__"] = tuple();
167 d
["values"] = dict();
170 object module_name
= module_prefix();
172 d
["__module__"] = module_name
;
176 object result
= (object(metatype
))(name
, make_tuple(base
), d
);
178 scope().attr(name
) = result
;
184 enum_base::enum_base(
186 , converter::to_python_function_t to_python
187 , converter::convertible_function convertible
188 , converter::constructor_function construct
192 : object(new_enum_type(name
, doc
))
194 converter::registration
& converters
195 = const_cast<converter::registration
&>(
196 converter::registry::lookup(id
));
198 converters
.m_class_object
= downcast
<PyTypeObject
>(this->ptr());
199 converter::registry::insert(to_python
, id
);
200 converter::registry::insert(convertible
, construct
, id
);
203 void enum_base::add_value(char const* name_
, long value
)
205 // Convert name to Python string
208 // Create a new enum instance by calling the class with a value
209 object x
= (*this)(value
);
211 // Store the object in the enum class
212 (*this).attr(name_
) = x
;
214 dict d
= extract
<dict
>(this->attr("values"))();
217 // Set the name field in the new enum instanec
218 enum_object
* p
= downcast
<enum_object
>(x
.ptr());
220 p
->name
= incref(name
.ptr());
222 dict names_dict
= extract
<dict
>(this->attr("names"))();
223 names_dict
[x
.attr("name")] = x
;
226 void enum_base::export_values()
228 dict d
= extract
<dict
>(this->attr("names"))();
229 list items
= d
.items();
232 for (unsigned i
= 0, max
= len(items
); i
< max
; ++i
)
233 api::setattr(current
, items
[i
][0], items
[i
][1]);
236 PyObject
* enum_base::to_python(PyTypeObject
* type_
, long x
)
238 object
type((type_handle(borrowed(type_
))));
240 dict d
= extract
<dict
>(type
.attr("values"))();
241 object v
= d
.get(x
, object());
243 (v
== object() ? type(x
) : v
).ptr());
246 }}} // namespace boost::python::object