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) |
---|
5 | |
---|
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> |
---|
16 | |
---|
17 | namespace boost { namespace python { namespace objects { |
---|
18 | |
---|
19 | struct enum_object |
---|
20 | { |
---|
21 | PyIntObject base_object; |
---|
22 | PyObject* name; |
---|
23 | }; |
---|
24 | |
---|
25 | static PyMemberDef enum_members[] = { |
---|
26 | {"name", T_OBJECT_EX, offsetof(enum_object,name),READONLY, 0}, |
---|
27 | {0, 0, 0, 0, 0} |
---|
28 | }; |
---|
29 | |
---|
30 | |
---|
31 | extern "C" |
---|
32 | { |
---|
33 | static PyObject* enum_repr(PyObject* self_) |
---|
34 | { |
---|
35 | enum_object* self = downcast<enum_object>(self_); |
---|
36 | if (!self->name) |
---|
37 | { |
---|
38 | return PyString_FromFormat("%s(%ld)", self_->ob_type->tp_name, PyInt_AS_LONG(self_)); |
---|
39 | } |
---|
40 | else |
---|
41 | { |
---|
42 | char* name = PyString_AsString(self->name); |
---|
43 | if (name == 0) |
---|
44 | return 0; |
---|
45 | |
---|
46 | return PyString_FromFormat("%s.%s", self_->ob_type->tp_name, name); |
---|
47 | } |
---|
48 | } |
---|
49 | |
---|
50 | static PyObject* enum_str(PyObject* self_) |
---|
51 | { |
---|
52 | enum_object* self = downcast<enum_object>(self_); |
---|
53 | if (!self->name) |
---|
54 | { |
---|
55 | return PyInt_Type.tp_str(self_); |
---|
56 | } |
---|
57 | else |
---|
58 | { |
---|
59 | return incref(self->name); |
---|
60 | } |
---|
61 | } |
---|
62 | } |
---|
63 | |
---|
64 | static PyTypeObject enum_type_object = { |
---|
65 | PyObject_HEAD_INIT(0) // &PyType_Type |
---|
66 | 0, |
---|
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 |
---|
117 | }; |
---|
118 | |
---|
119 | object module_prefix(); |
---|
120 | |
---|
121 | namespace |
---|
122 | { |
---|
123 | object new_enum_type(char const* name) |
---|
124 | { |
---|
125 | if (enum_type_object.tp_dict == 0) |
---|
126 | { |
---|
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(); |
---|
131 | } |
---|
132 | |
---|
133 | type_handle metatype(borrowed(&PyType_Type)); |
---|
134 | type_handle base(borrowed(&enum_type_object)); |
---|
135 | |
---|
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(); |
---|
141 | |
---|
142 | object module_name = module_prefix(); |
---|
143 | if (module_name) |
---|
144 | module_name += '.'; |
---|
145 | |
---|
146 | object result = (object(metatype))( |
---|
147 | module_name + name, make_tuple(base), d); |
---|
148 | |
---|
149 | scope().attr(name) = result; |
---|
150 | |
---|
151 | return result; |
---|
152 | } |
---|
153 | } |
---|
154 | |
---|
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 |
---|
161 | ) |
---|
162 | : object(new_enum_type(name)) |
---|
163 | { |
---|
164 | converter::registration& converters |
---|
165 | = const_cast<converter::registration&>( |
---|
166 | converter::registry::lookup(id)); |
---|
167 | |
---|
168 | converters.m_class_object = downcast<PyTypeObject>(this->ptr()); |
---|
169 | converter::registry::insert(to_python, id); |
---|
170 | converter::registry::insert(convertible, construct, id); |
---|
171 | } |
---|
172 | |
---|
173 | void enum_base::add_value(char const* name_, long value) |
---|
174 | { |
---|
175 | // Convert name to Python string |
---|
176 | object name(name_); |
---|
177 | |
---|
178 | // Create a new enum instance by calling the class with a value |
---|
179 | object x = (*this)(value); |
---|
180 | |
---|
181 | // Store the object in the enum class |
---|
182 | (*this).attr(name_) = x; |
---|
183 | |
---|
184 | dict d = extract<dict>(this->attr("values"))(); |
---|
185 | d[value] = x; |
---|
186 | |
---|
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()); |
---|
191 | } |
---|
192 | |
---|
193 | void enum_base::export_values() |
---|
194 | { |
---|
195 | dict d = extract<dict>(this->attr("values"))(); |
---|
196 | list values = d.values(); |
---|
197 | scope current; |
---|
198 | |
---|
199 | for (unsigned i = 0, max = len(values); i < max; ++i) |
---|
200 | { |
---|
201 | api::setattr(current, object(values[i].attr("name")), values[i]); |
---|
202 | } |
---|
203 | } |
---|
204 | |
---|
205 | PyObject* enum_base::to_python(PyTypeObject* type_, long x) |
---|
206 | { |
---|
207 | object type((type_handle(borrowed(type_)))); |
---|
208 | |
---|
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()); |
---|
213 | } |
---|
214 | |
---|
215 | }}} // namespace boost::python::object |
---|