Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-02-22 10:26:16

0001 //  (C) Copyright Joel de Guzman 2003.
0002 //  Distributed under the Boost Software License, Version 1.0. (See
0003 //  accompanying file LICENSE_1_0.txt or copy at
0004 //  http://www.boost.org/LICENSE_1_0.txt)
0005 
0006 #ifndef INDEXING_SUITE_JDG20036_HPP
0007 # define INDEXING_SUITE_JDG20036_HPP
0008 
0009 # include <boost/python/class.hpp>
0010 # include <boost/python/def_visitor.hpp>
0011 # include <boost/python/register_ptr_to_python.hpp>
0012 # include <boost/python/suite/indexing/detail/indexing_suite_detail.hpp>
0013 # include <boost/python/return_internal_reference.hpp>
0014 # include <boost/python/iterator.hpp>
0015 # include <boost/mpl/or.hpp>
0016 # include <boost/mpl/not.hpp>
0017 # include <boost/python/detail/type_traits.hpp>
0018 
0019 namespace boost { namespace python {
0020 
0021     // indexing_suite class. This class is the facade class for
0022     // the management of C++ containers intended to be integrated
0023     // to Python. The objective is make a C++ container look and
0024     // feel and behave exactly as we'd expect a Python container.
0025     // By default indexed elements are returned by proxy. This can be
0026     // disabled by supplying *true* in the NoProxy template parameter.
0027     //
0028     // Derived classes provide the hooks needed by the indexing_suite
0029     // to do its job:
0030     //
0031     //      static data_type&
0032     //      get_item(Container& container, index_type i);
0033     //
0034     //      static object
0035     //      get_slice(Container& container, index_type from, index_type to);
0036     //
0037     //      static void
0038     //      set_item(Container& container, index_type i, data_type const& v);
0039     //
0040     //      static void
0041     //      set_slice(
0042     //         Container& container, index_type from,
0043     //         index_type to, data_type const& v
0044     //      );
0045     //
0046     //      template <class Iter>
0047     //      static void
0048     //      set_slice(Container& container, index_type from,
0049     //          index_type to, Iter first, Iter last
0050     //      );
0051     //
0052     //      static void
0053     //      delete_item(Container& container, index_type i);
0054     //
0055     //      static void
0056     //      delete_slice(Container& container, index_type from, index_type to);
0057     //
0058     //      static size_t
0059     //      size(Container& container);
0060     //
0061     //      template <class T>
0062     //      static bool
0063     //      contains(Container& container, T const& val);
0064     //
0065     //      static index_type
0066     //      convert_index(Container& container, PyObject* i);
0067     //
0068     //      static index_type
0069     //      adjust_index(index_type current, index_type from,
0070     //          index_type to, size_type len
0071     //      );
0072     //
0073     // Most of these policies are self explanatory. convert_index and
0074     // adjust_index, however, deserves some explanation.
0075     //
0076     // convert_index converts an Python index into a C++ index that the
0077     // container can handle. For instance, negative indexes in Python, by
0078     // convention, indexes from the right (e.g. C[-1] indexes the rightmost
0079     // element in C). convert_index should handle the necessary conversion
0080     // for the C++ container (e.g. convert -1 to C.size()-1). convert_index
0081     // should also be able to convert the type of the index (A dynamic Python
0082     // type) to the actual type that the C++ container expects.
0083     //
0084     // When a container expands or contracts, held indexes to its elements
0085     // must be adjusted to follow the movement of data. For instance, if
0086     // we erase 3 elements, starting from index 0 from a 5 element vector,
0087     // what used to be at index 4 will now be at index 1:
0088     //
0089     //      [a][b][c][d][e] ---> [d][e]
0090     //                   ^           ^
0091     //                   4           1
0092     //
0093     // adjust_index takes care of the adjustment. Given a current index,
0094     // the function should return the adjusted index when data in the
0095     // container at index from..to is replaced by *len* elements.
0096     //
0097 
0098     template <
0099           class Container
0100         , class DerivedPolicies
0101         , bool NoProxy = false
0102         , bool NoSlice = false
0103         , class Data = typename Container::value_type
0104         , class Index = typename Container::size_type
0105         , class Key = typename Container::value_type
0106     >
0107     class indexing_suite
0108         : public def_visitor<
0109             indexing_suite<
0110               Container
0111             , DerivedPolicies
0112             , NoProxy
0113             , NoSlice
0114             , Data
0115             , Index
0116             , Key
0117         > >
0118     {
0119     private:
0120 
0121         typedef mpl::or_<
0122             mpl::bool_<NoProxy>
0123           , mpl::not_<is_class<Data> >
0124           , typename mpl::or_<
0125                 detail::is_same<Data, std::string>
0126               , detail::is_same<Data, std::complex<float> >
0127               , detail::is_same<Data, std::complex<double> >
0128               , detail::is_same<Data, std::complex<long double> > >::type>
0129         no_proxy;
0130 
0131         typedef detail::container_element<Container, Index, DerivedPolicies>
0132             container_element_t;
0133 
0134         typedef return_internal_reference<> return_policy;
0135 
0136         typedef typename mpl::if_<
0137             no_proxy
0138           , iterator<Container>
0139           , iterator<Container, return_policy> >::type
0140         def_iterator;
0141 
0142         typedef typename mpl::if_<
0143             no_proxy
0144           , detail::no_proxy_helper<
0145                 Container
0146               , DerivedPolicies
0147               , container_element_t
0148               , Index>
0149           , detail::proxy_helper<
0150                 Container
0151               , DerivedPolicies
0152               , container_element_t
0153               , Index> >::type
0154         proxy_handler;
0155 
0156         typedef typename mpl::if_<
0157             mpl::bool_<NoSlice>
0158           , detail::no_slice_helper<
0159                 Container
0160               , DerivedPolicies
0161               , proxy_handler
0162               , Data
0163               , Index>
0164           , detail::slice_helper<
0165                 Container
0166               , DerivedPolicies
0167               , proxy_handler
0168               , Data
0169               , Index> >::type
0170         slice_handler;
0171 
0172     public:
0173 
0174         template <class Class>
0175         void visit(Class& cl) const
0176         {
0177             // Hook into the class_ generic visitation .def function
0178             proxy_handler::register_container_element();
0179 
0180             cl
0181                 .def("__len__", base_size)
0182                 .def("__setitem__", &base_set_item)
0183                 .def("__delitem__", &base_delete_item)
0184                 .def("__getitem__", &base_get_item)
0185                 .def("__contains__", &base_contains)
0186                 .def("__iter__", def_iterator())
0187             ;
0188 
0189             DerivedPolicies::extension_def(cl);
0190         }
0191 
0192         template <class Class>
0193         static void
0194         extension_def(Class& cl)
0195         {
0196             // default.
0197             // no more extensions
0198         }
0199 
0200     private:
0201 
0202         static object
0203         base_get_item(back_reference<Container&> container, PyObject* i)
0204         {
0205             if (PySlice_Check(i))
0206                 return slice_handler::base_get_slice(
0207                     container.get(), static_cast<PySliceObject*>(static_cast<void*>(i)));
0208 
0209             return proxy_handler::base_get_item_(container, i);
0210         }
0211 
0212         static void
0213         base_set_item(Container& container, PyObject* i, PyObject* v)
0214         {
0215             if (PySlice_Check(i))
0216             {
0217                  slice_handler::base_set_slice(container,
0218                      static_cast<PySliceObject*>(static_cast<void*>(i)), v);
0219             }
0220             else
0221             {
0222                 extract<Data&> elem(v);
0223                 // try if elem is an exact Data
0224                 if (elem.check())
0225                 {
0226                     DerivedPolicies::
0227                         set_item(container,
0228                             DerivedPolicies::
0229                                 convert_index(container, i), elem());
0230                 }
0231                 else
0232                 {
0233                     //  try to convert elem to Data
0234                     extract<Data> elem(v);
0235                     if (elem.check())
0236                     {
0237                         DerivedPolicies::
0238                             set_item(container,
0239                                 DerivedPolicies::
0240                                     convert_index(container, i), elem());
0241                     }
0242                     else
0243                     {
0244                         PyErr_SetString(PyExc_TypeError, "Invalid assignment");
0245                         throw_error_already_set();
0246                     }
0247                 }
0248             }
0249         }
0250 
0251         static void
0252         base_delete_item(Container& container, PyObject* i)
0253         {
0254             if (PySlice_Check(i))
0255             {
0256                 slice_handler::base_delete_slice(
0257                     container, static_cast<PySliceObject*>(static_cast<void*>(i)));
0258                 return;
0259             }
0260 
0261             Index index = DerivedPolicies::convert_index(container, i);
0262             proxy_handler::base_erase_index(container, index, mpl::bool_<NoSlice>());
0263             DerivedPolicies::delete_item(container, index);
0264         }
0265 
0266         static size_t
0267         base_size(Container& container)
0268         {
0269             return DerivedPolicies::size(container);
0270         }
0271 
0272         static bool
0273         base_contains(Container& container, PyObject* key)
0274         {
0275             extract<Key const&> x(key);
0276             //  try if key is an exact Key type
0277             if (x.check())
0278             {
0279                 return DerivedPolicies::contains(container, x());
0280             }
0281             else
0282             {
0283                 //  try to convert key to Key type
0284                 extract<Key> x(key);
0285                 if (x.check())
0286                     return DerivedPolicies::contains(container, x());
0287                 else
0288                     return false;
0289             }
0290         }
0291     };
0292 
0293 }} // namespace boost::python
0294 
0295 #endif // INDEXING_SUITE_JDG20036_HPP