library of assembled shared sources

http://lass.cocamware.com

pymap.h

Go to the documentation of this file.
00001 /** @file
00002  *  @author Bram de Greve (bramz@users.sourceforge.net)
00003  *  @author Tom De Muer (tomdemuer@users.sourceforge.net)
00004  *
00005  *  *** BEGIN LICENSE INFORMATION ***
00006  *  
00007  *  The contents of this file are subject to the Common Public Attribution License 
00008  *  Version 1.0 (the "License"); you may not use this file except in compliance with 
00009  *  the License. You may obtain a copy of the License at 
00010  *  http://lass.sourceforge.net/cpal-license. The License is based on the 
00011  *  Mozilla Public License Version 1.1 but Sections 14 and 15 have been added to cover 
00012  *  use of software over a computer network and provide for limited attribution for 
00013  *  the Original Developer. In addition, Exhibit A has been modified to be consistent 
00014  *  with Exhibit B.
00015  *  
00016  *  Software distributed under the License is distributed on an "AS IS" basis, WITHOUT 
00017  *  WARRANTY OF ANY KIND, either express or implied. See the License for the specific 
00018  *  language governing rights and limitations under the License.
00019  *  
00020  *  The Original Code is LASS - Library of Assembled Shared Sources.
00021  *  
00022  *  The Initial Developer of the Original Code is Bram de Greve and Tom De Muer.
00023  *  The Original Developer is the Initial Developer.
00024  *  
00025  *  All portions of the code written by the Initial Developer are:
00026  *  Copyright (C) 2004-2007 the Initial Developer.
00027  *  All Rights Reserved.
00028  *  
00029  *  Contributor(s):
00030  *
00031  *  Alternatively, the contents of this file may be used under the terms of the 
00032  *  GNU General Public License Version 2 or later (the GPL), in which case the 
00033  *  provisions of GPL are applicable instead of those above.  If you wish to allow use
00034  *  of your version of this file only under the terms of the GPL and not to allow 
00035  *  others to use your version of this file under the CPAL, indicate your decision by 
00036  *  deleting the provisions above and replace them with the notice and other 
00037  *  provisions required by the GPL License. If you do not delete the provisions above,
00038  *  a recipient may use your version of this file under either the CPAL or the GPL.
00039  *  
00040  *  *** END LICENSE INFORMATION ***
00041  */
00042 
00043 /** @defgroup Python
00044  *  @brief interface library to Python
00045  */
00046 
00047 #ifndef LASS_GUARDIAN_OF_INCLUSION_UTIL_PYMAP_H
00048 #define LASS_GUARDIAN_OF_INCLUSION_UTIL_PYMAP_H
00049 
00050 #include "util_common.h"
00051 #include "pyobject_plus.h"
00052 #include "pyobject_util.h"
00053 #include "pyiteratorrange.h"
00054 #include "../meta/type_traits.h"
00055 
00056 #include <map>
00057 
00058 namespace lass
00059 {
00060 namespace python
00061 {
00062 namespace impl
00063 {
00064     class LASS_DLL PyMapImplBase
00065     {
00066     public:
00067         PyMapImplBase() {};
00068         virtual ~PyMapImplBase() {};
00069         virtual Py_ssize_t PyMap_Length() = 0;
00070         virtual PyObject* PyMap_Subscript( PyObject* iKey) = 0;
00071         virtual int PyMap_AssSubscript( PyObject* iKey, PyObject* iValue) = 0;
00072         virtual std::string pyStr(void) = 0;
00073         virtual std::string pyRepr(void) = 0;
00074         virtual TPyObjPtr keys() const = 0;
00075         virtual TPyObjPtr values() const = 0;
00076         virtual PyObject* PyMap_Iter() = 0;
00077         virtual bool pointsToSameContainer(void* iO) = 0;
00078     };
00079 
00080     template<typename M> 
00081     class PyMapImpl : public PyMapImplBase
00082     {
00083     public:
00084         enum Ownership
00085         {
00086             oOwner,
00087             oBorrowed
00088         };
00089         PyMapImpl(M* iMap, Ownership iOwnership = oBorrowed) : map_(iMap), ownership_(iOwnership) {}
00090         virtual ~PyMapImpl();
00091         virtual Py_ssize_t PyMap_Length();
00092         virtual PyObject* PyMap_Subscript( PyObject* iKey);
00093         virtual int PyMap_AssSubscript( PyObject* iKey, PyObject* iValue);
00094         virtual std::string pyStr(void);
00095         virtual std::string pyRepr(void);
00096         virtual TPyObjPtr keys() const;
00097         virtual TPyObjPtr values() const;
00098         virtual PyObject* PyMap_Iter();
00099         virtual bool pointsToSameContainer(void* iO) 
00100         { 
00101             return iO == (void*)map_;
00102         }
00103     private:
00104 
00105         int doPyMap_AssSubscript( PyObject* iKey, PyObject* iValue, meta::True);
00106         int doPyMap_AssSubscript( PyObject* iKey, PyObject* iValue, meta::False);
00107 
00108         M* map_;
00109         Ownership ownership_;
00110         enum { readOnly_ = meta::TypeTraits<M>::isConst };
00111     };
00112 
00113     /** PyMap.  Object for interfacing maps with Python 
00114     */
00115     class LASS_DLL PyMap : public PyObjectPlus
00116     {
00117         PY_HEADER(PyObjectPlus);
00118         static PyMappingMethods pyMappingMethods;
00119 
00120     public:
00121         /*
00122          * deprecated? [Bramz]
00123         template<typename M> PyMap( M* iStdMap ) 
00124         {
00125             initialize();
00126             impl::fixObjectType(this);
00127             LASS_ASSERT(iStdMap);
00128             pimpl_ = new PyMapImpl<M>(iStdMap); // also const M*
00129         }
00130         */
00131         template<typename M> PyMap( M& iStdMap ) 
00132         {
00133             initialize();
00134             impl::fixObjectType(this);
00135             pimpl_ = new PyMapImpl<M>(&iStdMap);
00136         }
00137         template<typename M> PyMap( const M& iStdMap ) 
00138         {
00139             initialize();
00140             impl::fixObjectType(this);
00141             std::auto_ptr<M> copy(new M(iStdMap));
00142             pimpl_ = new PyMapImpl<const M>(copy.get(), PyMapImpl<const M>::oOwner);
00143             copy.release();
00144         }
00145         virtual ~PyMap();
00146         virtual std::string doPyStr(void) { return pimpl_->pyStr(); }
00147         virtual std::string doPyRepr(void) { return pimpl_->pyRepr(); }
00148         virtual TPyObjPtr keys() const { return pimpl_->keys(); }
00149         virtual TPyObjPtr values() const { return pimpl_->values(); }
00150 
00151         static Py_ssize_t PyMap_Length( PyObject* iPO);
00152         static PyObject* PyMap_Subscript( PyObject* iPO, PyObject* iKey);
00153         static int PyMap_AssSubscript( PyObject* iPO, PyObject* iKey, PyObject* iValue);
00154 
00155         static PyObject* PyMap_Iter( PyObject* iPO);
00156 
00157         template<typename Container> bool pointsToSameContainer(Container& iO) 
00158         { 
00159             return pimpl_->pointsToSameContainer(&iO);
00160         }
00161 
00162     private:
00163 
00164         PyMap();
00165         PyMapImplBase*  pimpl_;
00166         static void initialize();
00167         static bool isInitialized;
00168     };
00169 
00170 
00171     template<typename M>
00172     PyMapImpl<M>::~PyMapImpl()
00173     {
00174         LASS_ASSERT(map_);
00175         if (ownership_ == oOwner)
00176         {
00177             delete map_;
00178         }
00179     }
00180 
00181     template<typename M>
00182     Py_ssize_t PyMapImpl<M>::PyMap_Length()
00183     {
00184         LASS_ASSERT(map_);
00185         const Py_ssize_t size = static_cast<Py_ssize_t>(map_->size());
00186         LASS_ASSERT(size >= 0);
00187         return size;
00188     }
00189 
00190     template<typename M>
00191     PyObject* PyMapImpl<M>::PyMap_Iter()
00192     {
00193         return new PyIteratorRange(map_->begin(), map_->end());
00194     }
00195 
00196 
00197     template<typename M>
00198     TPyObjPtr PyMapImpl<M>::keys() const
00199     {
00200         LASS_ASSERT(map_);
00201         std::vector<typename M::key_type> temp;
00202         for (typename M::const_iterator it=map_->begin();it!=map_->end();++it)
00203             temp.push_back(it->first);
00204         return pyBuildList(temp.begin(),temp.end());
00205     }
00206 
00207     template<typename M>
00208     TPyObjPtr PyMapImpl<M>::values() const
00209     {
00210         LASS_ASSERT(map_);
00211         std::vector<typename M::mapped_type> temp;
00212         for (typename M::const_iterator it=map_->begin();it!=map_->end();++it)
00213             temp.push_back(it->second);
00214         return pyBuildList(temp.begin(),temp.end());
00215     }
00216 
00217 
00218     template<typename M>
00219     PyObject* PyMapImpl<M>::PyMap_Subscript( PyObject* iKey)
00220     {
00221         LASS_ASSERT(map_);
00222         typename M::key_type cppKey;
00223         int r = PyExportTraits<typename M::key_type>::get( iKey, cppKey );
00224         if (r)
00225         {
00226             PyErr_SetString(PyExc_TypeError, "Cannot convert key to appropriate type");
00227             return NULL;
00228         }
00229         typename M::const_iterator it = map_->find(cppKey);
00230         if (it==map_->end())
00231         {
00232             PyErr_SetObject(PyExc_KeyError, iKey);
00233             return NULL;
00234         }
00235         PyObject* rv = PyExportTraits<typename M::mapped_type>::build( it->second );
00236         Py_INCREF(rv);
00237         return rv;
00238     }
00239     
00240     template<typename M>
00241     int PyMapImpl<M>::PyMap_AssSubscript( PyObject* iKey, PyObject* iData)
00242     {
00243         return PyMapImpl<M>::doPyMap_AssSubscript( iKey, iData, meta::Bool<readOnly_>());
00244     }
00245 
00246     template<typename M>
00247     int PyMapImpl<M>::doPyMap_AssSubscript( PyObject*, PyObject*, meta::True)
00248     {
00249         PyErr_SetString(PyExc_TypeError, "Map is not writeable");
00250         return 1;
00251     }
00252 
00253     template<typename M>
00254     int PyMapImpl<M>::doPyMap_AssSubscript( PyObject* iKey, PyObject* iData, meta::False)
00255     {
00256         LASS_ASSERT(map_);
00257         if (iData == NULL)      
00258         {
00259             typename M::key_type cppKey;
00260             int r = PyExportTraits<typename M::key_type>::get( iKey, cppKey );
00261             if (!r)
00262                 map_->erase(cppKey);
00263             else
00264             {
00265                 PyErr_SetString(PyExc_TypeError, "Cannot convert key to appropriate type");
00266                 return 1;
00267             }
00268             return 0;
00269         }
00270         else
00271         {
00272             typename M::key_type cppKey;
00273             typename M::mapped_type cppData;
00274             int rk = PyExportTraits<typename M::key_type>::get( iKey, cppKey );
00275             if (rk)
00276             {
00277                 PyErr_SetString(PyExc_TypeError, "Cannot convert key to appropriate type");
00278                 return 1;
00279             }
00280             int rv = PyExportTraits<typename M::mapped_type>::get( iData, cppData );
00281             if (rv)
00282             {
00283                 PyErr_SetString(PyExc_TypeError, "Cannot convert data to appropriate type");
00284                 return 1;
00285             }
00286             map_->insert(typename M::value_type(cppKey,cppData));
00287             return 0;
00288         }
00289     }
00290 
00291     template<typename M>
00292     std::string PyMapImpl<M>::pyStr( void)
00293     {
00294         LASS_ASSERT(map_);
00295         return  pyRepr();
00296     }
00297 
00298     template<typename M>
00299     std::string PyMapImpl<M>::pyRepr( void)
00300     {
00301         LASS_ASSERT(map_);
00302         return util::stringCast<std::string>(*map_);
00303     }
00304 
00305 }
00306 
00307 
00308 
00309 
00310 /** @ingroup Python
00311  *  @internal
00312  */
00313 template <typename ContainerType>
00314 struct PyExportTraitsMap
00315 {
00316     typedef ContainerType TContainer;
00317 
00318     /*  build a copy of a container as a Python dictionary  
00319      *  @note the constructed dictionary is made read only.
00320      *  @note a completely fresh copy of the container is made, so it's perfectly safe to use this
00321      *  to cast temporary function return values to Python.
00322      */
00323     static PyObject* build( const TContainer& iV )
00324     {
00325         return new impl::PyMap(iV);
00326     }
00327 
00328     /** wrap a "borrowed" container as Python dictionary
00329      *  @note you build a reference to the container, any changes done in Python
00330      *  will be reflected in the original object, as far as the typesystem allows it of course
00331      *  @warning holding a reference to the dictionary, while the original container is destroyed is a 
00332      *  not-so-good-idea.
00333      */
00334     static PyObject* build( TContainer& iV )
00335     {
00336         return new impl::PyMap(iV);
00337     }
00338 
00339     static int get( PyObject* iV, TContainer& oV )
00340     {
00341         if (!PyMapping_Check(iV))
00342         {
00343             PyErr_SetString(PyExc_TypeError, "python object doens't provide mapping protocol");
00344             return 1;
00345         }
00346         // check if we have our own PyMap object, then take a shortcut
00347         if (impl::isOfType(iV, &impl::PyMap::_lassPyType) && ((impl::PyMap*)iV)->pointsToSameContainer(oV))
00348         {
00349             return 0;
00350         }
00351         else
00352         {
00353             TContainer result;
00354             const Py_ssize_t size = PyMapping_Length(iV);
00355             TPyObjPtr items(PyMapping_Items(iV));
00356             if (!items)
00357             {
00358                 return 1;
00359             }
00360             LASS_ASSERT(PySequence_Size(items.get()) == size);
00361             PyObject** pairs = PySequence_Fast_ITEMS(items.get());
00362             for (Py_ssize_t i = 0; i < size; ++i)
00363             {
00364                 typename TContainer::key_type key;
00365                 typename TContainer::mapped_type mapped;
00366                 if (decodeTuple(pairs[i], key, mapped) != 0)
00367                 {
00368                     impl::addMessageHeader("map");
00369                     return 1;
00370                 }
00371                 result[key] = mapped;
00372             }
00373             oV.swap(result);
00374         }
00375         return 0;
00376     }
00377 };
00378 
00379 /** @ingroup Python
00380  *  @internal
00381  */
00382 template< typename K, typename V, typename P, typename A>
00383 struct PyExportTraits< std::map<K, V, P, A> >:
00384     public PyExportTraitsMap< std::map<K, V, P, A> >
00385 {
00386 };
00387 
00388 }
00389 
00390 }
00391 
00392 #endif

Generated on Mon Nov 10 14:21:05 2008 for Library of Assembled Shared Sources by doxygen 1.5.7.1
SourceForge.net Logo