Aurora C++ Library
Aurora is a small library that contains various useful C++ functionality. It is header-only, so it can be used very easily in any project.
The library doesn't focus on a specific application field such as Thor; it doesn't depend on SFML either. Instead, Aurora intends to make general programming techniques easier and to bring rather unknown idioms to the C++ community. Aurora is used in the implementation and interface of the Thor library.
Features
The library is split into the following modules:
- SmartPtr: Smart pointers with deep copy semantics, customizable cloners and deleters
- Tools: Various utility, like safe bool idiom, noncopyable base class, named tuples...
- Dispatch: Multimethods (as extension of virtual functions), non-intrusive dispatching on functions with 1 or 2 arguments
- Meta: Template and preprocessor metaprogramming (mainly used by other modules)
Philosophy
The idea of Aurora is not to cover all the typical daily C++ problems. That's the reason why you will find a lot of functionality that seems unusual, sometimes innovative, and possibly confusing at first. Yet, there are still places where the standard library and Boost do not provide the functionality you need to solve a specific problem, or they only provide it in an overly complicated (Boost developers would say "generic") way.
The core philosophy behind the library can be summarized as follows:
- Lightweight and modular: Unlike other libraries with similar application field such as Boost, the dependencies are tiny. When you use one feature, you use that specific feature, and it does not pull hundreds of files behind it. Compile times are short (and they're caused mainly by included standard headers).
- Simple: The use cases are sometimes complex, and even more so is Aurora's implementation. The focus lies on providing a simple and intuitive API that abstracts from this complexity and that lets you use features without caring about the internals.
- Zero installation: Aurora is a header-only library. All you need is to download it and put it in your include path -- done. No configuration, build or link steps are required.
- Unconventional: A lot of things in Aurora can't be found elsewhere, and you may encounter new C++ techniques as you use the library. Aurora attempts to fill several gaps in language-level libraries, and it does not stop short of exploiting the borders of the C++ language in order to achieve this goal.
- Genericity vs. overengineering: Aurora makes very few assumptions about your code. The use of templates makes it possible to integrate your own types directly. On the other hand, overly generic solutions to solve non-problems are avoided. You won't encounter class templates with dozens of policies, or non-documented concepts that your types have to fulfill.
Examples
Let's get concrete, what does Aurora offer? The following code snippets are not complete, but they should give you a basic idea of what this library provides, and whether it might be something for you.
Smart pointers: The copyable smart pointer is able to perform deep copies across polymorphic class hierarchies. This allows you to treat pointers to derived objects with value semantics, which simplifies code dramatically (e.g. copy constructor and assignment operator can often be omitted).
struct Base { virtual ~Base(); }; struct Derived : Base {}; aurora::CopiedPtr<Base> p(new Derived); aurora::CopiedPtr<Base> q = p; // *q is now a copy of *p
Dynamic dispatchers: Overloading at runtime. From a set of possible functions, choose the correct one depending on the arguments.
struct Object { virtual ~Object() {} };
struct Asteroid : Object {};
struct Ship : Object {}; void collisionAA(Asteroid*, Asteroid*) { std::cout << "Asteroid-Asteroid\n"; }
void collisionAS(Asteroid*, Ship*) { std::cout << "Asteroid-Ship\n"; }
void collisionSS(Ship*, Ship*) { std::cout << "Ship-Ship\n"; } // Register "overloaded" functions using aurora::Type; aurora::DoubleDispatcher<void(Object*,Object*)> disp;
disp.bind(Type<Asteroid>(), Type<Asteroid>(), &collisionAA);
disp.bind(Type<Asteroid>(), Type<Ship>(), &collisionAS);
disp.bind(Type<Ship>(), Type<Ship>(), &collisionSS); // Call function, given only base class pointers Asteroid a; Object* pa = &a;
Ship s; Object* ps = &s;
disp.call(pa, ps); // Output: Asteroid-Ship
Named tuples: Quickly define std::tuple
-like types, but with expressive syntax (i.e. named member access) and a list of automatically generated "extensions" such as comparison operators or hash functions.
AURORA_NAMED_TUPLE_EXT(MyTuple, // define a type called MyTuple ((int, myInt), (float, myFloat)), // with members int myInt, float myFloat (AURORA_NT_LESS)) // and automatically generated operator< MyTuple t(2, 3.5f); // construct MyTuple object t.myInt = 3; // access members -- more readable than t.first or std::get<0>(t) std::map<MyTuple, X> map; // use as key in map (because of operator<)
License
Like Thor, Aurora is licensed under zlib/libpng. So you can use it for virtually everything.