In my research code, I have a number of classes that act as wrappers for containers, and they provide begin
and end
functions. I want an easy way to provide a generator for looping over these embedded containers. Because of the way SWIG's STL wrappers work, it's not (easily?) possible to wrap a vector of pointers, and we'd like to avoid all the extra overhead those wrappers have anyway: all we need is a way to increment a pointer and to tell if it's at the end.
So, my solution is to create a thin wrapper for only the increment operator ++
, and extend the class with a function to return the "beginning" iterator and to check whether the iterator is at the end position.
For this particular instance, I have a class Mesh
that has methods for beginLeftBoundaryFaces
and endLeftBoundaryFaces
—which return STL vector iterators that point to a Face *
.
%inline %{
//! Thin wrapper for ONLY the increment operator
void _bfiter_incr( std::vector<Face *>::const_iterator* iter )
{
// increment the iterator
++(*iter);
}
%}
%extend Mesh {
%insert("python") %{
def left_boundary_faces(self):
"A generator to iterate through boundary faces."
faceIter = self._beginLeftBoundaryFaces()
keepLooping = True
while keepLooping == True:
face = self._bfiter_dereference_Left( faceIter )
if face:
_bfiter_incr( faceIter )
yield face
else:
keepLooping = False
%}
//! get the first element in the vector
std::vector<Face *>::const_iterator* _beginLeftBoundaryFaces()
{
return new std::vector<Face *>::const_iterator(
($self->beginLeftBoundaryFaces()) );
}
//! dereference the iterator; return NULL if at the end
const Face* _bfiter_dereference_Left(
const std::vector<Face *>::const_iterator* iter )
{
// if at the end, return NULL
if (*iter == ($self)->endLeftBoundaryFaces() ) {
return NULL;
}
// otherwise, return the face to which this iterator points
return **iter;
}
}
So now I can do:
for f in mesh.left_boundary_faces():
print f.area()
or, of course, anything else now that I'm using Python.
See further updates on the thin Python wrappers for C++ iterators.