]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/python/src/object/enum.cpp
add subtree-ish sources for 12.0.3
[ceph.git] / ceph / src / boost / libs / python / src / object / enum.cpp
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 #if PY_VERSION_HEX >= 0x03000000
22 PyLongObject base_object;
23 #else
24 PyIntObject base_object;
25 #endif
26 PyObject* name;
27 };
28
29 static PyMemberDef enum_members[] = {
30 {const_cast<char*>("name"), T_OBJECT_EX, offsetof(enum_object,name),READONLY, 0},
31 {0, 0, 0, 0, 0}
32 };
33
34
35 extern "C"
36 {
37 static PyObject* enum_repr(PyObject* self_)
38 {
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_);
43 if (!self->name)
44 {
45 return
46 #if PY_VERSION_HEX >= 0x03000000
47 PyUnicode_FromFormat("%S.%s(%ld)", mod, self_->ob_type->tp_name, PyLong_AsLong(self_));
48 #else
49 PyString_FromFormat("%s.%s(%ld)", PyString_AsString(mod), self_->ob_type->tp_name, PyInt_AS_LONG(self_));
50 #endif
51 }
52 else
53 {
54 PyObject* name = self->name;
55 if (name == 0)
56 return 0;
57
58 return
59 #if PY_VERSION_HEX >= 0x03000000
60 PyUnicode_FromFormat("%S.%s.%S", mod, self_->ob_type->tp_name, name);
61 #else
62 PyString_FromFormat("%s.%s.%s",
63 PyString_AsString(mod), self_->ob_type->tp_name, PyString_AsString(name));
64 #endif
65 }
66 }
67
68 static PyObject* enum_str(PyObject* self_)
69 {
70 enum_object* self = downcast<enum_object>(self_);
71 if (!self->name)
72 {
73 #if PY_VERSION_HEX >= 0x03000000
74 return PyLong_Type.tp_str(self_);
75 #else
76 return PyInt_Type.tp_str(self_);
77 #endif
78 }
79 else
80 {
81 return incref(self->name);
82 }
83 }
84 }
85
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 */
90 0, /* tp_itemsize */
91 0, /* tp_dealloc */
92 0, /* tp_print */
93 0, /* tp_getattr */
94 0, /* tp_setattr */
95 0, /* tp_compare */
96 enum_repr, /* tp_repr */
97 0, /* tp_as_number */
98 0, /* tp_as_sequence */
99 0, /* tp_as_mapping */
100 0, /* tp_hash */
101 0, /* tp_call */
102 enum_str, /* tp_str */
103 0, /* tp_getattro */
104 0, /* tp_setattro */
105 0, /* tp_as_buffer */
106 Py_TPFLAGS_DEFAULT
107 #if PY_VERSION_HEX < 0x03000000
108 | Py_TPFLAGS_CHECKTYPES
109 #endif
110 | Py_TPFLAGS_HAVE_GC
111 | Py_TPFLAGS_BASETYPE, /* tp_flags */
112 0, /* tp_doc */
113 0, /* tp_traverse */
114 0, /* tp_clear */
115 0, /* tp_richcompare */
116 0, /* tp_weaklistoffset */
117 0, /* tp_iter */
118 0, /* tp_iternext */
119 0, /* tp_methods */
120 enum_members, /* tp_members */
121 0, /* tp_getset */
122 0, //&PyInt_Type, /* tp_base */
123 0, /* tp_dict */
124 0, /* tp_descr_get */
125 0, /* tp_descr_set */
126 0, /* tp_dictoffset */
127 0, /* tp_init */
128 0, /* tp_alloc */
129 0, /* tp_new */
130 0, /* tp_free */
131 0, /* tp_is_gc */
132 0, /* tp_bases */
133 0, /* tp_mro */
134 0, /* tp_cache */
135 0, /* tp_subclasses */
136 0, /* tp_weaklist */
137 #if PYTHON_API_VERSION >= 1012
138 0 /* tp_del */
139 #endif
140 };
141
142 object module_prefix();
143
144 namespace
145 {
146 object new_enum_type(char const* name, char const *doc)
147 {
148 if (enum_type_object.tp_dict == 0)
149 {
150 Py_TYPE(&enum_type_object) = incref(&PyType_Type);
151 #if PY_VERSION_HEX >= 0x03000000
152 enum_type_object.tp_base = &PyLong_Type;
153 #else
154 enum_type_object.tp_base = &PyInt_Type;
155 #endif
156 if (PyType_Ready(&enum_type_object))
157 throw_error_already_set();
158 }
159
160 type_handle metatype(borrowed(&PyType_Type));
161 type_handle base(borrowed(&enum_type_object));
162
163 // suppress the instance __dict__ in these enum objects. There
164 // may be a slicker way, but this'll do for now.
165 dict d;
166 d["__slots__"] = tuple();
167 d["values"] = dict();
168 d["names"] = dict();
169
170 object module_name = module_prefix();
171 if (module_name)
172 d["__module__"] = module_name;
173 if (doc)
174 d["__doc__"] = doc;
175
176 object result = (object(metatype))(name, make_tuple(base), d);
177
178 scope().attr(name) = result;
179
180 return result;
181 }
182 }
183
184 enum_base::enum_base(
185 char const* name
186 , converter::to_python_function_t to_python
187 , converter::convertible_function convertible
188 , converter::constructor_function construct
189 , type_info id
190 , char const *doc
191 )
192 : object(new_enum_type(name, doc))
193 {
194 converter::registration& converters
195 = const_cast<converter::registration&>(
196 converter::registry::lookup(id));
197
198 converters.m_class_object = downcast<PyTypeObject>(this->ptr());
199 converter::registry::insert(to_python, id);
200 converter::registry::insert(convertible, construct, id);
201 }
202
203 void enum_base::add_value(char const* name_, long value)
204 {
205 // Convert name to Python string
206 object name(name_);
207
208 // Create a new enum instance by calling the class with a value
209 object x = (*this)(value);
210
211 // Store the object in the enum class
212 (*this).attr(name_) = x;
213
214 dict d = extract<dict>(this->attr("values"))();
215 d[value] = x;
216
217 // Set the name field in the new enum instanec
218 enum_object* p = downcast<enum_object>(x.ptr());
219 Py_XDECREF(p->name);
220 p->name = incref(name.ptr());
221
222 dict names_dict = extract<dict>(this->attr("names"))();
223 names_dict[x.attr("name")] = x;
224 }
225
226 void enum_base::export_values()
227 {
228 dict d = extract<dict>(this->attr("names"))();
229 list items = d.items();
230 scope current;
231
232 for (unsigned i = 0, max = len(items); i < max; ++i)
233 api::setattr(current, items[i][0], items[i][1]);
234 }
235
236 PyObject* enum_base::to_python(PyTypeObject* type_, long x)
237 {
238 object type((type_handle(borrowed(type_))));
239
240 dict d = extract<dict>(type.attr("values"))();
241 object v = d.get(x, object());
242 return incref(
243 (v == object() ? type(x) : v).ptr());
244 }
245
246 }}} // namespace boost::python::object