No description
  • C 95.4%
  • C++ 4.6%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
2026-11-01 09:24:05 +02:00
src added write_entire_file function to mio.h 2026-11-01 04:11:09 +02:00
.gitignore gitignore 2026-11-01 07:15:41 +02:00
nob.c fixed vendored warnings 2026-11-01 09:24:05 +02:00
nob.h Change makefile to nob.h 2026-11-01 07:09:09 +02:00
readme.org Change makefile to nob.h 2026-11-01 07:09:09 +02:00

Cpp-template

This is mostly repository for a fancy Makefile that handles project setup for you. Also as an added feature, shows the actual error messages on the end of the compile message.

MADE MOSTLY FOR MYSELF!

The mio.h is split on "modules" to avoid pulling in a lot of std headers when you only need one part of the library.

Example usage

mio.h is an stb-style C++ single header library. Include it wherever you need it, and in exactly one .cpp define MIO_IMPLEMENTATION first to compile the implementation. Options like MIO_MULTITHREAD must be defined before every include.

#define MIO_MULTITHREAD
#define MIO_IMPLEMENTATION
#include "mio.h"

String manipulation

Mio provides two types of trimming functions

trim_sv
returns a trimmed string_view. Doesnt touch the original
trim_str
Trims string in place
    std::string_view sv = "  Meow  ";
    sv = mio::trim_sv(sv);
    std::println("{}", sv);

    std::string str = "  Meow  ";
    mio::trim_str(str);
    std::println("{}", str);

File operations

  • Functions:

    write_entire_file
    Writes a string into a file
  • Enums:

    writeMode

    Enum to use for write mode

    • writeMode::write
    • writeMode::append
mio::write_entire_file("test.txt", std::string("some data\n"), mio::writeMode::write);

Channels/Multithreading

mio.h provides bounded channels (needs MIO_MULTITHREAD), example:

std::atomic<int> done {0};

void work(int id, std::string& out) {
    std::string str = "Hello from thread " + std::to_string(id) + "\n";

    std::lock_guard lk(mutex);
    out += str;
}

auto main() -> int {
    Channel<int> ch(16);
    std::vector<std::jthread> workers;
    // make 4 workers
    for (int i = 0; i < 4; i++) {
        workers.emplace_back([&] {
            // grab jobs from the channel on each worker and increment  atomic counter.
            while (auto job = ch.recv()) {
                work(*job, std::ref(s));
                done.fetch_add(1, std::memory_order_relaxed);
            }
        });
    }
    // Send 100 jobs to the channel
    for (int i = 0; i < 100; i++) ch.send(i);
    // Close the channel and await the workers
    ch.close();
    workers.clear();

    std::println("Jobs done: {}", done.load());

    return 0;
}

Simple single producer single consumer: (The library is not optimized for this, it uses the same mechanism as the multiple consumers)

Channel<int> ch(16);

// Start a single thread consumer
std::jthread consumer([&] {
    // Lambda captures everything by reference
    while (auto v = ch.recv()) {
        std::println("got {}", *v);
    }
});

// Send 10 messages to the Channel.
for (int i = 0; i < 10; i++) {
    ch.send(i);
}

// Close the channel.
ch.close();
// awaits before continuing
consumer.join();

Just a simple mutex example bc my memory is of a goldfish:

std::mutex mutex

void work(int id, std::string& out) {
    std::string str = "Hello from thread " + std::to_string(id) + "\n";

    // Create a new lock and lock using our mutex instance
    std::lock_guard lk(mutex);
    out += str;
    // unlock the mutex automatically in the scope end
}

auto main() -> void {
    std::string s;
    std::thread t;
    std::thread t2;
    t = std::thread(work, 1, std::ref(s));
    t2 = std::thread(work, 2, std::ref(s));
    t.join();
    t2.join();

    std::println("{}", s);
}

Shell run

mio.h provides shell run helper (needs MIO_SHELL), example:

// Takes in a vector of strings
// Could do: std::vector<std::string> cmds = {"ffmpeg", "-version"};
// auto cmd = mio::run(cmds);
auto cmd = mio::run({"ffmpeg", "-version"});
std::println("Output: {}, code: {}", cmd.out, cmd.code);

doctest

This template also sets up tests inside src/tests, follow the tests.cpp example and continue it. To run the tests:

make test

Nob

This template uses nob.h (nobuild made by Rexim) for building the project. The whole build script is defined in "nob.c". All the targets builds inside build/MODENAME/

# Bootstrap nob once
cc -o nob nob.c

# debug build
./nob

# release build
./nob release

# run doctest from "src/tests/tests.cpp"
./nob test