// Copyright (c) 2003 Raoul M. Gough // // Use, modification and distribution is subject to the Boost Software // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy // at http://www.boost.org/LICENSE_1_0.txt) // // Header file map.hpp // // Indexing algorithms support for std::map instances // // History // ======= // 2003/10/28 rmg File creation from algo_selector.hpp // 2008/12/08 Roman Change indexing suite layout // 2010/04/29 Roman Adding "__len__" method // // $Id: map.hpp,v 1.1.2.6 2004/02/08 18:57:42 raoulgough Exp $ // #ifndef BOOST_PYTHON_INDEXING_MAP_HPP #define BOOST_PYTHON_INDEXING_MAP_HPP #include <indexing_suite/container_traits.hpp> #include <indexing_suite/container_suite.hpp> #include <indexing_suite/algorithms.hpp> #include <boost/detail/workaround.hpp> #include <map> #include <indexing_suite/pair.hpp> namespace boost { namespace python { namespace indexing { ///////////////////////////////////////////////////////////////////////// // ContainerTraits implementation for std::map instances ///////////////////////////////////////////////////////////////////////// template<typename Container> class map_traits : public base_container_traits<Container> { typedef base_container_traits<Container> base_class; public: # if BOOST_WORKAROUND (BOOST_MSVC, <= 1200) // MSVC6 has a nonstandard name for mapped_type in std::map typedef typename Container::referent_type value_type; # else typedef typename Container::mapped_type value_type; # endif typedef value_type & reference; typedef typename Container::key_type index_type; // operator[] typedef typename Container::key_type key_type; // find, count, ... typedef typename BOOST_PYTHON_INDEXING_CALL_TRAITS <value_type>::param_type value_param; typedef typename BOOST_PYTHON_INDEXING_CALL_TRAITS <key_type>::param_type key_param; typedef typename BOOST_PYTHON_INDEXING_CALL_TRAITS <index_type>::param_type index_param; BOOST_STATIC_CONSTANT( method_set_type, supported_methods = ( method_iter | method_getitem | method_contains | method_count | method_has_key | method_len | detail::method_set_if< base_class::is_mutable, method_setitem | method_delitem | method_insert >::value )); }; ///////////////////////////////////////////////////////////////////////// // Algorithms implementation for std::map instances ///////////////////////////////////////////////////////////////////////// template<typename ContainerTraits, typename Ovr = detail::no_override> class map_algorithms : public assoc_algorithms <ContainerTraits, typename detail::maybe_override <map_algorithms<ContainerTraits, Ovr>, Ovr> ::type> { typedef map_algorithms<ContainerTraits, Ovr> self_type; typedef typename detail::maybe_override<self_type, Ovr>::type most_derived; typedef assoc_algorithms<ContainerTraits, most_derived> Parent; public: typedef typename Parent::container container; typedef typename Parent::reference reference; typedef typename Parent::index_param index_param; typedef typename Parent::value_param value_param; static reference get (container &, index_param); // Version to return only the mapped type static boost::python::list keys( container & ); static void assign (container &, index_param, value_param); static void insert (container &, index_param, value_param); template<typename PythonClass, typename Policy> static void visit_container_class( PythonClass &pyClass, Policy const &policy) { ContainerTraits::visit_container_class (pyClass, policy); pyClass.def( "keys", &self_type::keys ); typedef BOOST_DEDUCED_TYPENAME most_derived::container::value_type value_type; mapping::register_value_type< PythonClass, value_type, Policy >( pyClass ); //now we can expose iterators functionality pyClass.def( "__iter__", python::iterator< BOOST_DEDUCED_TYPENAME most_derived::container >() ); } }; #if !defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) namespace detail { /////////////////////////////////////////////////////////////////////// // algorithms support for std::map instances /////////////////////////////////////////////////////////////////////// template <class Key, class T, class Compare, class Allocator> class algorithms_selector<std::map<Key, T, Compare, Allocator> > { typedef std::map<Key, T, Compare, Allocator> Container; typedef map_traits<Container> mutable_traits; typedef map_traits<Container const> const_traits; public: typedef map_algorithms<mutable_traits> mutable_algorithms; typedef map_algorithms<const_traits> const_algorithms; }; /////////////////////////////////////////////////////////////////////// // algorithms support for std::multimap instances /////////////////////////////////////////////////////////////////////// template <class Key, class T, class Compare, class Allocator> class algorithms_selector<std::multimap<Key, T, Compare, Allocator> > { typedef std::multimap<Key, T, Compare, Allocator> Container; typedef map_traits<Container> mutable_traits; typedef map_traits<Container const> const_traits; public: typedef map_algorithms<mutable_traits> mutable_algorithms; typedef map_algorithms<const_traits> const_algorithms; }; } #endif template< class Container, method_set_type MethodMask = all_methods, class Traits = map_traits<Container> > struct map_suite : container_suite<Container, MethodMask, map_algorithms<Traits> > { }; ///////////////////////////////////////////////////////////////////////// // Index into a container (map version) ///////////////////////////////////////////////////////////////////////// template<typename ContainerTraits, typename Ovr> BOOST_DEDUCED_TYPENAME map_algorithms<ContainerTraits, Ovr>::reference map_algorithms<ContainerTraits, Ovr>::get (container &c, index_param ix) { return most_derived::find_or_throw (c, ix)->second; } template<typename ContainerTraits, typename Ovr> boost::python::list map_algorithms<ContainerTraits, Ovr>::keys( container &c ) { boost::python::list _keys; //For some reason code with set could not be compiled //std::set< key_param > unique_keys; typedef BOOST_DEDUCED_TYPENAME container::iterator iter_type; for( iter_type index = most_derived::begin(c); index != most_derived::end(c); ++index ){ //if( unique_keys.end() == unique_keys.find( index->first ) ){ // unique_keys.insert( index->first ); if( !_keys.count( index->first ) ){ _keys.append( index->first ); } //} } return _keys; } ///////////////////////////////////////////////////////////////////////// // Assign a value at a particular index (map version) ///////////////////////////////////////////////////////////////////////// template<typename ContainerTraits, typename Ovr> void map_algorithms<ContainerTraits, Ovr>::assign( container &c, index_param ix, value_param val) { c[ix] = val; // Handles overwrite and insert } ///////////////////////////////////////////////////////////////////////// // Insert a new key, value pair into a map ///////////////////////////////////////////////////////////////////////// template<typename ContainerTraits, typename Ovr> void map_algorithms<ContainerTraits, Ovr>::insert( container &c, index_param ix, value_param val) { typedef std::pair <BOOST_DEDUCED_TYPENAME self_type::container_traits::index_type, BOOST_DEDUCED_TYPENAME self_type::container_traits::value_type> pair_type; // Can't use std::make_pair, because param types may be references if (!c.insert (pair_type (ix, val)).second) { PyErr_SetString( PyExc_ValueError, "Map already holds value for insertion"); boost::python::throw_error_already_set (); } } } } } #endif // BOOST_PYTHON_INDEXING_MAP_HPP