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