library of assembled shared sources

http://lass.cocamware.com

pysequence.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_PYSEQUENCE_H
00048 #define LASS_GUARDIAN_OF_INCLUSION_UTIL_PYSEQUENCE_H
00049 
00050 #include "util_common.h"
00051 #include "pyobject_plus.h"
00052 #include "pyobject_util.h"
00053 #include "string_cast.h"
00054 #include "../stde/extended_algorithm.h"
00055 
00056 #include <vector>
00057 #include <list>
00058 #include <deque>
00059 #include "../stde/static_vector.h"
00060 
00061 namespace lass
00062 {
00063 namespace python
00064 {
00065 
00066 namespace impl
00067 {
00068 
00069     template<typename C>
00070     struct ContainerTraits
00071     {
00072         static const typename C::value_type&        element_at(const C& iC, Py_ssize_t i) { return iC[i]; };
00073         static typename C::value_type&              element_at(C& iC, Py_ssize_t i) { return iC[i]; };
00074         static typename C::const_iterator           const_iterator_at(const C& iC, Py_ssize_t i) { return iC.begin()+i; };
00075         static typename C::iterator                 iterator_at(C& iC, Py_ssize_t i) { return iC.begin()+i; };
00076         static void reserve(C& /*iC*/, int /*iAmount*/)     {};
00077     };
00078 
00079     template<typename C, typename A>
00080     struct ContainerTraits<std::vector<C, A> > 
00081     {
00082         static const typename std::vector<C, A>::value_type&        element_at(const std::vector<C, A>& iC, Py_ssize_t i) { return iC[i]; };
00083         static typename std::vector<C, A>::value_type&              element_at(std::vector<C, A>& iC, Py_ssize_t i) { return iC[i]; };
00084         static typename std::vector<C, A>::const_iterator           const_iterator_at(const std::vector<C, A>& iC, Py_ssize_t i) { return iC.begin()+i; };
00085         static typename std::vector<C, A>::iterator                 iterator_at(std::vector<C, A>& iC, Py_ssize_t i) { return iC.begin()+i; };
00086         static void reserve(std::vector<C, A>& iC, int iAmount)     {iC.reserve(iAmount);};
00087     };
00088 
00089 
00090     template<typename C, typename A>
00091     struct ContainerTraits<std::list<C, A> >
00092     {
00093         static const C& element_at(const std::list<C,A>& iC, Py_ssize_t i) { return *const_iterator_at(iC,i); };
00094         static C& element_at(std::list<C,A>& iC, Py_ssize_t i) { return *iterator_at(iC,i); };
00095         static typename std::list<C, A>::const_iterator const_iterator_at(const std::list<C,A>& iC, Py_ssize_t i) 
00096         { 
00097             typename std::list<C,A>::const_iterator it = iC.begin();
00098             for (Py_ssize_t j=0;j<i;++j)
00099                 ++it;
00100             return it;
00101         };
00102         static typename std::list<C, A>::iterator   iterator_at(std::list<C,A>& iC, Py_ssize_t i) 
00103         { 
00104             typename std::list<C,A>::iterator it = iC.begin();
00105             for (Py_ssize_t j=0;j<i;++j)
00106                 ++it;
00107             return it;
00108         };
00109         static void reserve(std::list<C, A>& /*iC*/, int /*iAmount*/)       {};
00110     };
00111 
00112 
00113 
00114     class LASS_DLL PySequenceImplBase
00115     {
00116     public:
00117         PySequenceImplBase() {};
00118         virtual ~PySequenceImplBase() {};
00119         virtual void clear() = 0;
00120         virtual void reserve(int iAmount) = 0;
00121 
00122 
00123         virtual Py_ssize_t PySequence_Length() = 0;
00124         virtual PyObject* PySequence_Concat(PyObject *bb) = 0;
00125         virtual PyObject* PySequence_Repeat(Py_ssize_t n) = 0;
00126         virtual PyObject* PySequence_Item(Py_ssize_t i) = 0;
00127         virtual PyObject* PySequence_Slice(Py_ssize_t ilow, Py_ssize_t ihigh) = 0;
00128         virtual int PySequence_AssItem(Py_ssize_t i, PyObject *v) = 0;
00129         virtual int PySequence_AssSlice(Py_ssize_t ilow, Py_ssize_t ihigh, PyObject *v) = 0;
00130         virtual int PySequence_Contains(PyObject *el) = 0;
00131         virtual int PySequence_InplaceConcat(PyObject *other) = 0;
00132         virtual int PySequence_InplaceRepeat(Py_ssize_t n) = 0;
00133         virtual void append(PyObject* i) = 0;
00134         virtual TPyObjPtr pop(int i) = 0;
00135         virtual bool pointsToSameContainer(void* iO) = 0;
00136         virtual std::string pyStr(void) = 0;
00137         virtual std::string pyRepr(void) = 0;
00138     };
00139 
00140     template<typename Container>
00141     struct ContainerNotOwned
00142     {
00143         typedef Container* ContainerPtr;
00144         static  void dispose(ContainerPtr /*ioC*/) {};
00145     };
00146     template<typename Container>
00147     struct ContainerOwned
00148     {
00149         typedef Container* ContainerPtr;
00150         static  void dispose(ContainerPtr ioC) {delete ioC;};
00151     };
00152 
00153     template<typename Container, typename ContainerOwnerShipPolicy = ContainerNotOwned<Container> > 
00154     class PySequenceContainer : public PySequenceImplBase
00155     {
00156     public:
00157         PySequenceContainer(typename ContainerOwnerShipPolicy::ContainerPtr iC, bool iReadOnly = false) : cont_(iC), readOnly_(iReadOnly) {}
00158         virtual ~PySequenceContainer() { ContainerOwnerShipPolicy::dispose(cont_); }
00159         virtual void clear();
00160         virtual void reserve(int iAmount);
00161 
00162         virtual Py_ssize_t PySequence_Length();
00163         virtual PyObject* PySequence_Concat(PyObject *bb);
00164         virtual PyObject* PySequence_Repeat(Py_ssize_t n);
00165         virtual PyObject* PySequence_Item(Py_ssize_t i);
00166         virtual PyObject* PySequence_Slice(Py_ssize_t ilow, Py_ssize_t ihigh);
00167         virtual int PySequence_AssItem(Py_ssize_t i, PyObject *v);
00168         virtual int PySequence_AssSlice(Py_ssize_t ilow, Py_ssize_t ihigh, PyObject *v);
00169         virtual int PySequence_Contains(PyObject *el);
00170         virtual int PySequence_InplaceConcat(PyObject *other);
00171         virtual int PySequence_InplaceRepeat(Py_ssize_t n);
00172         virtual void append(PyObject* i);
00173         virtual TPyObjPtr pop(int i);
00174         virtual bool pointsToSameContainer(void* iO) 
00175         { 
00176             return (iO == (void*)cont_);
00177         }
00178         virtual std::string pyStr(void);
00179         virtual std::string pyRepr(void);
00180     private:
00181         typename ContainerOwnerShipPolicy::ContainerPtr cont_;
00182         bool readOnly_;
00183     };
00184 
00185     /** PySequence.  Object for interfacing sequence-like objects with Python 
00186     */
00187     class LASS_DLL PySequence : public PyObjectPlus
00188     {
00189         PY_HEADER(PyObjectPlus);
00190         static PySequenceMethods pySequenceMethods;
00191         static bool isInitialized;
00192 
00193     public:
00194         template<typename Container> PySequence( Container& iCont )
00195         {
00196             initialize();
00197             impl::fixObjectType(this);
00198             pimpl_ = new PySequenceContainer<Container>(&iCont);
00199         }
00200         template<typename Container> PySequence( const Container& iCont ) 
00201         {
00202             initialize();
00203             impl::fixObjectType(this);
00204             pimpl_ = new PySequenceContainer<Container>(const_cast<Container*>(&iCont),true);
00205         }
00206         //PySequence( PyObject* iP );
00207         virtual ~PySequence();
00208         virtual std::string doPyStr(void)       { return pimpl_->pyStr(); }
00209         virtual std::string doPyRepr(void)  { return pimpl_->pyRepr(); }
00210         virtual void append(PyObject* i)    { pimpl_->append(i); }
00211         virtual void clear()                { pimpl_->clear(); }
00212         virtual void reserve(int iAmount)   { pimpl_->reserve(iAmount); }
00213         virtual TPyObjPtr pop(int i)        { return pimpl_->pop(i); }
00214 
00215         //static PyObject* PySequence_ListIter(PyObject* iPO);
00216 
00217         static Py_ssize_t PySequence_Length( PyObject* iPO);
00218         static PyObject* PySequence_Concat(PyObject *a, PyObject *bb);
00219         static PyObject* PySequence_Repeat(PyObject *a, Py_ssize_t n);
00220         static PyObject* PySequence_Item(PyObject*a, Py_ssize_t i);
00221         static PyObject* PySequence_Slice(PyObject *a, Py_ssize_t ilow, Py_ssize_t ihigh);
00222         static int PySequence_AssItem(PyObject *a, Py_ssize_t i, PyObject *v);
00223         static int PySequence_AssSlice(PyObject *a, Py_ssize_t ilow, Py_ssize_t ihigh, PyObject *v);
00224         static int PySequence_Contains(PyObject *a, PyObject *el);
00225         static PyObject * PySequence_InplaceConcat(PyObject *self, PyObject *other);
00226         static PyObject * PySequence_InplaceRepeat(PyObject *self, Py_ssize_t n);
00227 
00228         template<typename Container> bool pointsToSameContainer(Container& iO) 
00229         { 
00230             return pimpl_->pointsToSameContainer(&iO);
00231         }
00232     private:
00233         PySequence();
00234         PySequenceImplBase* pimpl_;
00235         static void initialize();
00236     };
00237 
00238     template <typename Sequence>
00239     int pyGetSequenceObject( PyObject* iValue, Sequence& oV )
00240     {
00241         if (!PySequence_Check(iValue))
00242         {
00243             PyErr_SetString(PyExc_TypeError, "not a python sequence");
00244             return 1;
00245         }
00246         // check if we have our own PySequence object, then take a shortcut
00247         if (isOfType(iValue, &PySequence::_lassPyType) && ((PySequence*)iValue)->pointsToSameContainer(oV))
00248         {
00249             return 0;
00250         }
00251         else
00252         {
00253             Sequence result;
00254             const Py_ssize_t size = PySequence_Length(iValue);
00255             for (Py_ssize_t i = 0; i < size; ++i)
00256             {
00257                 typename Sequence::value_type temp;
00258                 if (PyExportTraits<typename Sequence::value_type>::get( PySequence_ITEM(iValue, i) , temp ) != 0)
00259                 {
00260                     impl::addMessageHeader(
00261                         std::string("sequence element ") + util::stringCast<std::string>(i));
00262                     return 1;
00263                 }
00264                 result.push_back( temp );
00265             }
00266             oV.swap(result);
00267         }
00268         return 0;
00269     }
00270 
00271 
00272     template<typename Container, typename ContainerOwnerShipPolicy>
00273     void PySequenceContainer<Container, ContainerOwnerShipPolicy>::clear()
00274     {
00275         cont_->clear();
00276     }
00277     template<typename Container, typename ContainerOwnerShipPolicy>
00278     void PySequenceContainer<Container, ContainerOwnerShipPolicy>::reserve(int iAmount)
00279     {
00280         ContainerTraits<Container>::reserve(*cont_,iAmount);
00281     }
00282     template<typename Container, typename ContainerOwnerShipPolicy>
00283     Py_ssize_t PySequenceContainer<Container,ContainerOwnerShipPolicy>::PySequence_Length()
00284     {
00285         const Py_ssize_t size = static_cast<Py_ssize_t>(cont_->size());
00286         LASS_ASSERT(size >= 0);
00287         return size;
00288     }
00289     template<typename Container, typename ContainerOwnerShipPolicy>
00290     PyObject* PySequenceContainer<Container,ContainerOwnerShipPolicy>::PySequence_Concat(PyObject *bb)
00291     {
00292         Container toConcat;
00293         int r = pyGetSequenceObject(bb,toConcat);
00294         if (r)
00295         {
00296             PyErr_SetString(PyExc_TypeError, "Cannot convert to concatenation type");
00297             return NULL;
00298         }
00299         Container result(*cont_);
00300         result.insert(result.end(), toConcat.begin(), toConcat.end());
00301         return fromSharedPtrToNakedCast(pyBuildList(result.begin(),result.end()));
00302     }
00303     template<typename Container, typename ContainerOwnerShipPolicy>
00304     PyObject* PySequenceContainer<Container,ContainerOwnerShipPolicy>::PySequence_Repeat(Py_ssize_t n)
00305     {
00306         Container result = stde::repeat_c(*cont_,n);
00307         return fromSharedPtrToNakedCast(pyBuildList(result.begin(),result.end()));
00308     }
00309     template<typename Container, typename ContainerOwnerShipPolicy>
00310     PyObject* PySequenceContainer<Container,ContainerOwnerShipPolicy>::PySequence_Item(Py_ssize_t i)
00311     {
00312         const Py_ssize_t size = static_cast<Py_ssize_t>(cont_->size());
00313         LASS_ASSERT(size >= 0);
00314 
00315         if (i<0 || i>=size)
00316         {
00317             PyErr_SetString(PyExc_IndexError, "Index out of bounds");
00318             return NULL;
00319         }
00320         return lass::python::PyExportTraits< typename Container::value_type >::build( ContainerTraits<Container>::element_at(*cont_,i));
00321     }
00322     template<typename Container, typename ContainerOwnerShipPolicy>
00323     PyObject* PySequenceContainer<Container,ContainerOwnerShipPolicy>::PySequence_Slice(Py_ssize_t ilow, Py_ssize_t ihigh)
00324     {
00325         const Py_ssize_t size = static_cast<Py_ssize_t>(cont_->size());
00326         LASS_ASSERT(size >= 0);
00327 
00328         Py_ssize_t len;
00329         if (ilow < 0)
00330             ilow = 0;
00331         else if (ilow > size)
00332             ilow = size;
00333         if (ihigh < ilow)
00334             ihigh = ilow;
00335         else if (ihigh > size)
00336             ihigh = size;
00337         len = ihigh - ilow;
00338         return fromSharedPtrToNakedCast(pyBuildList(
00339             ContainerTraits<Container>::const_iterator_at(*cont_,ilow),
00340             ContainerTraits<Container>::const_iterator_at(*cont_,ilow+len) ));
00341     }
00342     template<typename Container, typename ContainerOwnerShipPolicy>
00343     int PySequenceContainer<Container,ContainerOwnerShipPolicy>::PySequence_AssItem(Py_ssize_t i, PyObject *v)
00344     {
00345         if (readOnly_)
00346         {
00347             PyErr_SetString(PyExc_TypeError, "Sequence is read-only");
00348             return -1;
00349         }
00350         if (i < 0 || i >= PySequence_Length()) 
00351         {
00352             PyErr_SetString(PyExc_IndexError,"list assignment index out of range");
00353             return -1;
00354         }
00355         if (v == NULL)
00356             return PySequence_AssSlice(i, i+1, v);
00357         return PyExportTraits<typename Container::value_type>::get(v,ContainerTraits<Container>::element_at(*cont_,i));
00358     }
00359     template<typename Container, typename ContainerOwnerShipPolicy>
00360     int PySequenceContainer<Container,ContainerOwnerShipPolicy>::PySequence_AssSlice(Py_ssize_t ilow, Py_ssize_t ihigh, PyObject *v)
00361     {
00362         if (readOnly_)
00363         {
00364             PyErr_SetString(PyExc_TypeError, "Sequence is read-only");
00365             return -1;
00366         }
00367         Container temp;
00368         int r = pyGetSequenceObject(v,temp);
00369         if (r)
00370         {
00371             PyErr_SetString(PyExc_TypeError, "Cannot convert to type for slice assignment");
00372             return -1;
00373         }
00374         cont_->erase(   ContainerTraits<Container>::iterator_at(*cont_,ilow),
00375                         ContainerTraits<Container>::iterator_at(*cont_,ihigh) );
00376         cont_->insert(  ContainerTraits<Container>::iterator_at(*cont_,ilow+1),
00377                         temp.begin(),temp.end());
00378         return 0;
00379     }
00380     template<typename Container, typename ContainerOwnerShipPolicy>
00381     int PySequenceContainer<Container,ContainerOwnerShipPolicy>::PySequence_Contains(PyObject *el)
00382     {
00383         typename Container::value_type temp;
00384         int r = PyExportTraits<typename Container::value_type>::get(el,temp);
00385         if (r)
00386         {
00387             // type is not convertible and hence is not found
00388             // this corresponds to the Python behavior
00389             return 0;
00390         }
00391         if (std::find(cont_->begin(),cont_->end(),temp)!=cont_->end())
00392             return 1;
00393         return 0;
00394     }
00395     template<typename Container, typename ContainerOwnerShipPolicy>
00396     int PySequenceContainer<Container,ContainerOwnerShipPolicy>::PySequence_InplaceConcat(PyObject *other)
00397     {
00398         if (readOnly_)
00399         {
00400             PyErr_SetString(PyExc_TypeError, "Sequence is read-only");
00401             return -1;
00402         }
00403         Container toConcat;
00404         //int r = pyGetSimpleObject(other,toConcat);
00405         int r = pyGetSequenceObject(other,toConcat);
00406         if (r)
00407         {
00408             PyErr_SetString(PyExc_TypeError, "Cannot convert to concatenation type");
00409             return 1;
00410         }
00411         cont_->insert(cont_->end(), toConcat.begin(), toConcat.end());
00412         return 0;
00413     }
00414     template<typename Container, typename ContainerOwnerShipPolicy>
00415     int PySequenceContainer<Container,ContainerOwnerShipPolicy>::PySequence_InplaceRepeat(Py_ssize_t n)
00416     {
00417         if (readOnly_)
00418         {
00419             PyErr_SetString(PyExc_TypeError, "Sequence is read-only");
00420             return -1;
00421         }
00422         stde::inplace_repeat_c(*cont_,n);
00423         return 0;
00424     }
00425     template<typename Container, typename ContainerOwnerShipPolicy>
00426     void PySequenceContainer<Container,ContainerOwnerShipPolicy>::append(PyObject* i)
00427     {
00428         if (readOnly_)
00429         {
00430             PyErr_SetString(PyExc_TypeError, "Sequence is read-only");
00431             return;
00432         }
00433         typename Container::value_type temp;
00434         int r = PyExportTraits<typename Container::value_type>::get(i,temp);
00435         if (r)
00436         {
00437             PyErr_SetString(PyExc_TypeError, "Cannot convert to append type");
00438             return;
00439         }
00440         cont_->push_back( temp );
00441     }
00442     template<typename Container, typename ContainerOwnerShipPolicy>
00443     TPyObjPtr PySequenceContainer<Container,ContainerOwnerShipPolicy>::pop(int i)
00444     {
00445         if (readOnly_)
00446         {
00447             PyErr_SetString(PyExc_TypeError, "Sequence is read-only");
00448             return TPyObjPtr();
00449         }
00450         typename Container::value_type temp = ContainerTraits<Container>::element_at(*cont_,i);
00451         cont_->erase(ContainerTraits<Container>::iterator_at(*cont_,i));
00452         return fromNakedToSharedPtrCast<PyObject>(lass::python::PyExportTraits<typename Container::value_type>::build(temp));
00453     }
00454 
00455     template<typename Container, typename ContainerOwnerShipPolicy>
00456     std::string PySequenceContainer<Container,ContainerOwnerShipPolicy>::pyStr( void)
00457     {
00458         return pyRepr();
00459     }
00460 
00461     template<typename Container, typename ContainerOwnerShipPolicy>
00462     std::string PySequenceContainer<Container,ContainerOwnerShipPolicy>::pyRepr( void)
00463     {
00464         return util::stringCast<std::string>(*cont_);
00465     }
00466 }
00467 
00468 
00469 
00470 /** @ingroup Python
00471  *  @internal
00472  */
00473 template <typename ContainerType>
00474 struct PyExportTraitsSequence
00475 {
00476     typedef ContainerType TContainer;
00477 
00478     /*  build a copy of a container as a Python tuple
00479      *  @note you get a read-only COPY of the container
00480      */
00481     static PyObject* build( const TContainer& iV) 
00482     { 
00483         return fromSharedPtrToNakedCast(impl::pyBuildTuple(iV.begin(),iV.end()));
00484     }
00485 
00486     /** expose a container to python as a reference.
00487      *  @note you build a reference to the container, any changes done in Python
00488      *  will be reflected in the original object, as far as the typesystem allows it of course
00489      */
00490     static PyObject* build(TContainer& iV) 
00491     { 
00492         return new impl::PySequence(iV);
00493     }
00494 
00495     /** get a copy of a Python sequence as a container.
00496      *  @note you get a COPY of the sequence, not the original sequence itself!
00497      */
00498     static int get( PyObject* iV, TContainer& oV) 
00499     { 
00500         return impl::pyGetSequenceObject(iV, oV);
00501     }
00502 };
00503 
00504 /** @ingroup Python
00505  *  @internal
00506  */
00507 template< typename C, typename A>
00508 struct PyExportTraits< std::vector< C, A > >:
00509     public PyExportTraitsSequence< std::vector< C, A > >
00510 {
00511 };
00512 
00513 /** @ingroup Python
00514  *  @internal
00515  */
00516 template< typename C, typename A>
00517 struct PyExportTraits< std::list< C, A > >:
00518     public PyExportTraitsSequence< std::list< C, A > >
00519 {
00520 };
00521 
00522 /** @ingroup Python
00523  *  @internal
00524  */
00525 template< typename C, typename A>
00526 struct PyExportTraits< std::deque< C, A > >:
00527     public PyExportTraitsSequence< std::deque< C, A > >
00528 {
00529 };
00530 
00531 /** @ingroup Python
00532  *  @internal
00533  */
00534 template< typename C, size_t maxsize>
00535 struct PyExportTraits< stde::static_vector< C, maxsize > >:
00536     public PyExportTraitsSequence< stde::static_vector< C, maxsize > >
00537 {
00538 };
00539 
00540 
00541 }
00542 
00543 }
00544 
00545 #endif

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