# coost: goroutines, shared stacks and a logger, all in one C++ base library

> coost, abbreviated co, is a lightweight, MIT-licensed C++ base library covering go-style coroutines with shared stack scheduling, a coroutine based networking stack with sockets, TCP and JSON RPC, a high performance logger with crash stack traces, flag and config parsing, unit testing and benchmarking. It runs on Linux, macOS, Windows and FreeBSD across x86, x64, ARM and ARM64, with v4.0.0 arriving in September 2026 after a three year release gap.

**idealvin/coost** — A tasteful, minimal C++ base library.

- Repository: https://github.com/idealvin/coost
- Stars: 4,216 · Forks: 592
- Language: C++
- License: NOASSERTION
- Published: 2026-09-23 · Updated: 2026-09-23 · Language: en
- Canonical page: https://hysenlabs.com/projects/idealvin-coost

## Goroutines in C++, with shared stacks

The headline component is a coroutine mechanism similar to goroutine in Golang, and the design choices mirror it closely. Scheduling is multi-threaded, with the number of scheduling threads defaulting to the number of CPU cores, and stacks are shared, coroutines in the same thread share several stacks of default 1MB size, keeping memory usage low. Synchronization knows about coroutine events, coroutine locks and a wait_group directly modeled on Go's WaitGroup:

```cpp
#include "co/co.h"
#include "co/flag.h"
#include "co/print.h"

int main(int argc, char** argv) {
    flag::parse(argc, argv);

    co::wait_group wg(2);

    go([wg](){
        co::println("hello world");
        wg.done();
    });

    go([wg](){
        co::println("hello again");
        wg.done();
    });

    wg.wait();
    return 0;
}
```

The go keyword becomes a go function taking a lambda, and the mental model transfers wholesale. The shared stack trick deserves emphasis, most coroutine libraries give each coroutine its own stack reservation, which multiplies memory by concurrency, while sharing a handful of 1MB stacks across the coroutines of a thread keeps footprint flat as coroutine counts climb into the hundreds of thousands.

## flag: one parser for argv and config files

Command line and configuration handling merge into one component, flag, a library for command-line argument and config file parsing that supports flag aliases and automatic config file generation. Definitions are macros at file scope, with type, default and comment in one place:

```cpp
#include "co/flag.h"
#include "co/print.h"

DEF_bool(x, false, "Comment here");
DEF_int32(n, 0, "Comment here");
DEF_string(s, "hello world", "Comment here");

int main(int argc, char** argv) {
    flag::parse(argc, argv);
    co::println("x: ", FLG_x);
    co::println("n: ", FLG_n);
    co::println("s: ", FLG_s);
    return 0;
}
```

Values live in FLG_ prefixed identifiers after a single parse call in main, and the automatic generation means a documented config file can be produced from the flags rather than maintained by hand, the small feature that keeps configuration and documentation from drifting apart.

## Sockets, TCP and JSON RPC

The networking layer is coroutine based, and its three tiers match how network programs actually grow. The Socket API is similar in form to the system socket API, so users familiar with socket programming can write high-performance network programs in a synchronous style, the coroutine scheduler absorbing the blocking that would otherwise demand callbacks or threads. Above it, TCP provides simple encapsulation of server and client, compatible with IPv6. And at the top, an RPC framework uses JSON for serialization, a simple remote call layer without schema compilers or code generation. The progression means a coost program can start with raw sockets where control matters, use TCP objects for ordinary services, and add RPC where cross-service calls begin, without leaving the library or changing concurrency model. IPv6 compatibility at the TCP layer is worth calling out, since many minimal networking layers ship IPv4 first and treat the newer protocol as an afterthought rather than a default capability.

## log, with stack traces when it crashes

The logging component emphasizes performance and post-mortem visibility, supporting the printing of stack traces when the program crashes. The interface is terse:

```cpp
#include "co/log.h"

int main(int argc, char** argv) {
    flag::parse(argc, argv);
    log::info("hello ", 23);   // info
    log::warn("hello ", 23);   // warning
    log::error("hello ", 23);  // error
    log::check(1+1==2, "xx");  // runtime assertion; prints stack trace and exits on failure
    return 0;
}
```

The levels are the familiar three plus a check macro that combines assertion with stack trace output and exit on failure, turning a failed invariant into a diagnosable crash rather than a silent continuation. Combined with the coroutine scheduler, a crash report can show where in coroutine execution the failure happened, which is the information a server operator actually needs at three in the morning.

## Two orders of magnitude over glog, published

The README publishes its logging benchmarks in full context. Against glog, continuously printing 1 million logs in a single thread, co/log writes 180MB/s versus 1.6MB/s on Windows 2012 with an HDD, a 112.5 times speedup, 560 versus 3.7MB/s on Windows 10 SSD at 151.3 times, 450 versus 17MB/s on mac SSD at 26.4 times, and 1023 versus 54MB/s on Linux SSD at 18.9 times, which the text summarizes as nearly two orders of magnitude faster than glog. Against spdlog, printing 1 million logs at 1, 2, 4 and 8 threads takes 0.087 to 0.302 seconds on Linux and 0.118 to 0.406 on Windows, with speedups of roughly 13 to 24 times on Linux and 2.3 to 3.9 times on Windows. These are the project's own numbers, reproducible through the bundled benchmark framework rather than accepted on faith. The thread scaling rows also tell a subtler story, co/log's time grows gently from 0.087 seconds at one thread to 0.302 at eight on Linux, so contention does not eat the gains as concurrency rises, which is where fast loggers usually falter.

## unitest and benchmark as macro frameworks

Testing and measurement ship inside the library. unitest is a simple unit testing framework where DEF_test defines a test unit that is actually a function and DEF_case defines a test case that is a code block, with EXPECT macros for assertions, and many components in coost use it for their own unit tests, which the documentation credits as important assurance for the library's stability:

```cpp
#include "co/unitest.h"
#include "co/os.h"

DEF_test(os) {
    DEF_case(homedir) {
        EXPECT_NE(os::homedir(), "");
    }

    DEF_case(cpunum) {
        EXPECT_GT(os::cpunum(), 0);
    }
}

int main(int argc, char** argv) {
    flag::parse(argc, argv);
    co::run_unitests();
    return 0;
}
```

The benchmark framework follows the same macro pattern with BM_group and BM_add. Tests build and run through xmake, xmake b unitest then xmake r unitest for all cases or xmake r unitest -os to filter to one unit like os.

## Commercial support, and a 4.0 after three years

The project stays open source while its author offers paid commercial support for production users, naming the services specifically, custom development, architecture adaptation for RISC-V and MIPS, coroutine hooks, performance optimization, and team training, with a free initial diagnosis to assess scope and feasibility and contact through GitHub issues or email. Documentation exists in English and Chinese at coostdocs.github.io, matching the bilingual readme. The release history has a distinctive shape, v3.0.2 in November 2023, then v4.0.0 on 2026-09-15 and v4.0.1 on 2026-09-28, a long quiet period ending in a major version restart, with the repository pushed 2026-09-26. Builds support both xmake and CMake from the same tree, and the license is MIT per the badge and LICENSE.md despite GitHub reporting it as unclassified.

## Conclusion

Choose coost when a C++ project wants the ergonomics of a small standard library replacement, goroutine shaped concurrency, synchronous looking network code and a fast logger, without pulling in a large framework. Compare it against Boost.Asio based stacks when ecosystem breadth matters more than minimalism, and against C++20 coroutines when standard language facilities suffice. Before adopting, review the published logging benchmarks against your own workload, verify your target architecture is among the supported x86, x64, ARM and ARM64 set, with RISC-V and MIPS adaptation available only through paid commercial support, and note the v4 line is days old, with v3.0.2 the previous release back in 2023.

## FAQ

### What is coost?

coost, abbreviated co, is a lightweight, high-performance, easy-to-use C++ base library supporting Linux, macOS, Windows and FreeBSD on x86, x64, ARM and ARM64. It includes go-style coroutines, a coroutine based networking stack, logging, config parsing, unit testing, benchmarking and a memory allocator, aiming to make C++ programming simple and enjoyable.

### How fast is coost's logging?

The project's published tests show co/log writing 1023MB/s versus glog's 54MB/s on Linux SSD when printing 1 million logs single-threaded, speedups of roughly 19 to 151 times over glog across platforms, and beating spdlog by about 13 to 24 times on Linux and 2.3 to 3.9 times on Windows at 1 to 8 threads.

### How do you run coost's unit tests?

Build with xmake b unitest, then run all cases with xmake r unitest, or filter to a single unit with xmake r unitest -os to run only the os unit's cases. The unitest directory contains the test code for the whole library, written with the DEF_test and DEF_case macros.

## Sources

- [idealvin/coost on GitHub](https://github.com/idealvin/coost)
- [Issues](https://github.com/idealvin/coost/issues)
- [README](https://github.com/idealvin/coost/blob/master/README.md)
- [Releases](https://github.com/idealvin/coost/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/idealvin-coost
