Skip to content
Dan Parnham edited this page Jan 23, 2023 · 31 revisions

Library Classes

Since uint8_t is a very useful type for image processing (or anything dealing with binary data) the library typedefs uint8_t to byte which is quicker to type and looks tidier.

Image<>

The Image class supports a number of types (the default being byte) along with a set of depths such as 8-bit greyscale and 24-bit RGB. It provides raw access to the pixel data as a contiguous block which makes it simpler to implement image processing algorithms based around it.

#include <emergent/image/Image.hpp>
using namespace emergent;

int main(int argc, char *argv[])
{
    // Standard greyscale byte image
    Image<byte> grey;
    
    // Colour byte image (24-bit, RGB)
    Image<byte, rgb> colour;

    // Greyscale floating-point image
    Image<double> floating;

    // Load from file (utilises the [freeimage](http://freeimage.sourceforge.net) library)
    if (grey.Load("test.png"))
    {
        // Implicitly cast to byte* to give raw access to the underlying data
        byte *g  = grey;
        const size_t size = grey.Size();

        // Simple inversion of pixel values
        for (size_t i=0; i<size; i++, g++)
        {
            *g = 255 - *g;
        } 

        // Assign the greyscale image to the colour one, the data will be copied
        // such that each channel (RGB) contains the same values.
        colour = grey;
    }
}

ResetEvent

Threading helper capable of acting as a manual and auto reset event.

DateTime

Basic wrapper around a time_t representing a UTC timestamp. Contains methods for converting to/from ISO 8601 and for incrementing/decrementing the timestamp.

#include <emergent/DateTime.hpp>
using namespace emergent;

int main(int argc, char *argv[])
{
    auto time = DateTime::Now().AddDays(4).AddSeconds(21);

    cout << time.FormatISO() << endl;
}

Logger

The class logger is a singleton that can be initialised with multiple sinks for directing log output.

#include <emergent/logger/Logger.hpp>
using namespace emergent;

int main(int argc, char *argv[])
{
    // Logs to std::cout
    Log::Initialise({ make_unique<logger::Console>() });

    ...

    // Simple logging macro 
    Log::Error("Something happened here");

    // Formatted logging
    Log::Error("There was an error: %s", errorString);
}

Maths

The Maths class contains a few static helper functions:

  • clamp for clamping values of one type within the numeric limits of another.
  • nrand for generating a normalised pseudo-random number (0.0 to 1.0).
  • cosine and sine lookup functions for positive integer angles in degrees.

Reverse

A wrapper for STL containers that will switch the begin/end for rbegin/rend so that they can be used in a range-based for loop.

#include <emergent/Reverse.hpp>
using namespace emergent;

int main(int argc, char *argv[])
{
    vector<string> values = { "a", "b", "c" };

    for (auto &s : reverse(values))
    {
        // Will print out "c" first 
        cout << s << endl;
    }
}

KeyIterator

A wrapper for std::map<> to allow range-based iteration over the keys.

#include <emergent/KeyIterator.hpp>
using namespace emergent;

int main(int argc, char *argv[])
{
    map<int, string> values = { { 0, "a" }, { 2, "b" }, { 4, "c" }};

    for (auto &k : key_iterator(values))
    {
        cout << k << endl;
    }
}

String

The String class is simply a container for some static helper functions:

  • demangle will demangle a function name (gcc only).
  • load will load an entire file into a std::string.
  • save will save a std::string to a file (overwriting a file if it already exists).
  • explode will split a string at the specified delimiters and return a std::vector<std::string>.
  • lowercase will transform a string to lowercase.
  • hyphenate will return a lowercase hyphenated string from a camel-cased one (for example, given "HelloWorld" it would return "hello-world").
  • trim will trim a specified character from both ends of a string.
  • format acts as a wrapper around snprintf.

Type

A system for registering types and allowing new instances to be constructed by string name.

#include <emergent/Type.hpp>
using namespace emergent;

class Base {};
class Derived : public Base {};

REGISTER_TYPE(Base, Derived)

int main(int argc, char *argv[])
{
    unique_ptr<Base> instance = Type<Base>::Create("Derived");
}

Uuid

Creates a UUID using the std::mersenne_twister_engine to generate random numbers.

#include <emergent/Uuid.hpp>
using namespace emergent;

int main(int argc, char *argv[])
{
    uuid id;

    // Convert to its canonical form (xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx)
    // where 'y' is one of 8, 9, a or b
    cout << id.to_string() << endl;

    // Alternatively convert to a std::vector<byte>
    for (auto &b : id.to_binary())
    {
        ...
    }
}

Profile

A simple, lightweight profiler that uses a concurrent queue to store readings in a lock-free and yet thread-safe manner. This means that the profiler itself should provide very little overhead and therefore could be left enabled in production. The Aggregator generates and stores the statistics at regular, configurable intervals. The storage class can be extended so that results can be written wherever you wish.

Please note that the built-in storage classes have an additional dependency on libentity which is used for serialisation of aggregated statistics.

#include <emergent/profile/Profile.hpp>
using namespace emergent::profile;

int main(int argc, char *argv[])
{
    // Initialise the profile aggregator with a unique ID for this process and the type of 
    // storage required. Time between aggregations will be 1000ms in this example.
    if (!Aggregator::Instance().Initialise("my-process", make_unique<ConsoleStorage>(), 1000))
    {
        cout << "Problem initialising aggregator" << endl;
        return -1;
    }

    const int THREADS = 50;
    thread t[THREADS];

    for (int i=0; i<THREADS; i++)
    {
        t[i] = thread([](){
            for (int i=0; i<500; i++)
            {
                // Profile the sample codeblock called from many threads. When the instance 
                // goes out of scope the time between construction and destruction is logged.
                Profile p = { "my-codeblock" };
                this_thread::sleep_for(milliseconds(10));
            }
        });
    }

    for (int i=0; i<THREADS; i++) t[i].join();

    return 0;
}

ThreadPool

A simple class that provides a fixed size thread pool which, unlike std::async, does not block when the returned future is destroyed.

#include <emergent/thread/Pool.hpp>
using namespace emergent;

int main(int argc, char *argv[])
{
    // A pool of 4 threads
    ThreadPool<4> pool;

    // Run a lambda with no return value.
    auto a = pool.Run([]() {
        this_thread::sleep_for(100ms);
        cout << "a," << flush;
    });

    // Run a lambda with an integer return value.
    auto b = pool.Run([]() {
        this_thread::sleep_for(50ms);
        cout << "b," << flush;
        return 42;
    });

    // You do not need to do anything with the returned future.
    pool.Run([]() {
        cout << "c," << flush;
    });

    // Wait for and retrieve the integer returned from "b".
    cout << b.get() << "," << flush;

    // Wait for "a" to complete.
    a.wait();

    // After this it should have printed "c,b,42,a,done"
    cout << "done" << endl;

    return 0;
}
Clone this wiki locally