00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
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
00114
00115 class LASS_DLL PyMap : public PyObjectPlus
00116 {
00117 PY_HEADER(PyObjectPlus);
00118 static PyMappingMethods pyMappingMethods;
00119
00120 public:
00121
00122
00123
00124
00125
00126
00127
00128
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
00311
00312
00313 template <typename ContainerType>
00314 struct PyExportTraitsMap
00315 {
00316 typedef ContainerType TContainer;
00317
00318
00319
00320
00321
00322
00323 static PyObject* build( const TContainer& iV )
00324 {
00325 return new impl::PyMap(iV);
00326 }
00327
00328
00329
00330
00331
00332
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
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
00380
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