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_protocol.hpp>
7 #include <boost/python/errors.hpp>
8 #include <boost/python/object.hpp>
9 #include <boost/python/ssize_t.hpp>
10 
11 namespace boost { namespace python { namespace api {
12 
getattr(object const & target,object const & key)13 BOOST_PYTHON_DECL object getattr(object const& target, object const& key)
14 {
15     return object(detail::new_reference(PyObject_GetAttr(target.ptr(), key.ptr())));
16 }
17 
getattr(object const & target,object const & key,object const & default_)18 BOOST_PYTHON_DECL object getattr(object const& target, object const& key, object const& default_)
19 {
20     PyObject* result = PyObject_GetAttr(target.ptr(), key.ptr());
21     if (result == NULL && PyErr_ExceptionMatches(PyExc_AttributeError))
22     {
23         PyErr_Clear();
24         return default_;
25     }
26     return object(detail::new_reference(result));
27 }
28 
setattr(object const & target,object const & key,object const & value)29 BOOST_PYTHON_DECL void setattr(object const& target, object const& key, object const& value)
30 {
31     if (PyObject_SetAttr(target.ptr(), key.ptr(), value.ptr()) == -1)
32         throw_error_already_set();
33 }
34 
delattr(object const & target,object const & key)35 BOOST_PYTHON_DECL void delattr(object const& target, object const& key)
36 {
37     if (PyObject_DelAttr(target.ptr(), key.ptr()) == -1)
38         throw_error_already_set();
39 }
40 
getattr(object const & target,char const * key)41 BOOST_PYTHON_DECL object getattr(object const& target, char const* key)
42 {
43     return object(
44         detail::new_reference(
45             PyObject_GetAttrString(target.ptr(), const_cast<char*>(key))
46         ));
47 }
48 
getattr(object const & target,char const * key,object const & default_)49 BOOST_PYTHON_DECL object getattr(object const& target, char const* key, object const& default_)
50 {
51     PyObject* result = PyObject_GetAttrString(target.ptr(), const_cast<char*>(key));
52     if (result == NULL && PyErr_ExceptionMatches(PyExc_AttributeError))
53     {
54         PyErr_Clear();
55         return default_;
56     }
57     return object(detail::new_reference(result));
58 
59 }
setattr(object const & target,char const * key,object const & value)60 BOOST_PYTHON_DECL void setattr(object const& target, char const* key, object const& value)
61 {
62     if (PyObject_SetAttrString(
63             target.ptr(), const_cast<char*>(key), value.ptr()) == -1
64         )
65     {
66         throw_error_already_set();
67     }
68 }
69 
delattr(object const & target,char const * key)70 BOOST_PYTHON_DECL void delattr(object const& target, char const* key)
71 {
72     if (PyObject_DelAttrString(
73             target.ptr(), const_cast<char*>(key)) == -1
74         )
75     {
76         throw_error_already_set();
77     }
78 }
79 
getitem(object const & target,object const & key)80 BOOST_PYTHON_DECL object getitem(object const& target, object const& key)
81 {
82     return object(detail::new_reference(
83                       PyObject_GetItem(target.ptr(), key.ptr())));
84 }
85 
setitem(object const & target,object const & key,object const & value)86 BOOST_PYTHON_DECL void setitem(object const& target, object const& key, object const& value)
87 {
88     if (PyObject_SetItem(target.ptr(), key.ptr(), value.ptr()) == -1)
89         throw_error_already_set();
90 }
91 
delitem(object const & target,object const & key)92 BOOST_PYTHON_DECL void delitem(object const& target, object const& key)
93 {
94     if (PyObject_DelItem(target.ptr(), key.ptr()) == -1)
95         throw_error_already_set();
96 }
97 
98 namespace // slicing code copied directly out of the Python implementation
99 {
100   #undef ISINT
101   #define ISINT(x) ((x) == NULL || PyInt_Check(x) || PyLong_Check(x))
102 
103   static PyObject *
apply_slice(PyObject * u,PyObject * v,PyObject * w)104   apply_slice(PyObject *u, PyObject *v, PyObject *w) /* return u[v:w] */
105   {
106 #if PY_VERSION_HEX < 0x03000000
107       PyTypeObject *tp = u->ob_type;
108       PySequenceMethods *sq = tp->tp_as_sequence;
109 
110       if (sq && sq->sq_slice && ISINT(v) && ISINT(w)) {
111           ssize_t ilow = 0, ihigh = ssize_t_max;
112           if (!_PyEval_SliceIndex(v, &ilow))
113               return NULL;
114           if (!_PyEval_SliceIndex(w, &ihigh))
115               return NULL;
116           return PySequence_GetSlice(u, ilow, ihigh);
117       }
118       else
119 #endif
120       {
121           PyObject *slice = PySlice_New(v, w, NULL);
122           if (slice != NULL) {
123               PyObject *res = PyObject_GetItem(u, slice);
124               Py_DECREF(slice);
125               return res;
126           }
127           else
128               return NULL;
129       }
130   }
131 
132   static int
assign_slice(PyObject * u,PyObject * v,PyObject * w,PyObject * x)133   assign_slice(PyObject *u, PyObject *v, PyObject *w, PyObject *x)
134       /* u[v:w] = x */
135   {
136 #if PY_VERSION_HEX < 0x03000000
137       PyTypeObject *tp = u->ob_type;
138       PySequenceMethods *sq = tp->tp_as_sequence;
139 
140       if (sq && sq->sq_slice && ISINT(v) && ISINT(w)) {
141           ssize_t ilow = 0, ihigh = ssize_t_max;
142           if (!_PyEval_SliceIndex(v, &ilow))
143               return -1;
144           if (!_PyEval_SliceIndex(w, &ihigh))
145               return -1;
146           if (x == NULL)
147               return PySequence_DelSlice(u, ilow, ihigh);
148           else
149               return PySequence_SetSlice(u, ilow, ihigh, x);
150       }
151       else
152 #endif
153       {
154           PyObject *slice = PySlice_New(v, w, NULL);
155           if (slice != NULL) {
156               int res;
157               if (x != NULL)
158                   res = PyObject_SetItem(u, slice, x);
159               else
160                   res = PyObject_DelItem(u, slice);
161               Py_DECREF(slice);
162               return res;
163           }
164           else
165               return -1;
166       }
167   }
168 }
169 
getslice(object const & target,handle<> const & begin,handle<> const & end)170 BOOST_PYTHON_DECL object getslice(object const& target, handle<> const& begin, handle<> const& end)
171 {
172     return object(
173         detail::new_reference(
174             apply_slice(target.ptr(), begin.get(), end.get())));
175 }
176 
setslice(object const & target,handle<> const & begin,handle<> const & end,object const & value)177 BOOST_PYTHON_DECL void setslice(object const& target, handle<> const& begin, handle<> const& end, object const& value)
178 {
179     if (assign_slice(
180             target.ptr(), begin.get(), end.get(), value.ptr()) == -1
181         )
182     {
183         throw_error_already_set();
184     }
185 }
186 
delslice(object const & target,handle<> const & begin,handle<> const & end)187 BOOST_PYTHON_DECL void delslice(object const& target, handle<> const& begin, handle<> const& end)
188 {
189     if (assign_slice(
190             target.ptr(), begin.get(), end.get(), 0) == -1
191         )
192     {
193         throw_error_already_set();
194     }
195 }
196 
197 }}} // namespace boost::python::api
198