Source Code Tales Tamás Szelei's coding blog

cmake is not great, but it doesn’t matter

CMake, the language is not great. It is just not a pleasant tool to work with. Not at all; it feels like it was not designed as a language, but a mere configuration file that sets build options in a compiler-agnostic way. But, it hits many important bullet points for building software and most importantly: “just works”. As a result, it has gained popularity over the years because cmake, the software is quite good.

As it happens often, control structures began to creep into the configuration file. This little if won’t hurt anyone, and look, I can do conditional steps during the build file generation with it! How about a for loop? We don’t even have to add an array type, we can just treat strings as arrays! Regex? Sure, add some Cthulhu curse while you are at it. And so on.

Continue Reading...
  • c++
  • cmake

Murmur3 hash as a constexpr function

C++14 relaxed many restrictions on constexpr functions. The ability to contain branching, loops, switch statements makes them really easy to use. Implementing complicated functions at compile time is now a piece of cake.

To prove this point, I tried and implemented Murmur3A, the Murmur3 hash variant which is optimized for x861 and computes 32 bit hash values. In this post I’m going to walk through the steps of the implementation.

  1. Not that this matters for constexpr; the point is, it computes the same values as that version of the algorithm does. 

Continue Reading...
  • c++
  • constexpr

Emulating the static initialization blocks of Java in C++

What is a static initialization block?

In Java, there is a language construct called a static initialization block. The static initialization block will be called the first time the class is loaded by the Java runtime. For example, consider the following code snippet:

class Foo {
    static {
        // initialization code goes here
        // called only once, when the class is loaded by the runtime
        System.out.println("I'm the static initialization block of Foo\n");
    }

    public Foo() {
        System.out.println("I'm the constructor of Foo\n");
    }

    public static void Main(String[] args) {
        Foo foo1 = new Foo();
        Foo foo2 = new Foo();
    }
}

This produces the output:

I'm the static initialization block of Foo
I'm the constructor of Foo
I'm the constructor of Foo

This construct can be useful in a variety of situations. In Java, the intended use case is to allow multiline initialization of static members of a class. It can also be used for logging and any kind of “registration” or “subscription” code (such as for script binding).

C++ lacks this construct, but with some clever use of the language it’s possible to mimic certain aspects of it.

Continue Reading...
  • c++
  • java

Rarely known C++ constructs (part 1): Function try blocks

C++ has some language constructs that are rarely seen in use. These constructs have their own, valid uses, but should be used sparingly. As the now adage-status quote from The Old New Thing says:

Code is read much more often than it is written, so plan accordingly

In this series we will take a look at different instances of unusual C++ language constructs, shortly explaining their use-cases, syntax and pitfalls.

UPDATE: the series was moved to Dr. Dobbs! The rewritten, expanded first part is available here.

Continue Reading...
  • c++

Implementing a code generator with libclang

The following article covers the process of implementing a practical code generator for C++ in detail. You can find the full source code for the article on GitHub.

A code generator is a very useful asset in a larger C++ project. Due to the lack of introspection in the language, implementing the likes of reflection, script binding and serialization requires writing some sort of boilerplate that essentially keeps the data which is otherwise thrown away by the compiler. These solutions are either intrusive (heavily macro-based, thus hard to debug and require weird syntax in declarations) or fragile (the boilerplate must be constantly updated to follow the actual code, and might break without warning). One way to improve the robustness is to automate writing this boilerplate. In order to achieve this, we need to parse the code somehow, in other words, understand what information to keep. However, parsing C++ is an extremely complex task, and with the copious amount of weird corner cases, we are in for quite a ride if we attempt to do so.

Continue Reading...
  • c++
  • clang
  • python
  • code-generation