From a8d2e3cc26a8562bc0c3482e6db7cba13518f287 Mon Sep 17 00:00:00 2001 From: Raoul Gough Date: Wed, 10 Sep 2003 15:36:45 +0000 Subject: [PATCH] C++ interface to iterable Python objects [SVN r1524] --- .../python/suite/indexing/python_iterator.cpp | 172 ++++++++++++++++++ .../python/suite/indexing/python_iterator.hpp | 71 ++++++++ 2 files changed, 243 insertions(+) create mode 100755 include/boost/python/suite/indexing/python_iterator.cpp create mode 100755 include/boost/python/suite/indexing/python_iterator.hpp diff --git a/include/boost/python/suite/indexing/python_iterator.cpp b/include/boost/python/suite/indexing/python_iterator.cpp new file mode 100755 index 00000000..1dd81112 --- /dev/null +++ b/include/boost/python/suite/indexing/python_iterator.cpp @@ -0,0 +1,172 @@ +// -*- mode:c++ -*- +// +// Module python_iterator.cpp +// +// Copyright (c) 2003 Raoul M. Gough +// +// This material is provided "as is", with absolutely no warranty expressed +// or implied. Any use is at your own risk. +// +// Permission to use or copy this material for any purpose is hereby +// granted without fee, provided the above notices are retained on all +// copies. Permission to modify the material and to distribute modified +// versions is granted, provided the above notices are retained, and a +// notice that the material was modified is included with the above +// copyright notice. +// +// History +// ======= +// 2003/ 9/10 rmg File creation +// +// $Id$ +// + +#include "python_iterator.hpp" + +//////////////////////////////////////////////////////////////////////////// +// python_iterator factory +/////////////////////////////////////////////////////////////////////////// + +std::auto_ptr +indexing::make_iterator (boost::python::object temp) +{ + std::auto_ptr result; + + try + { + result.reset (new python_iter_iterator (temp)); + } + + catch (boost::python::error_already_set const &) + { + PyErr_Clear (); + + try + { + result.reset (new python_getitem_iterator (temp)); + } + + catch (boost::python::error_already_set const &) + { + PyErr_Clear (); + } + } + + return result; +} + +//////////////////////////////////////////////////////////////////////////// +// Base class (virtual) destructor +/////////////////////////////////////////////////////////////////////////// + +indexing::python_iterator::~python_iterator () +{ +} + +//////////////////////////////////////////////////////////////////////////// +// python_getitem_iterator constructor +/////////////////////////////////////////////////////////////////////////// + +indexing::python_getitem_iterator +::python_getitem_iterator (boost::python::object obj) + : mGetitemMethod (obj.attr ("__getitem__")) + , mIndex (0) + , mCurrent() +{ +} + +//////////////////////////////////////////////////////////////////////////// +// Get our next item (if any) +/////////////////////////////////////////////////////////////////////////// + +bool indexing::python_getitem_iterator::next () +{ + bool result = true; // Assume success + + try + { + mCurrent = mGetitemMethod (mIndex); + ++mIndex; + } + + catch (boost::python::error_already_set const &) + { + if (PyErr_ExceptionMatches (PyExc_IndexError)) + { + // Eat this exception + PyErr_Clear (); + mCurrent = boost::python::object (); + result = false; + } + + else + { + // Pass it up the line + throw; + } + } + + return result; +} + +//////////////////////////////////////////////////////////////////////////// +// Return our current item +/////////////////////////////////////////////////////////////////////////// + +boost::python::object indexing::python_getitem_iterator::current () const +{ + return mCurrent; +} + +//////////////////////////////////////////////////////////////////////////// +// python_iter_iterator constructor +/////////////////////////////////////////////////////////////////////////// + +indexing::python_iter_iterator +::python_iter_iterator (boost::python::object obj) + : mNextMethod (obj.attr ("__iter__")().attr ("next")) + , mCurrent() +{ +} + +//////////////////////////////////////////////////////////////////////////// +// Get our next item (if any) +/////////////////////////////////////////////////////////////////////////// + +bool indexing::python_iter_iterator::next () +{ + bool result = true; // Assume success + + try + { + mCurrent = mNextMethod (); + } + + catch (boost::python::error_already_set const &) + { + if (PyErr_ExceptionMatches (PyExc_StopIteration)) + { + // Eat this exception + PyErr_Clear (); + mCurrent = boost::python::object (); + result = false; + } + + else + { + // Pass it up the line + throw; + } + } + + return result; +} + +//////////////////////////////////////////////////////////////////////////// +// Return our current item +/////////////////////////////////////////////////////////////////////////// + +boost::python::object indexing::python_iter_iterator::current () const +{ + return mCurrent; +} diff --git a/include/boost/python/suite/indexing/python_iterator.hpp b/include/boost/python/suite/indexing/python_iterator.hpp new file mode 100755 index 00000000..d1fcf41c --- /dev/null +++ b/include/boost/python/suite/indexing/python_iterator.hpp @@ -0,0 +1,71 @@ +// -*- mode:c++ -*- +// +// Header file python_iterator.hpp +// +// Handy Python iterable iterators +// +// Copyright (c) 2003 Raoul M. Gough +// +// This material is provided "as is", with absolutely no warranty expressed +// or implied. Any use is at your own risk. +// +// Permission to use or copy this material for any purpose is hereby +// granted without fee, provided the above notices are retained on all +// copies. Permission to modify the material and to distribute modified +// versions is granted, provided the above notices are retained, and a +// notice that the material was modified is included with the above +// copyright notice. +// +// History +// ======= +// 2003/ 9/10 rmg File creation +// +// $Id$ +// + +#ifndef python_iterator_rmg_20030910_included +#define python_iterator_rmg_20030910_included + +#include +#include + +namespace indexing { + struct python_iterator + { + virtual ~python_iterator (); + virtual bool next () = 0; + virtual boost::python::object current() const = 0; + }; + + std::auto_ptr make_iterator (boost::python::object); + // Returns null auto_ptr if object does not provide __iter__ nor + // __getitem__, otherwise a pointer to a suitable implementation of + // python_iterator + + struct python_getitem_iterator : public python_iterator + { + public: + python_getitem_iterator (boost::python::object); + virtual bool next (); + virtual boost::python::object current() const; + + private: + boost::python::object mGetitemMethod; + int mIndex; + boost::python::object mCurrent; + }; + + struct python_iter_iterator : public python_iterator + { + public: + python_iter_iterator (boost::python::object); + virtual bool next (); + virtual boost::python::object current() const; + + private: + boost::python::object mNextMethod; + boost::python::object mCurrent; + }; +} + +#endif // python_iterator_rmg_20030910_included