Skip to content

Commit ee1cc99

Browse files
committed
Added support for enums
[SVN r15223]
1 parent dcf7e7c commit ee1cc99

1 file changed

Lines changed: 206 additions & 0 deletions

File tree

src/object/enum.cpp

Lines changed: 206 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,206 @@
1+
// Copyright David Abrahams 2002. Permission to copy, use,
2+
// modify, sell and distribute this software is granted provided this
3+
// copyright notice appears in all copies. This software is provided
4+
// "as is" without express or implied warranty, and with no claim as
5+
// to its suitability for any purpose.
6+
7+
#include <boost/python/object/enum_base.hpp>
8+
#include <boost/python/cast.hpp>
9+
#include <boost/python/scope.hpp>
10+
#include <boost/python/object.hpp>
11+
#include <boost/python/tuple.hpp>
12+
#include <boost/python/dict.hpp>
13+
#include <boost/python/str.hpp>
14+
#include <boost/python/extract.hpp>
15+
#include <structmember.h>
16+
#include <cstdio>
17+
18+
namespace boost { namespace python { namespace objects {
19+
20+
struct enum_object
21+
{
22+
PyIntObject base_object;
23+
PyObject* name;
24+
};
25+
26+
static PyMemberDef enum_members[] = {
27+
{"name", T_OBJECT_EX, offsetof(enum_object,name),READONLY},
28+
{0}
29+
};
30+
31+
32+
extern "C" {
33+
static int
34+
enum_print(PyObject *v, std::FILE *fp, int flags)
35+
{
36+
PyObject* s
37+
= (flags & Py_PRINT_RAW) ? v->ob_type->tp_str(v) : v->ob_type->tp_repr(v);
38+
if (s == 0)
39+
return -1;
40+
41+
char const* text = PyString_AsString(s);
42+
if (text == 0)
43+
return -1;
44+
45+
std::fprintf(fp, text);
46+
return 0;
47+
}
48+
49+
/* flags -- not used but required by interface */
50+
static PyObject* enum_repr(PyObject* self_)
51+
{
52+
enum_object* self = downcast<enum_object>(self_);
53+
if (!self->name)
54+
{
55+
return PyString_FromFormat("%s(%ld)", self_->ob_type->tp_name, PyInt_AS_LONG(self_));
56+
}
57+
else
58+
{
59+
char* name = PyString_AsString(self->name);
60+
if (name == 0)
61+
return 0;
62+
63+
return PyString_FromFormat("%s.%s", self_->ob_type->tp_name, name);
64+
}
65+
}
66+
67+
static PyObject* enum_str(PyObject* self_)
68+
{
69+
enum_object* self = downcast<enum_object>(self_);
70+
if (!self->name)
71+
{
72+
return PyInt_Type.tp_str(self_);
73+
}
74+
else
75+
{
76+
return incref(self->name);
77+
}
78+
}
79+
}
80+
81+
static PyTypeObject enum_type_object = {
82+
PyObject_HEAD_INIT(0) // &PyType_Type
83+
0,
84+
"Boost.Python.enum",
85+
sizeof(enum_object), /* tp_basicsize */
86+
0, /* tp_itemsize */
87+
0, /* tp_dealloc */
88+
enum_print, /* tp_print */
89+
0, /* tp_getattr */
90+
0, /* tp_setattr */
91+
0, /* tp_compare */
92+
enum_repr, /* tp_repr */
93+
0, /* tp_as_number */
94+
0, /* tp_as_sequence */
95+
0, /* tp_as_mapping */
96+
0, /* tp_hash */
97+
0, /* tp_call */
98+
enum_str, /* tp_str */
99+
0, /* tp_getattro */
100+
0, /* tp_setattro */
101+
0, /* tp_as_buffer */
102+
Py_TPFLAGS_DEFAULT
103+
| Py_TPFLAGS_CHECKTYPES
104+
| Py_TPFLAGS_HAVE_GC
105+
| Py_TPFLAGS_BASETYPE, /* tp_flags */
106+
0, /* tp_doc */
107+
0, /* tp_traverse */
108+
0, /* tp_clear */
109+
0, /* tp_richcompare */
110+
0, /* tp_weaklistoffset */
111+
0, /* tp_iter */
112+
0, /* tp_iternext */
113+
0, /* tp_methods */
114+
enum_members, /* tp_members */
115+
0, /* tp_getset */
116+
0, //&PyInt_Type, /* tp_base */
117+
0, /* tp_dict */
118+
0, /* tp_descr_get */
119+
0, /* tp_descr_set */
120+
0, /* tp_dictoffset */
121+
0, /* tp_init */
122+
0, /* tp_alloc */
123+
0 /* tp_new */
124+
};
125+
126+
object module_prefix();
127+
128+
namespace
129+
{
130+
object new_enum_type(char const* name)
131+
{
132+
if (enum_type_object.tp_dict == 0)
133+
{
134+
enum_type_object.ob_type = incref(&PyType_Type);
135+
enum_type_object.tp_base = &PyInt_Type;
136+
if (PyType_Ready(&enum_type_object))
137+
throw_error_already_set();
138+
}
139+
140+
type_handle metatype(borrowed(&PyType_Type));
141+
type_handle base(borrowed(&enum_type_object));
142+
143+
// suppress the instance __dict__ in these enum objects. There
144+
// may be a slicker way, but this'll do for now.
145+
dict d;
146+
d["__slots__"] = tuple();
147+
d["values"] = dict();
148+
149+
object result = (object(metatype))(
150+
module_prefix() + name, make_tuple(base), d);
151+
152+
scope().attr(name) = result;
153+
154+
return result;
155+
}
156+
}
157+
158+
enum_base::enum_base(
159+
char const* name
160+
, converter::to_python_function_t to_python
161+
, converter::convertible_function convertible
162+
, converter::constructor_function construct
163+
, type_info id
164+
)
165+
: object(new_enum_type(name))
166+
{
167+
converter::registration& converters
168+
= const_cast<converter::registration&>(
169+
converter::registry::lookup(id));
170+
171+
converters.class_object = downcast<PyTypeObject>(this->ptr());
172+
converter::registry::insert(to_python, id);
173+
converter::registry::insert(convertible, construct, id);
174+
}
175+
176+
void enum_base::add_value(char const* name_, long value)
177+
{
178+
// Convert name to Python string
179+
object name(name_);
180+
181+
// Create a new enum instance by calling the class with a value
182+
object x = (*this)(value);
183+
184+
// Store the object in the enum class
185+
(*this).attr(name_) = x;
186+
187+
dict d = extract<dict>(this->attr("values"))();
188+
d[value] = x;
189+
190+
// Set the name field in the new enum instanec
191+
enum_object* p = downcast<enum_object>(x.ptr());
192+
Py_XDECREF(p->name);
193+
p->name = incref(name.ptr());
194+
}
195+
196+
PyObject* enum_base::to_python(PyTypeObject* type_, long x)
197+
{
198+
object type(type_handle(borrowed(type_)));
199+
200+
dict d = extract<dict>(type.attr("values"))();
201+
object v = d.get(x, object());
202+
return incref(
203+
(v == object() ? type(x) : v).ptr());
204+
}
205+
206+
}}} // namespace boost::python::object

0 commit comments

Comments
 (0)