Skip to content

A library with a range of utility classes and methods for jump starting C++ applications.

License

Notifications You must be signed in to change notification settings

gbmhunter/CppUtils

Repository files navigation

CppUtils

A library with a range of utility classes and methods for jump starting C++ applications.

https://travis-ci.org/gbmhunter/CppUtils.svg?branch=master

Bits.hpp

Contains static bit manipulation methods. This includes methods for generating a bit mask, getting an arbitrary sequence of bits from an integer type, or setting an arbitrary sequence of bits in an integer type.

BitMask()

uint8_t bitMask;
bitMask = Bits::BitMask<uint8_t>(1));
// bitMask = 0b00000001 or 0x01

bitMask = Bits::BitMask<uint8_t>(4));
// bitMask = 0b00001111 or 0x0F

bitMask = Bits::BitMask<uint32_t>(11));
// bitMask = 0x000007FF

GetBits()

uint8_t result;
result = Bits::GetBits(0b11001100, 0, 3));
// result = 0b00000100 or 0x4

result = Bits::GetBits(0b11001100, 2, 5));
// result = 0b00010011 or 0x13

SetBits()

uint8_t result;
result = Bits::SetBits(0b00000000, 0b11011, 0, 5));
// result = 0b00011011 or 0x1B

result = Bits::SetBits(0b11111111, 0b11011, 0, 5));
// result = 0b11111011 or 0xFB

Event.hpp

Contains a basic event class which you can use to implement an event/listener based design.

Basic Example

Event<void()> event;

event.AddListener([&](){
    std::cout << "Listener called!" << std::endl;
});

event.Fire(); // Prints "Listener called!"

One Input Parameter

Event<void(std::string)> event;

event.AddListener([&](std::string msg){
    std::cout << msg << std::endl;
});

event.Fire("Hello"); // Prints "Hello"

Bind To Method

class TestClass {
    void TestMethod() {
        std::cout << "TestMethod() called." << std::endl;
    }
}

int main() {
    TestClass testClass;

    Event<void(std::string)> event;

    event.AddListener(std::bind(&TestClass::TestMethod, &testClass));

    event.Fire(); // Prints "TestMethod() called"
}

Exception.hpp

Exception.hpp provides functionality to throw an exception which will print the file name and line number that it was thrown on, which can be of great help when debugging!

Once including the header file, you can throw one of these exceptions with the THROW_EXCEPT() macro, as shown in the below code:

#include "CppUtils/Exception.hpp"

int main() {
    THROW_EXCEPT("Something bad happened!");
}

The above code will print:

terminate called after throwing an instance of 'Exception'
  what(): /home/user/main.cpp:4: Something bad happened!

HeapTracker.hpp

HeapTracker.hpp contains a HeapTracker class which can be used keep track of memory allocations and deallocations (via new, new[], delete, and delete[]) to the heap.

Usage:

#include "CppUtils/HeapTracker.hpp"

// IMPORTANT! Only use these macros in one .cpp file. These macros define functions for new and delete
// which override the default ones provided by the compiler. These new functions define some additional
// code to keep track of new/delete calls.
HEAP_TRACKER_NEW;
HEAP_TRACKER_DELETE;

int main() {
    std::cout << "Heap size (B) = " << HeapTracker::Instance().GetHeapSize_B() >> std::endl;
    // Prints some value "x"

    uint8_t* tempBuffer = new uint8_t[100];

    std::cout << "Heap size (B) = " << HeapTracker::Instance().GetHeapSize_B() >> std::endl;
    // Prints "x + 100"

    delete[] tempBuffer;

    std::cout << "Heap size (B) = " << HeapTracker::Instance().GetHeapSize_B() >> std::endl;
    // Prints "x" again

    return 0;
}

Points To Note:

  • HeapTracker is thread safe. HeapTracker::Instance().GetHeapSize_B() can be called from multiple threads. The additions to the overriden new and delete functions are also thread safe.
  • HeapTracker does not report the exact number of bytes used by the heap. This is becausethe compiler adds additional meta-data to a heap allocation so that delete knows exactly how to delete the provided memory pointer (e.g. how many array elements to delete if delete[] is called). Typically this is done by inserting a byte before the returned pointer which holds this meta-data, although this is implementation specific. Also, HeapTracker creates a map on the heap to store needed pointer/size data which is not counted by GetHeapSize_B() (a custom allocator is used to prevent infinite recursion). Thus the number returned by GetHeapSize_B() will always be slightly less than the true heap usage, although should still be relatively accurate.
  • As mentioned above, the macros HEAP_TRACKER_NEW and HEAP_TRACKER_DELETE should be included in only one source file. However, #include CppUtils/HeapTracker.hpp can be included in as many files as you want.
  • Using HeapTracker imposes a small performance penalty as extra code is run on every call to new or delete. For every new, a std::mutex is locked, a map entry is created and the byte count incremented. On every delete, a std::mutex is locked, a map key/value pair is looked up and removed, and the byte count decremented.
  • HeapTracker is not able to keep track of heap allocations that do not use the standard new/delete. This includes any use of malloc()/free() and custom allocators.
  • HeapTracker is a thread-safe Singleton. Use HeapTracker::Instance() to acquire a reference to the single instance.

Logger.hpp

A simpler header-only logging class which supports:

  • printf() style support (for the easy logging of integers, hex values, e.t.c)
  • Different logging severities (e.g. DEBUG, WARNING, ERROR)
  • Automatic capture of filename, line number and function name
  • User control of where to direct logging output (does not automatically go to std::cout)
  • ANSI colour support

Usage:

#include "CppUtils/Logger.hpp"

using namespace mn::CppUtils;

int main() {
    Logger logger("ExampleLogger", Logger::Severity::DEBUG, Logger::Color::BLUE, [](Logger::Severity severity, std::string msg){
        std::cout << msg << std::endl;
    });

    int myNum = 5;
    LOG(logger, "My num. = %i", myNum); // Prints "ExampleLogger (/home/CppUtils/Example.cpp, 10, main()). DEBUG: My num. = 5" in a blue font
}

StrConv.hpp

A header-only collection of "to string" conversion methods which convert various objects (incl discrete values and iterable types) to various string representations.

ToHex()

std::cout << StrConv::ToHex(15, 2) << std::endl;
// Prints "0xFF"

std::cout << StrConv::ToHex(4, 3) << std::endl;
// Prints "0x004"

std::cout << StrConv::ToHex(std::vector({ 0x0A, 0x0B }) << std::endl;
// Prints "{ 0x0A, 0x0B }"

ToAscii()

std::cout << StrConv::ToAscii(std::vector({ 'a', 'b' }) << std::endl;
// Prints "{ 'a', 'b' }"

ThreadSafeQueue.hpp

Contains a cross-platform thread safe queue object which uses the C++14 standard only (no UNIX pthread or Windows CreateThread).

Timer.hpp

A timer which allows you to run code after a timeout occurs (code will be run within a new timer thread).

#include <atomic>
#include "CppUtils/Timer.hpp"
using namespace std::literals;

std::atomic<bool> callbackCalled(false);
Timer timer(100ms, [&]{
    // This will be called in the context of a timer thread, be aware
    // of concurrency concerns!
    callbackCalled.store(true);
});

std::this_thread::sleep_for(200ms);

std::cout << "callbackCalled = " << callbackCalled.load() << std::endl;
// Prints "true"

TimerWheel.hpp

This header file contains a TimerWheel class that can be used to easily create and manage timers (timeouts) in a multi-threaded environment.

Single-Shot Timer Example

#include "CppUtils/TimerWheel.hpp"

using namespace std::literals;
using namespace mn::CppUtils::TimerWheel;

int main() {
    TimerWheel timerWheel;

    timerWheel.AddSingleShotTimer(500ms, [&]() {
        std::cout << "Timer expired!" << std::endl;
    });

    std::this_thread::sleep_for(1000ms);

    // "Timer expired!" will be printed after 500ms
}

Note that the lambda callback provided above is executed in the context of the TimerWheel thread. This callback could put messages onto other thread's commands queues, notify a std::condition_variable, or lock a std::mutex and perform actions on another thread's data.

TimerWheel also supports repetitive timers.

Repetitive Timer Example

#include "CppUtils/TimerWheel.hpp"

using namespace std::literals;
using namespace mn::CppUtils::TimerWheel;

int main() {
    TimerWheel timerWheel;

    timerWheel.AddRepetitiveTimer(300ms, 3, [&]() {
        std::cout << "Repeat" << std::endl;
    });

    std::this_thread::sleep_for(1000ms);

    // "Repeat" will be printed every 300ms for a total of three times.
    // Provide -1 instead of 3 to the timer constructor to make the timer run indefinitely.
}

VerNumParser.hpp

This header file provides a class which has utility functions for dealing with string-based version numbers.

#include "CppUtils/VerNumParser.hpp"

using namespace mn::CppUtils;

int main() {

    // Converts a version string into the individual integer
    // digits
    auto digits = VerNumParser::ToInts("v2.7.4");

    std::cout << digits[0]; // "2"
    std::cout << digits[1]; // "7"
    std::cout << digits[2]; // "4"
}