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 PyIntObject base_object
;
25 static PyMemberDef enum_members
[] = {
26 {"name", T_OBJECT_EX
, offsetof(enum_object
,name
),READONLY
, 0},
33 static PyObject
* enum_repr(PyObject
* self_
)
35 enum_object
* self
= downcast
<enum_object
>(self_
);
38 return PyString_FromFormat("%s(%ld)", self_
->ob_type
->tp_name
, PyInt_AS_LONG(self_
));
42 char* name
= PyString_AsString(self
->name
);
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_
);
55 return PyInt_Type
.tp_str(self_
);
59 return incref(self
->name
);
64 static PyTypeObject enum_type_object
= {
65 PyObject_HEAD_INIT(0) // &PyType_Type
68 sizeof(enum_object
), /* tp_basicsize */
75 enum_repr
, /* tp_repr */
77 0, /* tp_as_sequence */
78 0, /* tp_as_mapping */
81 enum_str
, /* tp_str */
86 | Py_TPFLAGS_CHECKTYPES
88 | Py_TPFLAGS_BASETYPE
, /* tp_flags */
92 0, /* tp_richcompare */
93 0, /* tp_weaklistoffset */
97 enum_members
, /* tp_members */
99 0, //&PyInt_Type, /* tp_base */
101 0, /* tp_descr_get */
102 0, /* tp_descr_set */
103 0, /* tp_dictoffset */
112 0, /* tp_subclasses */
114 #if PYTHON_API_VERSION >= 1012
119 object
module_prefix();
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.
139 d
["__slots__"] = tuple();
140 d
["values"] = dict();
142 object module_name
= module_prefix();
146 object result
= (object(metatype
))(
147 module_name
+ name
, make_tuple(base
), d
);
149 scope().attr(name
) = result
;
155 enum_base::enum_base(
157 , converter::to_python_function_t to_python
158 , converter::convertible_function convertible
159 , converter::constructor_function construct
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
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"))();
187 // Set the name field in the new enum instanec
188 enum_object
* p
= downcast
<enum_object
>(x
.ptr());
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();
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());
212 (v
== object() ? type(x
) : v
).ptr());
215 }}} // namespace boost::python::object