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 MAP_INDEXING_SUITE_JDG20038_HPP 7 # define MAP_INDEXING_SUITE_JDG20038_HPP 8 9 # include <boost/python/suite/indexing/indexing_suite.hpp> 10 # include <boost/python/iterator.hpp> 11 # include <boost/python/call_method.hpp> 12 # include <boost/python/tuple.hpp> 13 14 namespace boost { namespace python { 15 16 // Forward declaration 17 template <class Container, bool NoProxy, class DerivedPolicies> 18 class map_indexing_suite; 19 20 namespace detail 21 { 22 template <class Container, bool NoProxy> 23 class final_map_derived_policies 24 : public map_indexing_suite<Container, 25 NoProxy, final_map_derived_policies<Container, NoProxy> > {}; 26 } 27 28 // The map_indexing_suite class is a predefined indexing_suite derived 29 // class for wrapping std::map (and std::map like) classes. It provides 30 // all the policies required by the indexing_suite (see indexing_suite). 31 // Example usage: 32 // 33 // class X {...}; 34 // 35 // ... 36 // 37 // class_<std::map<std::string, X> >("XMap") 38 // .def(map_indexing_suite<std::map<std::string, X> >()) 39 // ; 40 // 41 // By default indexed elements are returned by proxy. This can be 42 // disabled by supplying *true* in the NoProxy template parameter. 43 // 44 template < 45 class Container, 46 bool NoProxy = false, 47 class DerivedPolicies 48 = detail::final_map_derived_policies<Container, NoProxy> > 49 class map_indexing_suite 50 : public indexing_suite< 51 Container 52 , DerivedPolicies 53 , NoProxy 54 , true 55 , typename Container::value_type::second_type 56 , typename Container::key_type 57 , typename Container::key_type 58 > 59 { 60 public: 61 62 typedef typename Container::value_type value_type; 63 typedef typename Container::value_type::second_type data_type; 64 typedef typename Container::key_type key_type; 65 typedef typename Container::key_type index_type; 66 typedef typename Container::size_type size_type; 67 typedef typename Container::difference_type difference_type; 68 69 template <class Class> 70 static void extension_def(Class & cl)71 extension_def(Class& cl) 72 { 73 // Wrap the map's element (value_type) 74 std::string elem_name = "map_indexing_suite_"; 75 object class_name(cl.attr("__name__")); 76 extract<std::string> class_name_extractor(class_name); 77 elem_name += class_name_extractor(); 78 elem_name += "_entry"; 79 80 typedef typename mpl::if_< 81 mpl::and_<is_class<data_type>, mpl::bool_<!NoProxy> > 82 , return_internal_reference<> 83 , default_call_policies 84 >::type get_data_return_policy; 85 86 class_<value_type>(elem_name.c_str()) 87 .def("__repr__", &DerivedPolicies::print_elem) 88 .def("data", &DerivedPolicies::get_data, get_data_return_policy()) 89 .def("key", &DerivedPolicies::get_key) 90 ; 91 } 92 93 static object print_elem(typename Container::value_type const & e)94 print_elem(typename Container::value_type const& e) 95 { 96 return "(%s, %s)" % python::make_tuple(e.first, e.second); 97 } 98 99 static 100 typename mpl::if_< 101 mpl::and_<is_class<data_type>, mpl::bool_<!NoProxy> > 102 , data_type& 103 , data_type 104 >::type get_data(typename Container::value_type & e)105 get_data(typename Container::value_type& e) 106 { 107 return e.second; 108 } 109 110 static typename Container::key_type get_key(typename Container::value_type & e)111 get_key(typename Container::value_type& e) 112 { 113 return e.first; 114 } 115 116 static data_type& get_item(Container & container,index_type i_)117 get_item(Container& container, index_type i_) 118 { 119 typename Container::iterator i = container.find(i_); 120 if (i == container.end()) 121 { 122 PyErr_SetString(PyExc_KeyError, "Invalid key"); 123 throw_error_already_set(); 124 } 125 return i->second; 126 } 127 128 static void set_item(Container & container,index_type i,data_type const & v)129 set_item(Container& container, index_type i, data_type const& v) 130 { 131 container[i] = v; 132 } 133 134 static void delete_item(Container & container,index_type i)135 delete_item(Container& container, index_type i) 136 { 137 container.erase(i); 138 } 139 140 static size_t size(Container & container)141 size(Container& container) 142 { 143 return container.size(); 144 } 145 146 static bool contains(Container & container,key_type const & key)147 contains(Container& container, key_type const& key) 148 { 149 return container.find(key) != container.end(); 150 } 151 152 static bool compare_index(Container & container,index_type a,index_type b)153 compare_index(Container& container, index_type a, index_type b) 154 { 155 return container.key_comp()(a, b); 156 } 157 158 static index_type convert_index(Container &,PyObject * i_)159 convert_index(Container& /*container*/, PyObject* i_) 160 { 161 extract<key_type const&> i(i_); 162 if (i.check()) 163 { 164 return i(); 165 } 166 else 167 { 168 extract<key_type> i(i_); 169 if (i.check()) 170 return i(); 171 } 172 173 PyErr_SetString(PyExc_TypeError, "Invalid index type"); 174 throw_error_already_set(); 175 return index_type(); 176 } 177 }; 178 179 }} // namespace boost::python 180 181 #endif // MAP_INDEXING_SUITE_JDG20038_HPP 182