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 VECTOR_INDEXING_SUITE_JDG20036_HPP 7 # define VECTOR_INDEXING_SUITE_JDG20036_HPP 8 9 # include <boost/python/suite/indexing/indexing_suite.hpp> 10 # include <boost/python/suite/indexing/container_utils.hpp> 11 # include <boost/python/iterator.hpp> 12 13 namespace boost { namespace python { 14 15 // Forward declaration 16 template <class Container, bool NoProxy, class DerivedPolicies> 17 class vector_indexing_suite; 18 19 namespace detail 20 { 21 template <class Container, bool NoProxy> 22 class final_vector_derived_policies 23 : public vector_indexing_suite<Container, 24 NoProxy, final_vector_derived_policies<Container, NoProxy> > {}; 25 } 26 27 // The vector_indexing_suite class is a predefined indexing_suite derived 28 // class for wrapping std::vector (and std::vector like) classes. It provides 29 // all the policies required by the indexing_suite (see indexing_suite). 30 // Example usage: 31 // 32 // class X {...}; 33 // 34 // ... 35 // 36 // class_<std::vector<X> >("XVec") 37 // .def(vector_indexing_suite<std::vector<X> >()) 38 // ; 39 // 40 // By default indexed elements are returned by proxy. This can be 41 // disabled by supplying *true* in the NoProxy template parameter. 42 // 43 template < 44 class Container, 45 bool NoProxy = false, 46 class DerivedPolicies 47 = detail::final_vector_derived_policies<Container, NoProxy> > 48 class vector_indexing_suite 49 : public indexing_suite<Container, DerivedPolicies, NoProxy> 50 { 51 public: 52 53 typedef typename Container::value_type data_type; 54 typedef typename Container::value_type key_type; 55 typedef typename Container::size_type index_type; 56 typedef typename Container::size_type size_type; 57 typedef typename Container::difference_type difference_type; 58 59 template <class Class> 60 static void extension_def(Class & cl)61 extension_def(Class& cl) 62 { 63 cl 64 .def("append", &base_append) 65 .def("extend", &base_extend) 66 ; 67 } 68 69 static 70 typename mpl::if_< 71 is_class<data_type> 72 , data_type& 73 , data_type 74 >::type get_item(Container & container,index_type i)75 get_item(Container& container, index_type i) 76 { 77 return container[i]; 78 } 79 80 static object get_slice(Container & container,index_type from,index_type to)81 get_slice(Container& container, index_type from, index_type to) 82 { 83 if (from > to) 84 return object(Container()); 85 return object(Container(container.begin()+from, container.begin()+to)); 86 } 87 88 static void set_item(Container & container,index_type i,data_type const & v)89 set_item(Container& container, index_type i, data_type const& v) 90 { 91 container[i] = v; 92 } 93 94 static void set_slice(Container & container,index_type from,index_type to,data_type const & v)95 set_slice(Container& container, index_type from, 96 index_type to, data_type const& v) 97 { 98 if (from > to) { 99 return; 100 } 101 else { 102 container.erase(container.begin()+from, container.begin()+to); 103 container.insert(container.begin()+from, v); 104 } 105 } 106 107 template <class Iter> 108 static void set_slice(Container & container,index_type from,index_type to,Iter first,Iter last)109 set_slice(Container& container, index_type from, 110 index_type to, Iter first, Iter last) 111 { 112 if (from > to) { 113 container.insert(container.begin()+from, first, last); 114 } 115 else { 116 container.erase(container.begin()+from, container.begin()+to); 117 container.insert(container.begin()+from, first, last); 118 } 119 } 120 121 static void delete_item(Container & container,index_type i)122 delete_item(Container& container, index_type i) 123 { 124 container.erase(container.begin()+i); 125 } 126 127 static void delete_slice(Container & container,index_type from,index_type to)128 delete_slice(Container& container, index_type from, index_type to) 129 { 130 if (from > to) { 131 // A null-op. 132 return; 133 } 134 container.erase(container.begin()+from, container.begin()+to); 135 } 136 137 static size_t size(Container & container)138 size(Container& container) 139 { 140 return container.size(); 141 } 142 143 static bool contains(Container & container,key_type const & key)144 contains(Container& container, key_type const& key) 145 { 146 return std::find(container.begin(), container.end(), key) 147 != container.end(); 148 } 149 150 static index_type get_min_index(Container &)151 get_min_index(Container& /*container*/) 152 { 153 return 0; 154 } 155 156 static index_type get_max_index(Container & container)157 get_max_index(Container& container) 158 { 159 return container.size(); 160 } 161 162 static bool compare_index(Container &,index_type a,index_type b)163 compare_index(Container& /*container*/, index_type a, index_type b) 164 { 165 return a < b; 166 } 167 168 static index_type convert_index(Container & container,PyObject * i_)169 convert_index(Container& container, PyObject* i_) 170 { 171 extract<long> i(i_); 172 if (i.check()) 173 { 174 long index = i(); 175 if (index < 0) 176 index += DerivedPolicies::size(container); 177 if (index >= long(container.size()) || index < 0) 178 { 179 PyErr_SetString(PyExc_IndexError, "Index out of range"); 180 throw_error_already_set(); 181 } 182 return index; 183 } 184 185 PyErr_SetString(PyExc_TypeError, "Invalid index type"); 186 throw_error_already_set(); 187 return index_type(); 188 } 189 190 static void append(Container & container,data_type const & v)191 append(Container& container, data_type const& v) 192 { 193 container.push_back(v); 194 } 195 196 template <class Iter> 197 static void extend(Container & container,Iter first,Iter last)198 extend(Container& container, Iter first, Iter last) 199 { 200 container.insert(container.end(), first, last); 201 } 202 203 private: 204 205 static void base_append(Container & container,object v)206 base_append(Container& container, object v) 207 { 208 extract<data_type&> elem(v); 209 // try if elem is an exact Data 210 if (elem.check()) 211 { 212 DerivedPolicies::append(container, elem()); 213 } 214 else 215 { 216 // try to convert elem to data_type 217 extract<data_type> elem(v); 218 if (elem.check()) 219 { 220 DerivedPolicies::append(container, elem()); 221 } 222 else 223 { 224 PyErr_SetString(PyExc_TypeError, 225 "Attempting to append an invalid type"); 226 throw_error_already_set(); 227 } 228 } 229 } 230 231 static void base_extend(Container & container,object v)232 base_extend(Container& container, object v) 233 { 234 std::vector<data_type> temp; 235 container_utils::extend_container(temp, v); 236 DerivedPolicies::extend(container, temp.begin(), temp.end()); 237 } 238 }; 239 240 }} // namespace boost::python 241 242 #endif // VECTOR_INDEXING_SUITE_JDG20036_HPP 243