Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/boost_1_34_1/boost/python/suite/indexing/indexing_suite.hpp @ 29

Last change on this file since 29 was 29, checked in by landauf, 17 years ago

updated boost from 1_33_1 to 1_34_1

File size: 9.8 KB
Line 
1//  (C) Copyright Joel de Guzman 2003.
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#ifndef INDEXING_SUITE_JDG20036_HPP
7# define INDEXING_SUITE_JDG20036_HPP
8
9# include <boost/python/class.hpp>
10# include <boost/python/def_visitor.hpp>
11# include <boost/python/register_ptr_to_python.hpp>
12# include <boost/python/suite/indexing/detail/indexing_suite_detail.hpp>
13# include <boost/python/return_internal_reference.hpp>
14# include <boost/python/iterator.hpp>
15# include <boost/mpl/or.hpp>
16# include <boost/mpl/not.hpp>
17# include <boost/type_traits/is_same.hpp>
18
19namespace boost { namespace python {
20                   
21    // indexing_suite class. This class is the facade class for
22    // the management of C++ containers intended to be integrated
23    // to Python. The objective is make a C++ container look and
24    // feel and behave exactly as we'd expect a Python container.
25    // By default indexed elements are returned by proxy. This can be
26    // disabled by supplying *true* in the NoProxy template parameter.
27    //
28    // Derived classes provide the hooks needed by the indexing_suite
29    // to do its job:
30    //
31    //      static data_type&
32    //      get_item(Container& container, index_type i);
33    //
34    //      static object
35    //      get_slice(Container& container, index_type from, index_type to);
36    //
37    //      static void
38    //      set_item(Container& container, index_type i, data_type const& v);
39    //
40    //      static void
41    //      set_slice(
42    //         Container& container, index_type from,
43    //         index_type to, data_type const& v
44    //      );
45    //
46    //      template <class Iter>
47    //      static void
48    //      set_slice(Container& container, index_type from,
49    //          index_type to, Iter first, Iter last
50    //      );
51    //
52    //      static void
53    //      delete_item(Container& container, index_type i);
54    //       
55    //      static void
56    //      delete_slice(Container& container, index_type from, index_type to);
57    //       
58    //      static size_t
59    //      size(Container& container);
60    //
61    //      template <class T>
62    //      static bool
63    //      contains(Container& container, T const& val);
64    //       
65    //      static index_type
66    //      convert_index(Container& container, PyObject* i);
67    //       
68    //      static index_type
69    //      adjust_index(index_type current, index_type from,
70    //          index_type to, size_type len
71    //      );
72    //
73    // Most of these policies are self explanatory. convert_index and
74    // adjust_index, however, deserves some explanation.
75    //
76    // convert_index converts an Python index into a C++ index that the
77    // container can handle. For instance, negative indexes in Python, by
78    // convention, indexes from the right (e.g. C[-1] indexes the rightmost
79    // element in C). convert_index should handle the necessary conversion
80    // for the C++ container (e.g. convert -1 to C.size()-1). convert_index
81    // should also be able to convert the type of the index (A dynamic Python
82    // type) to the actual type that the C++ container expects.
83    //
84    // When a container expands or contracts, held indexes to its elements
85    // must be adjusted to follow the movement of data. For instance, if
86    // we erase 3 elements, starting from index 0 from a 5 element vector,
87    // what used to be at index 4 will now be at index 1:
88    //
89    //      [a][b][c][d][e] ---> [d][e]
90    //                   ^           ^
91    //                   4           1
92    //
93    // adjust_index takes care of the adjustment. Given a current index,
94    // the function should return the adjusted index when data in the
95    // container at index from..to is replaced by *len* elements.
96    //
97
98    template <
99          class Container
100        , class DerivedPolicies
101        , bool NoProxy = false
102        , bool NoSlice = false
103        , class Data = typename Container::value_type
104        , class Index = typename Container::size_type
105        , class Key = typename Container::value_type
106    >
107    class indexing_suite 
108        : public def_visitor<
109            indexing_suite<
110              Container
111            , DerivedPolicies
112            , NoProxy
113            , NoSlice
114            , Data
115            , Index
116            , Key
117        > >
118    {
119    private:
120       
121        typedef mpl::or_<
122            mpl::bool_<NoProxy>
123          , mpl::not_<is_class<Data> >
124          , typename mpl::or_<
125                is_same<Data, std::string>
126              , is_same<Data, std::complex<float> >
127              , is_same<Data, std::complex<double> >
128              , is_same<Data, std::complex<long double> > >::type>
129        no_proxy;
130                   
131        typedef detail::container_element<Container, Index, DerivedPolicies>
132            container_element_t;
133       
134#if BOOST_WORKAROUND(BOOST_MSVC, < 1300)
135        struct return_policy : return_internal_reference<> {};
136#else
137        typedef return_internal_reference<> return_policy;
138#endif
139
140        typedef typename mpl::if_<
141            no_proxy
142          , iterator<Container>
143          , iterator<Container, return_policy> >::type
144        def_iterator;
145       
146        typedef typename mpl::if_<
147            no_proxy
148          , detail::no_proxy_helper<
149                Container
150              , DerivedPolicies
151              , container_element_t
152              , Index>
153          , detail::proxy_helper<
154                Container
155              , DerivedPolicies
156              , container_element_t
157              , Index> >::type
158        proxy_handler;
159
160        typedef typename mpl::if_<
161            mpl::bool_<NoSlice>
162          , detail::no_slice_helper<
163                Container
164              , DerivedPolicies
165              , proxy_handler
166              , Data
167              , Index>
168          , detail::slice_helper<
169                Container
170              , DerivedPolicies
171              , proxy_handler
172              , Data
173              , Index> >::type
174        slice_handler;
175 
176    public:
177     
178        template <class Class>
179        void visit(Class& cl) const
180        {
181            // Hook into the class_ generic visitation .def function
182            proxy_handler::register_container_element();
183           
184            cl
185                .def("__len__", base_size)
186                .def("__setitem__", &base_set_item)
187                .def("__delitem__", &base_delete_item)
188                .def("__getitem__", &base_get_item)
189                .def("__contains__", &base_contains)
190                .def("__iter__", def_iterator())
191            ;
192           
193            DerivedPolicies::extension_def(cl);
194        }       
195       
196        template <class Class>
197        static void 
198        extension_def(Class& cl)
199        {
200            // default.
201            // no more extensions
202        }
203
204    private:
205     
206        static object
207        base_get_item(back_reference<Container&> container, PyObject* i)
208        { 
209            if (PySlice_Check(i))
210                return slice_handler::base_get_slice(
211                    container.get(), reinterpret_cast<PySliceObject*>(i));
212           
213            return proxy_handler::base_get_item_(container, i);
214        }
215       
216        static void 
217        base_set_item(Container& container, PyObject* i, PyObject* v)
218        {
219            if (PySlice_Check(i))
220            {
221                 slice_handler::base_set_slice(container, 
222                     reinterpret_cast<PySliceObject*>(i), v);
223            }
224            else
225            {
226                extract<Data&> elem(v);
227                // try if elem is an exact Data
228                if (elem.check())
229                {
230                    DerivedPolicies::
231                        set_item(container, 
232                            DerivedPolicies::
233                                convert_index(container, i), elem());
234                }
235                else
236                {
237                    //  try to convert elem to Data
238                    extract<Data> elem(v);
239                    if (elem.check())
240                    {
241                        DerivedPolicies::
242                            set_item(container, 
243                                DerivedPolicies::
244                                    convert_index(container, i), elem());
245                    }
246                    else
247                    {
248                        PyErr_SetString(PyExc_TypeError, "Invalid assignment");
249                        throw_error_already_set();
250                    }
251                }
252            }
253        }
254
255        static void 
256        base_delete_item(Container& container, PyObject* i)
257        {
258            if (PySlice_Check(i))
259            {
260                slice_handler::base_delete_slice(
261                    container, reinterpret_cast<PySliceObject*>(i));
262                return;
263            }
264           
265            Index index = DerivedPolicies::convert_index(container, i);
266            proxy_handler::base_erase_index(container, index, mpl::bool_<NoSlice>());
267            DerivedPolicies::delete_item(container, index);
268        } 
269
270        static size_t
271        base_size(Container& container)
272        {
273            return DerivedPolicies::size(container);
274        }
275
276        static bool
277        base_contains(Container& container, PyObject* key)
278        {
279            extract<Key const&> x(key);
280            //  try if key is an exact Key type
281            if (x.check())
282            {
283                return DerivedPolicies::contains(container, x());
284            }
285            else
286            {
287                //  try to convert key to Key type
288                extract<Key> x(key);
289                if (x.check())
290                    return DerivedPolicies::contains(container, x());
291                else
292                    return false;
293            }           
294        }
295    };
296   
297}} // namespace boost::python
298
299#endif // INDEXING_SUITE_JDG20036_HPP
Note: See TracBrowser for help on using the repository browser.