简体中文 | English
A tiny, minimalist Swiss Army knife for C++.
coost is a lightweight, high-performance, easy-to-use C++ base library. It supports Linux, macOS, Windows, FreeBSD, and CPU architectures such as x86, x64, ARM, and ARM64.
coost, abbreviated as co, includes go-style coroutines, networking, logging, config parsing, unit testing, benchmarking, memory allocator, and other components. Its goal is to make C++ programming simple and enjoyable.
coost remains open source. If you use coost in production and need in-depth support such as custom development, architecture adaptation (RISC-V / MIPS), coroutine hooks, performance optimization, or team training, the author offers paid commercial support to reduce risk and save time.
For service packages, pricing, and process, see:
Contact the author via GitHub Issues or email idealvin@qq.com. A free initial diagnosis is available to assess scope and feasibility.
The documentation currently lags behind the latest version of coost. Please refer to the latest code and the include/co headers for the most accurate information.
flag is a command-line argument and config file parsing library. It supports flag aliases, automatic config file generation, and more.
#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;
}coost implements a coroutine mechanism similar to goroutine in Golang. It has the following features:
- Multi-thread scheduling. By default, the number of scheduling threads is the number of CPU cores.
- Shared stacks. Coroutines in the same thread share several stacks (default size 1MB), resulting in low memory usage.
- Supports coroutine synchronization events, coroutine locks, waitgroup.
#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;
}coost provides a coroutine-based network programming framework:
- Socket API. It is similar in form to the system socket API. Users familiar with socket programming can easily write high-performance network programs in a synchronous style.
- TCP. Simple encapsulation of TCP server and client, compatible with IPv6.
- RPC. A simple RPC framework using JSON for serialization.
log is a high-performance logging component. It supports printing stack traces when the program crashes.
#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;
}log is very fast. Here are some test results:
| platform | glog | co/log | speedup |
|---|---|---|---|
| win2012 HDD | 1.6MB/s | 180MB/s | 112.5 |
| win10 SSD | 3.7MB/s | 560MB/s | 151.3 |
| mac SSD | 17MB/s | 450MB/s | 26.4 |
| linux SSD | 54MB/s | 1023MB/s | 18.9 |
The table above shows the write speed comparison between co/log and glog when continuously printing 1 million logs in a single thread. co/log is nearly two orders of magnitude faster than glog.
| threads | linux co/log | linux spdlog | win co/log | win spdlog | speedup |
|---|---|---|---|---|---|
| 1 | 0.087235 | 2.076172 | 0.117704 | 0.461156 | 23.8/3.9 |
| 2 | 0.183160 | 3.729386 | 0.158122 | 0.511769 | 20.3/3.2 |
| 4 | 0.206712 | 4.764238 | 0.316607 | 0.743227 | 23.0/2.3 |
| 8 | 0.302088 | 3.963644 | 0.406025 | 1.417387 | 13.1/3.5 |
The table above shows the time consumed to print 1 million logs with 1, 2, 4, and 8 threads respectively, in seconds. speedup is the performance improvement factor of co/log over spdlog on Linux and Windows.
unitest is a simple and easy-to-use unit testing framework. Many components in coost use it to write unit test code, providing important assurance for coost's stability.
#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 above is a simple example. The DEF_test macro defines a test unit, which is actually a function. The DEF_case macro defines a test case, and each test case is actually a code block.
The coost/unitest directory contains the unit test code in coost. Run the following commands to build and run:
xmake b unitest
xmake r unitest # run all unit test cases
xmake r unitest -os # run only test cases in the os unit; os is the unit test namebenchmark is a simple and easy-to-use performance benchmark framework.
#include "co/benchmark.h"
#include "co/atomic.h"
BM_group(atomic) {
int i = 0;
BM_add(atomic_inc) {
co::atomic_inc(&i);
}
BM_use(i);
BM_add(atomic_dec) {
co::atomic_dec(&i);
}
BM_use(i);
}The coost/benchmark directory contains some performance test code. Run the following commands to build and run:
xmake b benchmark
xmake r benchmark # run all benchmark code by default
xmake r benchmark -mem # run only benchmark code in BM_group(mem)JSON adopts a fluent interface design, making it easier to use.
// {"a":23,"b":false,"s":"123","v":[1,2,3],"o":{"xx":0}}
json::any x = {
{ "a", 23 },
{ "b", false },
{ "s", "123" },
{ "v", {1,2,3} },
{ "o", {
{"xx", 0}
}},
};
// equal to x
json::any y = Json()
.add_member("a", 23)
.add_member("b", false)
.add_member("s", "123")
.add_member("v", Json().push_back(1).push_back(2).push_back(3))
.add_member("o", Json().add_member("xx", 0));
x.get("a").as_int(); // 23
x.get("s").as_string(); // "123"
x.get("s").as_int(); // 123, string -> int
x.get("v", 0).as_int(); // 1
x.get("v", 2).as_int(); // 3
x.get("o", "xx").as_int(); // 0Below is the performance comparison between co/json and rapidjson:
| os | co/json stringify | co/json parse | rapidjson stringify | rapidjson parse | speedup |
|---|---|---|---|---|---|
| win | 569 | 924 | 2089 | 2495 | 3.6/2.7 |
| mac | 783 | 1097 | 1289 | 1658 | 1.6/1.5 |
| linux | 468 | 764 | 1359 | 1070 | 2.9/1.4 |
The table above shows the average time for stringify and parse measured after minifying twitter.json, in microseconds (us). speedup is the performance improvement factor of co/json over rapidjson in stringify and parse.
-
Header files of coost.
-
Source code of coost, which compiles into libco.
-
Performance benchmark code. Each
.ccfile corresponds to a different test unit, and all code is compiled into a single test program. -
Test code. Each
.ccfile is compiled into a separate test program. -
Unit test code. Each
.ccfile corresponds to a different test unit, and all code is compiled into a single test program. -
Code generation tools.
The latest version of coost requires a compiler that supports C++17:
coost recommends xmake as the build tool.
# All commands are executed in the coost root directory, and this will not be repeated below
xmake # build libco by default
xmake -a # build all projects (libco, benchmark, gen, test, unitest)On Linux and macOS, printing stack traces on crashes requires libbacktrace. Newer versions of gcc on Linux already have a built-in backtrace library; on macOS it usually needs to be installed manually.
xmake f --with_backtrace=true
xmake b stack # test/stack.cc
xmake r stack # run stack test programxmake install -o pkg # package and install to the pkg directory
xmake i -o pkg # same as above
xmake install -o /usr/local # install to /usr/localmkdir cmakebuild && cd cmakebuild
cmake ..
make -j8mkdir cmakebuild && cd cmakebuild
cmake .. -DBUILD_ALL=ON -DCMAKE_INSTALL_PREFIX=/usr/local
make -j8
cd bin
./unitest # run unit test programmkdir cmakebuild && cd cmakebuild
cmake .. -DWITH_BACKTRACE=ON
make -j8The MIT license. coost includes code from some other projects, which may use different licenses. See LICENSE.md for details.
- The related code of context is taken from ruki's tbox. ruki also helped improve the xmake build script. Special thanks!
- izhengfan provided the cmake build script. Special thanks!
- SpaceIm improved the cmake build script and provided
find_packagesupport. Special thanks! - Leedehai and daidai21 helped translate coost's Chinese reference documentation into English in the early days. Special thanks!