Category Archives: C++

Create ruby/jruby bindings of C++/C with ffi

Let’s start with the basic. What are bindings? It’s a way to call low level libraries (normally in C or C++) from another language (high level one, like ruby, java or whatever). This simple step requires two important things: 1) first, to know how we should call the method itself and 2) second, how to map the type from the high level language to C primitives types. To accomplish this, we have what is called foreign function interface which trivialize this task.

In ruby/jruby world we are gonna need ffi gem (jruby also has a compatible ffi gem), besides that the most important part is to have a clear interface in C. You can do bindings for a C++ library if you create a C interface first (because the bindings between C++ and C are free, the compiler knows how to do it by itself). So let’s cut the crap and write some code

First our C++ library which can be this few lines or thousands:

class awesome_object {
  public:
    awesome_object(int a, int b) : a_(a), b_(b) {}
 
    int awesome_method() {
      return a_ + b_;
    }
 
  protected:
    int a_, b_;
}

Now the C bindings which will be our façade for our c++ library:

extern "C" {
  typedef awesome_object_p void *;
 
  awesome_object_p create_awesome_object(int a, int b) {
    return static_cast<void *>(new awesome_object(a, b));
  }
 
  void delete_pointer_to_awesome_object(awesome_object_p p) {
    delete static_cast<awesome_object *>(p);
  }
 
  int awesome_method(awesome_object_p p) {
    awesome_object o = *static_cast<awesome_object *>(p);
    return o.awesome_method();
  }
}

Now ruby code that use ffi gem to be able to call the methods defined in C:

require 'ffi'
 
module AwesomeObject
  include FFI
  extend FFI::Library
  ffi_lib "libawesome.so" # .dll if you are in windows, it doesn't matter the OS
  attach_function "delete_pointer_to_awesome_object", "delete_pointer_to_awesome_object", [:pointer], :void
  attach_function "awesome_method", "awesome_method", [:pointer], :int
  attach_function "create_awesome_object", "create_awesome_object", [:int, :int], :pointer
end

With this you can use your C++ library from ruby code (I’d recommend package everything as a gem) just like this:

class MyTest
  include AwesomeObject
  def test!
    object = create_awesome_object(11, 31)
    awesome_method object
    delete_pointer_to_awesome_object object
  end
end
MyTest.new.test!

So, if you have read until now, probably you just want something working, say no more. Download this tar.gz, and see all this by yourself. In the tar you have the code split into c/h cpp/hpp files as it should be, in the post I’ve put all together to simplify things. Just execute make test and if you have ruby, ffi gem and g++ installed on your system, you’ll see something like:

$ make test
g++ -g -Wall -fPIC -c awesome_object.cpp
g++ -g -Wall -fPIC -c awesome.c
g++ -g -Wall -fPIC -shared -o libawesome.so awesome.o awesome_object.o
ruby test.rb
42

boost::asio, synchronous read with timeout

The boost::asio (which means asynchronous input/output) library, is quite powerful library for asynchronous i/o, but it could be a bit difficult at first to figure out how to do a normal synchronous read. So, as a reminder for my future-me, and for you, this snippet it’ll be very useful to accomplish that. Probably there will be another ways for doing that, but this is how I managed to do it:

using namespace boost::asio;
using namespace boost::system;
using boost::optional;
 
ip::tcp::socket _socket; // it could be another kind of socket, not only ip::tcp
 
/** 
 * Dumb function to be used as handler argument and save the error_code
 * into a pointer
 *
 * e.g.: boost::bind( &set_result, some_pointer, _1 )
 */
void set_result( optional<error_code>* a, error_code b ) 
{
  a->reset( b );
}
 
#define TIMEOUT 60
/**
 * it uses _socket 
 * if timeout happends throw a system_error exception
 */
template<typename MutableBufferSequence>
optional<error_code> read_with_timeout(
    const MutableBufferSequence& buffer
  ) throw( system_error )
{
  optional<error_code> timer_result;
  optional<error_code> read_result;
 
  deadline_timer timer( _socket.io_service() );
 
  timer.expires_from_now( seconds(TIMEOUT) );
  timer.async_wait( boost::bind(&set_result, &timer_result, _1) );
 
  boost::asio::async_read(
      _socket,
      buffer,
      boost::asio::transfer_at_least( buffer_size_helper(buffer) ),
      boost::bind( &set_result, &read_result, _1 )
    );
 
  _socket.io_service().reset();
 
  while ( _socket.io_service().run_one() )
  {
    if ( read_result )
    {
      timer.cancel();
    }
    else if ( timer_result )
    {
      _socket.cancel();
      throw system_error(
          error_code( errc::timed_out, get_generic_category() )            
        );
    }
  }
  return read_result;
}

I hope it will be useful, have fun.

C++, cadenas multilínea de forma clara

Según el estándar c++98 (sección 2.13.4) las cadenas literales tienen como propiedad que durante el análisis léxico del código fuente (la primera fase que realiza el compilador, convirtiendo texto de entrada a tokens y símbolos) se concatenarán cadenas adyacentes.

In translation phase 6 (2.1), adjacent narrow string literals are concatenated and adjacent wide string literals are concatenated.

Esto viene a decir que podemos partir nuestras cadenas en cualquier momento sin poner ningún signo de concatenación entre ellas, de esta forma:

const char s1* = "dum" "de" "dum";
const char s2* = "dum"
                 "de"
                 "dum"
;

Lo cual viene realmente bien para formar código bien indentado y formateado, pues aunque también podemos usar “\” para saltar de línea, el texto a continuación no puede estar indentado pues significaría incluir esos espacios/tabuladores en la cadena que estamos definiendo. Y lo realmente interesante es que todo esto está en la propia definición del lenguaje, no es ninguna ayuda concreta del compilador, a los ojos del programa todas las siguientes definiciones son idénticas:

#include <string>
#include <iostream>
 
const char * cmp( const char *s1, const char *s2 );
 
int main()
{
 
    const char * s1 = "My spoon is too big"
                      "My spoon is TOO BIG"
                      "I AM A BANANA";
    const char * s2 = "My spoon is too big\
My spoon is TOO BIG\
I AM A BANANA";
    const char * s3 = ( std::string("My spoon is too big") +
                        std::string("My spoon is TOO BIG") +
                        std::string("I AM A BANANA") ).c_str();
 
    std::cout << "s1 and s2 are " << cmp( s1, s2 ) << std::endl;
    std::cout << "s1 and s3 are " << cmp( s1, s3 ) << std::endl;
    std::cout << "s2 and s3 are " << cmp( s2, s3 ) << std::endl;
 
    return 0;
}
 
 
const char * cmp( const char *s1, const char *s2 );
{
    while( *s1 && *s2 && *s1++ == *s2++ );
    if ( ( *s1 != *s2 ) || ( *s1 || *s2 ) )
        return "different";
    return "equal";
}
$ c++ const_char_declaration_sample.cpp && ./a.out
s1 and s2 are equal
s1 and s3 are equal
s2 and s3 are equal

Librería de logging para C++, boost::logging

En C++ tienes diversas librerías de logging, la mayoría son clones de log4j realmente, u otras con un estilo diferente bastante interesante; pero como suele ser costumbre en el mundo C++, tienes una alternativa relacionada con las librerías boost (en realidad boost::logging no es de boost oficialmente, pero es más que probable que en el futuro lo sea) que suele ser la ganadora por méritos propios.

Estoy hablando de la implementación de John Torjo. Muy flexible a la hora de configurarla unido a un uso trivial de la misma (como tiene que ser, tampoco es que, la labor de logging, sea algo muy complejo que digamos…). Para conocer todos los detalles puedes leerte la extensa y útil documentación, aunque de primeras puede ser un tanto compleja debido a nuevos conceptos que se usan a diestro y siniestro.

Principalmente debemos de conocer dos cosas:

  • Qué tipo de filtro queremos: el cual será el encargado decidir si un mensaje se escribe o no, dependiendo tanto de si el logging está activado, como si cumplimos la restricción de nivel (debug, warn, error, etc…)
  • Qué tipo de log queremos: ¿cómo debe de ser el formato de salida?, ¿cuál es la salida/s? ¿cómo será su comportamiento?.

Una vez definido esto, podemos escribirnos un par de ficheros en los cuales definiremos el log que podrá ser usado desde cualquier parte de la aplicación, incluyendo el header, y siempre y cuando se haya inicializado previamente.

#ifndef __LOGGING_HPP__
#define __LOGGING_HPP__
 
#include <boost/logging/format_fwd.hpp>
 
using namespace boost::logging;
using namespace boost::logging::scenario::usage;
 
typedef use<
    filter_::change::single_thread, // how often does the filter change?
    filter_::level::no_levels,      // does the filter use levels?
    logger_::change::single_thread, // how often does the logger change?
    logger_::favor::correctness     // what does the logger favor?
  > finder;
 
BOOST_DECLARE_LOG_FILTER( g_log_filter, finder::filter )
BOOST_DECLARE_LOG( g_log, finder::logger )
 
#define L_ BOOST_LOG_USE_LOG_IF_FILTER( g_log(), g_log_filter()->is_enabled() )
 
void initialize_logs();
 
#endif // __LOGGING_HPP__

Aquí acabamos de declarar un log, sin niveles, para una aplicación simple sin usar un thread separado para el logging. Para ver otras alternativas puedes echarle un ojo a los namespaces boost::logging::scenario::usage::filter_ y boost::logging::scenario::usage::logger_.

Finalmente solo nos quedaría inicializar el log (o logs, recuerda que nada te impide tener tantos como quieras):

#include "logging.hpp"
#include <boost/logging/format_ts.hpp>
#include <boost/thread/xtime.hpp>
 
BOOST_DEFINE_LOG_FILTER( g_log_filter, finder::filter )
 
BOOST_DEFINE_LOG( g_log, finder::logger )
 
void initialize_logs()
{
  g_log()->writer().add_formatter( formatter::idx(), "[%] "  );
  g_log()->writer().add_formatter( formatter::time("$hh:$mm.$ss ") );
  g_log()->writer().add_formatter( formatter::append_newline() );
 
  typedef detail::flag<destination::file_settings> flag;
  destination::file_settings file_settings;
  file_settings.initial_overwrite = flag::t<bool>( &file_settings, true );
  g_log()->writer().add_destination(
      destination::file( "app_debug.txt", file_settings )
    );
  g_log()->writer().add_destination(
      destination::cerr
    );
 
  g_log()->turn_cache_off(); // for showing output immediately
  g_log()->mark_as_initialized();
}

Aquí tenemos que hacer la definición del log y del filter de la misma forma que hemos hecho su declaración anteriormente. Definimos el formato de salida como más nos guste y finalmente solo nos queda indicar dónde se deben de escribir los mensajes. Se puede tener varios destinos, aunque básicamente podemos usar desde ficheros hasta cualquier stream, pasando por las salidas estándar (fíjate en los typedef de boost::logging:destination).

Una cosa importante que merece la pena mencionar es la llamada al método turn_cache_off(), especialmente importante si usas una salida a consola, pues por defecto el logging se cachea y solo se escribe al destino cada cierto tiempo, por lo que si monitorizas el log en tiempo real es crucial desactivar esta caché.

De esta forma, ya tendremos en cualquier parte de nuestro código donde incluyamos la declaración una macro L_ (o como la hayamos definido) lista para ser usada:

L_ << "Here we are";
 
unsigned int n = 42;
L_ << "The meaning of life is " << n;
 
L_ << boost::format( "We can even use the awesome %s library versión %d.%d.%d" ) 
    % "boost::format"
    % ( BOOST_VERSION / 100000 )
    % ( ( BOOST_VERSION / 100 ) % 1000 )
    % ( BOOST_VERSION % 100 );