annotate DEPENDENCIES/generic/include/boost/python/suite/indexing/indexing_suite.hpp @ 125:34e428693f5d vext

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