26 February 2010

Vim: strip trailing whitespace on write

Git is picky about leave trailing whitespace (spaces at the end of a line) in your code. To keep it from being a problem, I modified some helpful scripts to my exacting specifications: it will notify you if it replaces trailing whitespace, it won't change your cursor position, and it won't affect innocent bystander files. Add it to your $HOME/.vim/ftplugin/cpp.vim ftplugin file.

" automatically remove trailing whitespace before write
function! StripTrailingWhitespace()
  normal mZ
  %s/\s\+$//e
  if line("'Z") != line(".")
    echo "Stripped whitespace\n"
  endif
  normal `Z
endfunction
autocmd BufWritePre *.cpp,*.hpp,*.i :call StripTrailingWhitespace()

I like Vim, but I despise Vimscript. Trying to get it to do exactly what I want takes so much guessing and consequently far too much time.

17 February 2010

SWIG iterators and generators, continued

This is a continuation of my previous post on Python generators with SWIG. I've improved the code, added an iterator class so that the same generator method can be called multiple times concurrently, and added a couple of macros to allow easy instantiation of the SWIG code.

A SWIG file (use with the %include directive) is available for download, and further updates will be posted on my projects page.

As an example of how this would be used, see an excerpt of a 2D diffusion input file that uses my mesh library:

for c in mesh.cells():
    source[c] = max(  math.cos( c.getCenter()[0] / 2 * math.pi )
                    + math.cos( c.getCenter()[1] / 2 * math.pi ),
                  0)

UPDATE 4/25/2011: my project that uses this file is now posted on github.

15 February 2010

Easy Python generators using SWIG

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.