Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/boost_1_33_1/libs/python/src/object/enum.cpp @ 12

Last change on this file since 12 was 12, checked in by landauf, 18 years ago

added boost

File size: 7.0 KB
Line 
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 <boost/python/detail/api_placeholder.hpp>
16#include <structmember.h>
17#include <cstdio>
18
19namespace boost { namespace python { namespace objects { 
20
21struct enum_object
22{
23    PyIntObject base_object;
24    PyObject* name;
25};
26
27static PyMemberDef enum_members[] = {
28    {"name", T_OBJECT_EX, offsetof(enum_object,name),READONLY},
29    {0}
30};
31
32
33extern "C"
34{
35    static int
36    enum_print(PyObject *v, BOOST_CSTD_::FILE *fp, int flags)
37    {
38        PyObject* s
39            = (flags & Py_PRINT_RAW) ? v->ob_type->tp_str(v) : v->ob_type->tp_repr(v);
40        if (s == 0)
41            return -1;
42       
43        char const* text = PyString_AsString(s);
44        if (text == 0)
45            return -1;
46       
47        BOOST_CSTD_::fprintf(fp, text);
48        return 0;
49    }
50   
51     /* flags -- not used but required by interface */
52    static PyObject* enum_repr(PyObject* self_)
53    {
54        enum_object* self = downcast<enum_object>(self_);
55        if (!self->name)
56        {
57            return PyString_FromFormat("%s(%ld)", self_->ob_type->tp_name, PyInt_AS_LONG(self_));
58        }
59        else
60        {
61            char* name = PyString_AsString(self->name);
62            if (name == 0)
63                return 0;
64           
65            return PyString_FromFormat("%s.%s", self_->ob_type->tp_name, name);
66        }
67    }
68
69    static PyObject* enum_str(PyObject* self_)
70    {
71        enum_object* self = downcast<enum_object>(self_);
72        if (!self->name)
73        {
74            return PyInt_Type.tp_str(self_);
75        }
76        else
77        {
78            return incref(self->name);
79        }
80    }
81}
82
83static PyTypeObject enum_type_object = {
84    PyObject_HEAD_INIT(0) // &PyType_Type
85    0,
86    "Boost.Python.enum",
87    sizeof(enum_object),                    /* tp_basicsize */
88    0,                                      /* tp_itemsize */
89    0,                                      /* tp_dealloc */
90    enum_print,                             /* tp_print */
91    0,                                      /* tp_getattr */
92    0,                                      /* tp_setattr */
93    0,                                      /* tp_compare */
94    enum_repr,                              /* tp_repr */
95    0,                                      /* tp_as_number */
96    0,                                      /* tp_as_sequence */
97    0,                                      /* tp_as_mapping */
98    0,                                      /* tp_hash */
99    0,                                      /* tp_call */
100    enum_str,                               /* tp_str */
101    0,                                      /* tp_getattro */
102    0,                                      /* tp_setattro */
103    0,                                      /* tp_as_buffer */
104    Py_TPFLAGS_DEFAULT
105    | Py_TPFLAGS_CHECKTYPES
106    | Py_TPFLAGS_HAVE_GC
107    | Py_TPFLAGS_BASETYPE,                  /* tp_flags */
108    0,                                      /* tp_doc */
109    0,                                      /* tp_traverse */
110    0,                                      /* tp_clear */
111    0,                                      /* tp_richcompare */
112    0,                                      /* tp_weaklistoffset */
113    0,                                      /* tp_iter */
114    0,                                      /* tp_iternext */
115    0,                                      /* tp_methods */
116    enum_members,                           /* tp_members */
117    0,                                      /* tp_getset */
118    0, //&PyInt_Type,                       /* tp_base */
119    0,                                      /* tp_dict */
120    0,                                      /* tp_descr_get */
121    0,                                      /* tp_descr_set */
122    0,                                      /* tp_dictoffset */
123    0,                                      /* tp_init */
124    0,                                      /* tp_alloc */
125    0                                       /* tp_new */
126};
127
128object module_prefix();
129
130namespace
131{
132  object new_enum_type(char const* name)
133  {
134      if (enum_type_object.tp_dict == 0)
135      {
136          enum_type_object.ob_type = incref(&PyType_Type);
137          enum_type_object.tp_base = &PyInt_Type;
138          if (PyType_Ready(&enum_type_object))
139              throw_error_already_set();
140      }
141
142      type_handle metatype(borrowed(&PyType_Type));
143      type_handle base(borrowed(&enum_type_object));
144
145      // suppress the instance __dict__ in these enum objects. There
146      // may be a slicker way, but this'll do for now.
147      dict d;
148      d["__slots__"] = tuple();
149      d["values"] = dict();
150
151      object module_name = module_prefix();
152      if (module_name)
153          module_name += '.';
154     
155      object result = (object(metatype))(
156          module_name + name, make_tuple(base), d);
157     
158      scope().attr(name) = result;
159
160      return result;
161  }
162}
163
164enum_base::enum_base(
165    char const* name
166    , converter::to_python_function_t to_python
167    , converter::convertible_function convertible
168    , converter::constructor_function construct
169    , type_info id
170    )
171    : object(new_enum_type(name))
172{
173    converter::registration& converters
174        = const_cast<converter::registration&>(
175            converter::registry::lookup(id));
176           
177    converters.m_class_object = downcast<PyTypeObject>(this->ptr());
178    converter::registry::insert(to_python, id);
179    converter::registry::insert(convertible, construct, id);
180}
181
182void enum_base::add_value(char const* name_, long value)
183{
184    // Convert name to Python string
185    object name(name_);
186
187    // Create a new enum instance by calling the class with a value
188    object x = (*this)(value);
189
190    // Store the object in the enum class
191    (*this).attr(name_) = x;
192
193    dict d = extract<dict>(this->attr("values"))();
194    d[value] = x;
195   
196    // Set the name field in the new enum instanec
197    enum_object* p = downcast<enum_object>(x.ptr());
198    Py_XDECREF(p->name);
199    p->name = incref(name.ptr());
200}
201
202void enum_base::export_values()
203{
204    dict d = extract<dict>(this->attr("values"))();
205    list values = d.values();
206    scope current;
207   
208    for (unsigned i = 0, max = len(values); i < max; ++i)
209    {
210        api::setattr(current, object(values[i].attr("name")), values[i]);
211    }
212 }
213
214PyObject* enum_base::to_python(PyTypeObject* type_, long x)
215{
216    object type((type_handle(borrowed(type_))));
217
218    dict d = extract<dict>(type.attr("values"))();
219    object v = d.get(x, object());
220    return incref(
221        (v == object() ? type(x) : v).ptr());
222}
223
224}}} // namespace boost::python::object
Note: See TracBrowser for help on using the repository browser.