Monthly Archives: June 2012

vim: smart C/C++ boilerplate templates

A simple vim scriptie for those who are interested. It is triggered when new C/C++ files are created (e.g. via vim new-file.cxx), and fills it in with boilerplate unit code. What’s special about it is that it tries to find tips about that code in other files in that or parent directory.

The templates

The template used for .c/.cxx files is:

/* header-comment
 */

#ifdef HAVE_CONFIG_H
#	include "config.h"
#endif

While for .h/.hxx files the following is used:

/* header-comment
 */

#pragma once

#ifndef PREFIX_FN_H
#define PREFIX_FN_H 1

#endif /*PREFIX_FN_H*/

In order to simplify the work flow, the following magic is done:

  1. header-comment is actually copied from any other file with the same suffix,
  2. FN_H is substituted for actual filename,
  3. PREFIX is copied from any other file with the same suffix,
  4. if no file is found in the same directory as the new file, the scripts falls back to parent directory, and appends the subdirectory name to PREFIX.

The script

Just a dirty, quick vimrc. Feel free to improve:

function CTemplate()
  let fext = expand('%:e')
  let ucext = toupper(fext)
  let myprefix = substitute(toupper(expand('%')), '[^A-Z0-9]', '_', 'g')

  let head_done = 0
  let head_line = 0
  let prefix_done = 0

  if fext =~ '^h'
    call append(1, '#pragma once')
    call append(2, '')
    call append(3, '#ifndef @fn@')
    call append(4, '#define @fn@ 1')
    call append(5, '')
    call append(6, '#endif /*@fn@*/')
  else
    call append(1, '#ifdef HAVE_CONFIG_H')
    call append(2, '#  include "config.h"')
    call append(3, '#endif')
    let prefix_done = 1
  endif

  let mywd = expand("%:p:h")
  echo mywd
  let myfiles = glob(mywd . '/*.' . fext, 0, 1)
  let myfiles += glob(mywd . '/../*.' . fext, 0, 1)

  for myfile in myfiles
    if filereadable(myfile)
      for myline in readfile(myfile)
        if !head_done
          if head_line != 0
            call append(head_line, myline)
            if myline =~ '[*][/]'
              let head_done = 1
            else
              let head_line += 1
            endif
          endif

          if head_line == 0 && myline =~ '^[/][*]'
            call append(0, myline)
            let head_line += 1

            if myline =~ '[*][/]'
              let head_done = 1
            endif
          endif
        endif

        if !prefix_done && myline =~ '^#ifndef .*_'.ucext
          if myfile =~ '^../'
            let mydir = toupper(expand('%:p:h:t'))

            let myprefix = mydir . '_' . myprefix
          endif

          let myprefix = substitute(myline[8:],
            \ '[^_]*_[^_]*$', '', '') . myprefix
          let prefix_done = 1
        endif
      endfor
    endif

    if head_done && prefix_done
      break
    endif
  endfor

  if fext =~ '^h'
    exec '%s/@fn@/'.myprefix.'/'
  endif
endfunction

A C API for C++ and Python ones — or making of libh2o

Lately I spent a lot of time working on a small project of mine called libh2o. Its goal is to provide a library of routines implementing IAPWS IF97 equations for water and steam properties. With the core written in C, and providing a nice-to-use API for C++ and Python.

At first, I thought about not providing a «high level» C API at all. It was like: if you want to use plain C, you’ve gotta glue all the low-level equations yourself. However, after some thinking I decided to provide one, and built the two remaining APIs (C++ and Python) on top of it.

The main reason for doing this was that Python (well, CPython) is written in C. Although I’ve seen people writing Python extensions in C++, and even using some of C++ features to make them a little nicer, that’s still a bunch of ugly C hacks and pointer casts. I don’t see a really good reason to write a Python extension in C++, nor to make it depend on a C++ compiler when it’s all limited to C-based CPython API anyway.

And that means that I have either to duplicate all the high-level logic in the Python extension, or just create a C API first and reuse that. Since the whole logic was simple enough to be covered completely and clearly in C, I have chosen this way.

As it happens when people choose C, I had to implement some kind of poor man’s objectivity. Not something as wide (and ugly) as GObject (someone, please kill it!) but a few bits necessary to keep the state. In other words, a structure keeping the «object» and a bunch of nicely named functions taking it as their first argument.

Before I learnt C++, I would assume that the object structure should be a private (and obscured) blob, and the object type should be an incomplete pointer to it. User should just grab that pointer from a «constructor», pass it around and finally free it through a «destructor». Advantage: the exact struct contents are not the part of ABI.

But now I’ve decided to go the other way; way similar to how C++ classes work. I’ve created a structure with explicitly listed private fields (and a very simple /*private:*/ comment), and used that as the public type. It doesn’t need to keep any memory allocated, and is simple enough to be allocated on stack. Advantages: no need for a destructor, and an ability to pack that struct in the C++ class which will wrap it.

Then the usual stuff: a bunch of functions with common prefixes. One prefix for the «namespace», another one for the function (new, get…). All in nice and clear fashion, either to be used directly or wrapped in the C++ or Python APIs.