Probably Dance

I can program and like games

Category: Programming

The importance of std::function

In C++11 there is a new class in the standard library called std::function. It allows you to store anything that is callable. For example

#include <functional>
#include <iostream>
void print_world()
{
    std::cout << "World!" << std::endl;
}

int main()
{
    std::function<void ()> hello_world = []{ std::cout << "Hello "; };
    hello_world();
    hello_world = &print_world;
    hello_world();
}

Prints “Hello World!” as you would expect. The assignment to and storage of the two different types is handled internally by the std::function.

The amazing thing is that calling a std::function is fairly cheap: It’s one virtual function call. That has wide implications for how you will use (or not use) virtual functions in the future. In many cases where you used to have to use a virtual function it is now better to use a std::function. For example for an update loop.

Read the rest of this entry »

scope(exit), scope(failure) and scope(success)

scope(exit) is a great idea from the D programming language. I’ll refer to the D website for motivating examples because they do a good job. There have been many implementations in C++ and Ignacio Castaño showed an elegant implementation using lambdas which is using a bit too many macros for my taste. (it’s using one) There is also an exception-safe implementation by Jon Kalb which doesn’t use the same optimization that Castaño does. I wrote an implementation that combines the benefits of the two.

Also D has scope(exit), scope(failure) and scope(success), where failure runs only if an exception caused stack unwinding, success runs otherwise, and exit runs in any case. And I think it makes sense to offer the complete set. So to keep this post short here is an implementation of all three in C++:

#pragma once

#include <exception>

namespace detail
{

template<typename F>
struct ScopeExitRunner
{
    ScopeExitRunner(const F & to_run)
    try : to_run(to_run)
    {
    }
    catch(...)
    {
        // if the copy constructor for to_run threw,
        // call the argument immediately then rethrow
        to_run();
    }
    ScopeExitRunner(ScopeExitRunner &&) = default;
    ~ScopeExitRunner()
    {
        to_run();
    }
private:
    F to_run;
};

template<typename F>
struct ScopeFailureRunner
{
    ScopeFailureRunner(const F & to_run)
    try : to_run(to_run)
    {
    }
    catch(...)
    {
        to_run();
    }
    ScopeFailureRunner(ScopeFailureRunner &&) = default;
    ~ScopeFailureRunner() noexcept
    {
        static_assert(noexcept(to_run()), "the given function must be noexcept. it will only be run if there was an exception");
        static_assert(noexcept(to_run.~F()), "the given functor must have a noexcept destructor. it is likely that it will be run when there was an exception");
        if (::std::uncaught_exception())
        {
            to_run();
        }
    }
private:
    F to_run;
};

template<typename F>
struct ScopeSuccessRunner
{
    ScopeSuccessRunner(const F & to_run)
        : to_run{to_run}
    {
    }
    ScopeSuccessRunner(ScopeSuccessRunner && other) = default;
    ~ScopeSuccessRunner()
    {
        if (!::std::uncaught_exception())
        {
            to_run();
        }
    }
private:
    F to_run;
};

} // end namespace detail

template<typename T>
detail::ScopeExitRunner<T> AtScopeExit(const T & to_run)
{
    return detail::ScopeExitRunner<T>(to_run);
}
template<typename T>
detail::ScopeFailureRunner<T> AtScopeFailure(const T & to_run)
{
    return detail::ScopeFailureRunner<T>(to_run);
}
template<typename T>
detail::ScopeSuccessRunner<T> AtScopeSuccess(const T & to_run)
{
    return detail::ScopeSuccessRunner<T>(to_run);
}

And you use it for example when dealing with windows functions:

// ...
IUnknown * important = nullptr;
::SomeWindowsFunctionA(/*...*/, &important);
auto release_important = AtScopeExit([important]
{
    important->Release();
});
// ...

This code should be as efficient as if you had placed that call manually at each exit point of your function.

Read the rest of this entry »

Learning D Part 4: I’m done

D has a lot of features which I like very much. And it has a few design decisions that completely kill it for me.

  • In D I don’t like making my objects structs, and I don’t like making my objects classes. I would like to have more control over how my type behaves.
  • The garbage collector has too much of an impact on the core language and the standard library.
  • Everything has shared ownerhsip by default. C++11 introduced features that make it easier to clearly indicate who owns what. D went in the opposite direction.

The issue with all of these is that they are so fundamental to the language that you can not ignore them. In C++ I always have the option to ignore a feature. In D I do not.

Read the rest of this entry »

Variadic Coroutines in C++ and D

In my last post I implemented a tiny coroutine class that is fully functional, but it doesn’t support arguments and return values. This time I provide an implementation which adds those features as well as exception safety.

I also used this as an example to compare D and C++; as an excuse to learn C++’s variadic template syntax and as a reason to see how you can improve on boost’s implementation by using variadic templates.
Let’s start off with the punchline. Here is my coroutine implementation in C++:

#pragma once

#include <ucontext.h>
#include <cstdint>
#include <exception>
#include <functional>
#include <memory>
#include <tuple>

#ifndef CORO_DEFAULT_STACK_SIZE
#define CORO_DEFAULT_STACK_SIZE SIGSTKSZ
#endif

namespace coro
{
namespace detail
{

/**
 * the coroutine_context holds the stack context and the current state
 * of the coroutine. it also starts the coroutine
 */
struct coroutine_context
{
    coroutine_context(size_t stack_size, void (*coroutine_call)())
        : stack{new unsigned char[stack_size]}
    {
        // create a context for the callee
        getcontext(&callee);
        callee.uc_link = &caller; // tell it to return to me when done
        callee.uc_stack.ss_size = stack_size;
        callee.uc_stack.ss_sp = stack.get();
        // pass the this pointer as two arguments, because officially
        // makecontext will pass the arguments as ints (even though
        // inofficially it would work with a single argument)
        makecontext(&callee, coroutine_call, 2, reinterpret_cast<size_t>(this) >> 32, this);
    }

    void operator()()
    {
        if (returned) throw "This coroutine has already finished";

        swapcontext(&caller, &callee); // continue here if yielded or returned

        if (exception)
        {
            std::rethrow_exception(std::move(exception));
        }
    }

protected:
    ucontext_t caller;
    ucontext_t callee;
    std::unique_ptr<unsigned char[]> stack;
    std::exception_ptr exception;
    bool returned = false;
};

// a type that can store both objects and references
template<typename T>
struct any_storage
{
    any_storage() = default;
    any_storage(T to_store)
        : stored{std::move(to_store)}
    {
    }
    any_storage & operator=(T to_store)
    {
        stored = std::move(to_store);
        return *this;
    }
    operator T &&()
    {
        return std::move(stored);
    }

private:
    T stored = T{};
};
// specialization for void
template<>
struct any_storage<void>
{
};
// specialization for lvalue references
template<typename T>
struct any_storage<T &>
{
    any_storage() = default;
    any_storage(T & to_store)
        : stored{&to_store}
    {
    }
    any_storage & operator=(T & to_store)
    {
        stored = &to_store;
        return *this;
    }
    operator T &()
    {
        return *stored;
    }

private:
    T * stored = nullptr;
};
// specialization for rvalue references
template<typename T>
struct any_storage<T &&>
{
    any_storage() = default;
    any_storage(T && to_store)
        : stored{&to_store}
    {
    }
    any_storage & operator=(T && to_store)
    {
        stored = &to_store;
        return *this;
    }
    operator T &&()
    {
        return *stored;
    }

private:
    T * stored = nullptr;
};

// implements the shared code among all specializations of coroutine_yielder
template<typename Result, typename... Arguments>
struct coroutine_yielder_base
    : protected coroutine_context
{
    coroutine_yielder_base(size_t stack_size, void (*coroutine_call)())
        : coroutine_context{stack_size, coroutine_call}
    {
    }
    std::tuple<Arguments...> yield()
    {
        swapcontext(&this->callee, &this->caller);
        return std::move(this->arguments);
    }

protected:
    any_storage<Result> result;
    std::tuple<any_storage<Arguments>...> arguments;
};

/**
 * The coroutine_yielder is responsible for providing a yield
 * function
 */
template<typename Result, typename... Arguments>
struct coroutine_yielder
    : protected coroutine_yielder_base<Result, Arguments...>
{
    coroutine_yielder(size_t stack_size, void (*coroutine_call)())
        : coroutine_yielder_base<Result, Arguments...>{stack_size, coroutine_call}
    {
    }
    std::tuple<Arguments...> yield(Result && result)
    {
        this->result = std::forward<Result>(result);
        return coroutine_yielder_base<Result, Arguments...>::yield();
    }

    // copying yield
    std::tuple<Arguments...> yield(const Result & result)
    {
        this->result = result;
        return coroutine_yielder_base<Result, Arguments...>::yield();
    }
};
// specialization for void
template<typename... Arguments>
struct coroutine_yielder<void, Arguments...>
    : coroutine_yielder_base<void, Arguments...>
{
    coroutine_yielder(size_t stack_size, void (*coroutine_call)())
        : coroutine_yielder_base<void, Arguments...>{stack_size, coroutine_call}
    {
    }
};
// specialization for lvalue reference
template<typename Result, typename... Arguments>
struct coroutine_yielder<Result &, Arguments...>
    : protected coroutine_yielder_base<Result &, Arguments...>
{
    coroutine_yielder(size_t stack_size, void (*coroutine_call)())
        : coroutine_yielder_base<Result &, Arguments...>{stack_size, coroutine_call}
    {
    }
    std::tuple<Arguments...> yield(Result & result)
    {
        this->result = result;
        return coroutine_yielder_base<Result &, Arguments...>::yield();
    }
};
// specialization for rvalue reference
template<typename Result, typename... Arguments>
struct coroutine_yielder<Result &&, Arguments...>
    : protected coroutine_yielder_base<Result &&, Arguments...>
{
    coroutine_yielder(size_t stack_size, void (*coroutine_call)())
        : coroutine_yielder_base<Result &&, Arguments...>{stack_size, coroutine_call}
    {
    }
    std::tuple<Arguments...> yield(Result && result)
    {
        this->result = std::move(result);
        return coroutine_yielder_base<Result &&, Arguments...>::yield();
    }
};
}

template<typename Result, typename... Arguments>
struct coroutine;

template<typename Result, typename... Arguments>
struct coroutine<Result (Arguments...)>
    : detail::coroutine_yielder<Result, Arguments...>
{
private:
    template<int N, int... S>
    struct starter;
    typedef starter<sizeof...(Arguments)> Starter;
public:
    typedef typename detail::coroutine_yielder<Result, Arguments...> self;
    coroutine(std::function<Result (self &, Arguments...)> func, size_t stack_size = CORO_DEFAULT_STACK_SIZE)
        : detail::coroutine_yielder<Result, Arguments...>{stack_size, reinterpret_cast<void (*)()>(&Starter::coroutine_start)}
        , func{std::move(func)}
    {
    }
    // I don't need to specify these. the default behavior would result
    // in the same constructors and assignment operators being generated
    // but you get better error messages if I'm explicit about it
    coroutine(const coroutine &) = delete;
    coroutine & operator=(const coroutine &) = delete;
    coroutine(coroutine &&) = default;
    coroutine & operator=(coroutine &&) = default;

    operator bool() const
    {
        return !this->returned;
    }

    Result operator()(Arguments... args)
    {
        this->arguments = std::make_tuple(detail::any_storage<Arguments>{std::forward<Arguments>(args)}...);
        detail::coroutine_yielder<Result, Arguments...>::operator()();
        return Starter::Finisher::return_result(*this);
    }

private:
    // returning a value needs to be specialized for void return
    // this struct handles that
    template<typename R, int... S>
    struct finisher
    {
        static R return_result(coroutine & this_)
        {
            return std::forward<Result>(this_.result);
        }
        static void start_and_store_result(coroutine & caller)
        {
            caller.result = caller.coroutine_start<S...>();
        }
    };
    template<int... S>
    struct finisher<void, S...>
    {
        static void return_result(coroutine &)
        {
        }
        static void start_and_store_result(coroutine & caller)
        {
            caller.coroutine_start<S...>();
        }
    };

    template<int ...ArgCountList>
    Result coroutine_start()
    {
        return func(*this, std::forward<Arguments>(std::get<ArgCountList>(this->arguments))...);
    }

    // the calling of the coroutine needs to be specialized by
    // the number of arguments. this struct handles that
    template<int N, int... S>
    struct starter : starter<N - 1, N - 1, S...>
    {
    };

    template<int... S>
    struct starter<0, S...>
    {
        typedef finisher<Result, S...> Finisher;
        static void coroutine_start(uint32_t this_pointer_left_half, uint32_t this_pointer_right_half)
        {
            coroutine & this_ = *reinterpret_cast<coroutine *>((static_cast<size_t>(this_pointer_left_half) << 32) + this_pointer_right_half);
            try
            {
                Finisher::start_and_store_result(this_);
            }
            catch(...)
            {
                this_.exception = std::current_exception();
            }
            this_.returned = true;
        }
    };

    std::function<Result (self &, Arguments...)> func;
};

}

And here it is in D:

module coro.coroutine;

import coro.ucontext;
import std.algorithm;
import std.conv;
import std.typecons;

template VariadicForward(string before, string toforward, string after, size_t i)
{
    static if (i == 0)
    {
        immutable string VariadicForward = before ~ after;
    }
    else static if (i == 1)
    {
        immutable string VariadicForward = VariadicForward!(before, toforward, "move(" ~ toforward ~ "[" ~ to!string(i - 1) ~ "])" ~ after, i - 1);
    }
    else
    {
        immutable string VariadicForward = VariadicForward!(before, toforward, ", move(" ~ toforward ~ "[" ~ to!string(i - 1) ~ "])" ~ after, i - 1);
    }
}

class coroutine(Result, Arguments...)
{
	private alias Tuple!Arguments.Types Types;
	this(Result delegate(coroutine!(Result, Arguments), Types) func, size_t stack_size = 8192)
	{
		this.func = func;
		stack = new ubyte[stack_size];
		getcontext(&callee);
		callee.uc_link = &caller;
		callee.uc_stack.ss_size = stack_size;
		callee.uc_stack.ss_sp = stack.ptr;
		extern(C) void function() call = cast(void function())&coroutine_start;
		makecontext(&callee, call, 2, cast(size_t)(cast(void *)this) >> 32, this);
	}

	Result opCall(Types arguments)
	{
		if (returned) throw new Throwable("This coroutine has already finished");

		static if (arguments.length)
		{
			foreach(i, ref argument; arguments)
				this.arguments[i] = move(argument);
		}
	    swapcontext(&caller, &callee);

	    if (exception)
		{
			throw exception;
		}
		else static if (!is(Result == void))
		{
			return move(result);
		}
	}

	@property bool callable() const
	{
		return !returned;
	}

	static if (is(Result == void))
	{
		alias yield_common yield;
	}
	else
	{
		Tuple!Arguments yield(ref Result result)
		{
			this.result = result;
			return yield_common();
		}
		Tuple!Arguments yield(Result result)
		{
			this.result = move(result);
			return yield_common();
		}
	}

	private Tuple!Arguments yield_common()
	{
	    swapcontext(&callee, &caller);
    	mixin(VariadicForward!("return Tuple!Arguments(", "arguments", ");", Types.length));
	}

private:
	Result delegate(coroutine!(Result, Arguments), Types) func;
	ubyte[] stack;
	ucontext_t caller;
	ucontext_t callee;
	Throwable exception;
	bool returned = false;
	static if (!is(Result == void))
	{
		Result result;
	}
	Types arguments;

	extern(C) static void coroutine_start(uint this_pointer_left_half, uint this_pointer_right_half)
	{
		coroutine this_ = cast(coroutine)cast(void *)(((cast(size_t)this_pointer_left_half) << 32) + this_pointer_right_half);
	    try
	    {
	    	static if (is(Result == void))
	    	{
	    		mixin(VariadicForward!("this_.func(this_, ", "this_.arguments", ");", Types.length));
	    	}
	    	else
	    	{
	    		mixin(VariadicForward!("this_.result = this_.func(this_, ", "this_.arguments", ");", Types.length));
	    	}
	    }
	    catch(Throwable ex)
	    {
	    	this_.exception = ex;
	    }
	    this_.returned = true;
	}
}

The most obvious point first: D is much cleaner.

Read the rest of this entry »

Implementing coroutines with ucontext

Coroutines are a way of doing cooperative multithreading where each context has it’s own stack. And they can be incredibly useful for games. (I’ll use the word context as the coroutine equivalent of a thread) The basic idea of a coroutine is that you can yield from a context in the middle of a function, and then you will continue exactly at that point when the coroutine gets called the next time.
Imagine that you want something to happen in a sequence, for example you want to spawn an enemy, show a text for two seconds, then kill the enemy and show another text for two seconds. A trivial implementation would be this:

void sudden_exploding_unit(const Vector3 & pos)
{
    std::unique_ptr<Entity> guy = spawn_entity(pos, "grunt.entity");
    sleep(1.0f);
    show_text(pos, "oh no he is exploding!", 2.0f);
    sleep(0.5f);
    explode(*guy);
    sleep(1.0f);
    show_text(pos, "well that was underwhelming", 2.0f);
}

Even though this code is simple, you would probably have a large amount of pain to implement this in a game engine, because a game can never block, and this code is sleeping all over the place. You’d probably end up writing some kind of state machine (maybe using a kismet-like scripting system) or if you’re a terrible person you’d use asynchronous callbacks. State machines can be a fine solution, but they introduce way too much infrastructure for such a trivial piece of code.

Enter coroutines. If your engine has coroutines, you can write exactly the above code. With very little downsides. Because you could just sleep like this:

void sleep(float seconds)
{
    while (seconds >= 0.0f)
    {
        yield(); // resume here next frame
        seconds -= global_dt;
    }
}

Read the rest of this entry »

Learning D Part 3: Garbage Collection

Garbage collection is a red flag for any C++ programmer, simply because a garbage collector makes it more difficult to use the language for the kinds of things that C++ programmers like to program.

When I started programming in D, I was going to give the garbage collector the benefit of the doubt. The language has enough smart features that I figured that the designers must have had good reasons for including a GC.

But really, it’s a mess. In fact it’s a bigger mess than I have seen in other garbage collected languages. Fortunately that mess is solvable, and where it isn’t solvable the language designers could probably make it less of a problem.

Read the rest of this entry »

Learning D Part 2: Random Little Things I Like

D is better than C++ in many ways. Here are a couple examples that I have encountered so far.

Let’s start with the scope keyword:

void main()
{
    OSInterface.Load();
    scope(exit) OSInterface.Quit();
    //...
}

What this means is “at the end of the current scope, run OSInterface.Quit();. Meaning I can put the call to freeing resources right next to the line where I allocate it. There is also scope(failure) which only runs the when there is an exception, and scope(success) which only runs when the scope exits normally. This is a much better solution than try {} catch {} finally {}.

Another cool thing is lazy evaluation, for example in the function std.exception.enforce, which has this signature:

T enforce(T)(T value, lazy const(char)[] msg = null, string file = __FILE__, size_t line = __LINE__)

Read the rest of this entry »

Learning D Part 1: IDE and Libraries

I am learning the D programming language.

I’m a C++ programmer, and like most C++ programmers I am rather annoyed with C++. It can be a pretty bad language. The problem is only that all other languages are even worse for the stuff that you’d want to use C++ for.

But D seems promising. Reading through the features of the language, you notice that it has many smart solutions for things which are cumbersome or error-prone in C++. I’ll go into benefits and problems of features one by one as I am using them. But the D overview page says under “Who D is for:”

  • Programmers who routinely use lint or similar code analysis tools to eliminate bugs before the code is even compiled.
  • People who compile with maximum warning levels turned on and who instruct the compiler to treat warnings as errors.

Which sounds like me, or at least sounds like the programmer I wish I was.

But to start, you just want a simple “Hello, World” on the screen. And that already is kinda complicated in D.

Read the rest of this entry »

First Class Functions in C++

I’ve been working on a library that allows you to treat functions as first class objects in C++. Meaning you can assign to a function. Here’s a download link, and here’s a very simple example:

#include "fcf.h"
void foo()
{
    std::cout << "foo\n";
}
void bar()
{
    std::cout << "bar\n";
}
void main()
{
    foo(); // prints "foo"
    auto oldFoo = fcf::function(&foo);
    FCF_ASSIGN(&foo, &bar);
    foo(); // prints "bar"
    FCF_ASSIGN(&foo, oldFoo);
    foo(); // prints "foo"
}

If you have ever worked in a language with first class functions, you’ll know that you can do some quite cool stuff with this.

Read the rest of this entry »

How to make successful student games

I’m almost done with DigiPen. Time to write down some learned lessons. I was only at DigiPen for two years, so others could probably write this better, but until they do there is this post. In both years I was in the most successful game team of the Master’s program, which is my claim to being qualified to write this post. So here are a couple rules, starting with

1. Gameplay first

This is the first point on Blizzard’s mission statement, and they mean “prioritize gameplay.” Do that. But for student games I consider it even more important to interpret that as “work on gameplay first.” The biggest mistake I have seen on student games is wasting time on features that don’t improve gameplay in the end. You do not have time for a student game.

Now how do you finish gameplay first?  Obviously you need tech to do your gameplay. If you want to make a physics-based puzzle platformer, someone has to implement your physics. But I would consider it a mistake to work on the physics until you know that it will result in good gameplay. Which is a problem.

Read the rest of this entry »