Skip to content
Merged

Dev #45

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
8edfb98
fix: correct CLI filter parsing and add machine-readable test listing
sunxfancy Aug 23, 2026
d91f03e
fix: allow enum class and smart pointers in CHECK/LOG
sunxfancy Aug 23, 2026
62797e4
Merge pull request #38 from sunxfancy/codex/evengine-zeroerr-integration
sunxfancy Aug 23, 2026
8ca2273
fix(print): handle unstreamable enums
sunxfancy Sep 3, 2026
d94c6a5
Merge pull request #39 from sunxfancy/codex/unprintable-enum-diagnostics
sunxfancy Sep 3, 2026
fc9d51d
fix: scope warning suppression and keep consumer macros clean
sunxfancy Sep 7, 2026
4bfea52
Merge pull request #40 from sunxfancy/codex/warning-hygiene
sunxfancy Sep 9, 2026
3001b9d
feat(print): support function pointers and std::function
sunxfancy Oct 25, 2026
e8b3d9a
fix: eliminate remaining build warnings and fix example encoding
sunxfancy Oct 25, 2026
086b661
refactor(print): match capabilities without STL type dependencies
sunxfancy Oct 25, 2026
9b5ae45
Merge pull request #41 from sunxfancy/codex/print-function-types
sunxfancy Oct 25, 2026
0d70713
fix(serialization): include stdexcept for standalone headers
sunxfancy Oct 25, 2026
62f0079
Merge dev and preserve capability-based pointer dispatch
sunxfancy Oct 25, 2026
5792cae
Merge pull request #42 from sunxfancy/codex/remaining-warning-cleanup
sunxfancy Oct 25, 2026
5e5546e
Merge dev warning cleanup and retain capability regression tests
sunxfancy Oct 25, 2026
05f1bdf
feat: isolate core text storage and lighten default headers
sunxfancy Oct 25, 2026
30f1ddf
Merge pull request #43 from sunxfancy/codex/capability-based-printing
sunxfancy Oct 25, 2026
65bbde8
merge: integrate dev fixes with lightweight text backend
sunxfancy Oct 25, 2026
ee11604
merge: retain capability printing with internal string buffers
sunxfancy Oct 25, 2026
56e70d1
fix: enforce lightweight includes across libc++ consumers
sunxfancy Oct 25, 2026
69735be
Merge pull request #44 from sunxfancy/codex/lightweight-string-runtime
sunxfancy Oct 25, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 15 additions & 2 deletions .github/workflows/cmake.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ name: CMake

on:
push:
branches: [ "master" ]
branches: [ "master", "dev" ]
pull_request:
branches: [ "master" ]
branches: [ "master", "dev" ]

jobs:
build:
Expand All @@ -14,12 +14,24 @@ jobs:
name: Build on ${{ matrix.os }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest, macOS-latest]

steps:
- uses: actions/checkout@v4

- name: Check Clang warning hygiene
if: runner.os != 'Windows'
run: python3 scripts/check-warning-hygiene.py --compiler clang++

- name: Configure lightweight header checks
run: cmake -S test/lightweight -B build-lightweight -DCMAKE_BUILD_TYPE=Release
- name: Build lightweight header checks
run: cmake --build build-lightweight --config Release --parallel 2
- name: Test lightweight header checks
run: ctest --test-dir build-lightweight -C Release --output-on-failure

- name: Configure CMake
# Configure CMake in a 'build' subdirectory.
run: bash ${{github.workspace}}/scripts/build-all.sh config ${{github.workspace}}
Expand All @@ -32,3 +44,4 @@ jobs:
# See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail
- name: Test
run: bash ${{github.workspace}}/scripts/build-all.sh test ${{github.workspace}}

3 changes: 2 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ if(MAIN_PROJECT)
endif()

if(BUILD_TEST)
enable_testing()
add_subdirectory(test)
endif()

Expand Down Expand Up @@ -152,7 +153,7 @@ if(MAIN_PROJECT)
# # Install
install(TARGETS zeroerr DESTINATION lib)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/zeroerr.hpp DESTINATION include)
install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/include DESTINATION include/..)
install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/include/ DESTINATION include)
else()
# Export Headerfiles
set(ZEROERR_INCLUDE_DIR ${header_dirs} PARENT_SCOPE)
Expand Down
3 changes: 2 additions & 1 deletion Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -253,4 +253,5 @@ While logging at the end, we can record the time consuming for this function.
## The logo generation

Thanks to the `tiv` tool:
https://github.com/stefanhaustein/TerminalImageViewer
https://github.com/stefanhaustein/TerminalImageViewer
See [header dependencies and optional modules](docs/dependencies.md) for the lightweight consumer contract, runtime dependencies and migration notes.
2 changes: 2 additions & 0 deletions Readme.zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -216,3 +216,5 @@ cmake --build ./build




See [header dependencies and optional modules](docs/dependencies.md) for the lightweight consumer contract, runtime dependencies and migration notes.
32 changes: 32 additions & 0 deletions docs/dependencies.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Header dependencies and optional modules

A normal translation unit may include `zeroerr.hpp` (or modular `zeroerr.h`) without defining `ZEROERR_IMPLEMENTATION`. Assertions, logging, printing and unit tests are available by default. Core text storage uses `zeroerr::String`; `Printer::os` is a `zeroerr::StringBuffer`.

Default consumer headers do not include the implementations of `<string>`, `<ostream>`, `<iostream>`, `<sstream>`, `<chrono>`, `<regex>`, `<mutex>` or `<complex>`. This is not a promise of no standard library: core declarations still use lightweight facilities including containers, tuples, memory, type traits, atomics and exceptions. `<iosfwd>` supplies forward declarations for the reporter interface. Transitive dependencies can differ by standard-library vendor; `test/lightweight/forbidden_headers.h` checks the supported header guards to catch regressions.

Define the following macros before including the umbrella header to enable optional modules:

- `ZEROERR_ENABLE_BENCHMARK`: benchmarking (including its table rendering implementation).
- `ZEROERR_ENABLE_FUZZTEST`: fuzz testing, domains and serialization.
- `ZEROERR_ENABLE_TABLE`: tables.
- `ZEROERR_ENABLE_STD_ADAPTER`: standard stream insertion and common manipulators. This explicitly includes string and stream headers.

With modular headers, explicitly include `zeroerr/benchmark.h`, `zeroerr/fuzztest.h`, `zeroerr/table.h` or `zeroerr/std_adapter.h` instead. Enable optional modules consistently where their definitions are needed, including the single implementation translation unit. Defining `ZEROERR_IMPLEMENTATION` alone does not enable optional modules.

## Runtime boundary

Exactly one translation unit may define `ZEROERR_IMPLEMENTATION` before including `zeroerr.hpp`, or the application can link the compiled library. This implementation is allowed to include standard-library runtime facilities: streams and strings for test capture, reports and file output; regex for test filtering; chrono for timing; mutex for synchronization; and standard exceptions for error reporting. These dependencies are intentionally confined to implementation sources. Optional fuzz/benchmark/table modules may add further dependencies when explicitly enabled.

## Compatibility and migration

Common assertion, log, test and formatting call syntax is retained. String results and stored names/messages now use `zeroerr::String`, which provides `data()`, `size()`, `c_str()`, concatenation and common search operations. Conversions to and from compatible owning string types are templates; applications using `std::string` must include `<string>` themselves. This is a source migration for explicitly typed callbacks, containers and reference bindings, and an ABI change: rebuild all library consumers together.

`Printer` captures into its own `StringBuffer` by default. `Printer(stream)` still attaches a supplied stream with `write` and `flush` methods; the caller includes that stream's headers. The legacy `use_stringstream` flag now indicates capture mode. Extensions using `P.os << value` work for core supported values. Include `zeroerr/std_adapter.h` for standard stream-only custom types and common manipulators. `StringBuffer` is not a complete `std::ostream`: native `std::ostream&` APIs need an explicit temporary stream and then a buffer write; locale and all standard formatting flags are not emulated.

Public timing fields use `zeroerr::Duration` (seconds, with `count()`) and `zeroerr::Timestamp` (nanoseconds). Code explicitly naming their former chrono types must adapt. Core type definitions do not depend on which standard headers the application included first.

## Verification

`cmake -S test/lightweight -B build-lightweight`, followed by a build and CTest, checks modular and single-header consumers, include order, internal string behavior, XML reporting and explicitly enabled optional modules. The runtime translation unit is deliberately outside the forbidden-header check.

For libc++ versions with compatibility transitive includes, core headers temporarily set `_LIBCPP_REMOVE_TRANSITIVE_INCLUDES` while loading their explicit standard dependencies, then restore the caller's setting with `push_macro`/`pop_macro`. This suppresses incidental compatibility includes without changing library types or the caller's configuration.
44 changes: 35 additions & 9 deletions docs/pages/en/5.print.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,29 @@ Printer MultiFunctor
====================
[TOC]

Printer is a template based multifunctor which can print any type. Printer is a stateful functor which support printing to any `std::ostream` or `std::stringstream` if not specified.
Printer is a stateful template functor. It captures text in an internal `StringBuffer` by default and can attach an explicitly supplied output stream. See [header dependencies](../../dependencies.md) for optional standard stream support.

### Capability matching and header dependencies

Printing rules inspect operations rather than specific STL template names:

- Containers expose const `begin()/end()` and copyable, incrementable iterators. Indexable containers use brackets.
- Map elements expose `first/second`; complex values expose arithmetic `real()/imag()` results.
- Text exposes `traits_type::char_type = char` and `data()/size()`, or converts to `const char*`. Ordinary character containers remain containers.
- Pointer wrappers expose `get()` convertible to `const void*`; weak wrappers expose `lock()` returning such a wrapper.
- Tuple protocols expose `std::tuple_size<T>` and ADL-accessible `get<I>(const T&)`. Containers take precedence over tuples.

Include the headers defining your types yourself. `<tuple>`, `<complex>`, `<memory>`, etc. may appear before or after `zeroerr/print.h`, provided the types are complete before printing. Printing neither copies values nor takes ownership of smart pointers.

The print header retains its `std::ostream` and `std::string` interfaces. Stringstream management and type-name demangling live in `.cpp` implementations: link the zeroerr library, or define `ZEROERR_IMPLEMENTATION` in one translation unit when using the single header.

### Construction

Printer can be constructed with or without a `std::ostream` object:
Printer can capture text or attach a stream supplied by the caller:

```cpp
Printer(); // print to std::stringstream
Printer(std::ostream& os); // print to 'os'
Printer(); // capture into StringBuffer
template<class Stream> explicit Printer(Stream& os); // attach caller's stream
```

There are helper functions to get a global printer object that print to stdout or stderr:
Expand Down Expand Up @@ -42,6 +56,11 @@ Output:
1 1 <int* at 0x7ffebc813ed4>
```

Function pointers print as `<function-pointer-type at address>`. An empty function
pointer prints as `nullptr`. `std::function` prints as
`<wrapper-type holding target-type>`, or `nullptr` when empty. Printing never calls
the target. These values are also supported inside containers and tuples.

STL container support:

```cpp
Expand Down Expand Up @@ -128,7 +147,7 @@ The functor can be configured with different mode:
The printer can be used in a stream once you constructed it without giving a output stream.

```cpp
Printer print(); // print to stringstream
Printer print; // capture into StringBuffer
std::cerr << print("hello world") << std::endl;
```

Expand All @@ -152,8 +171,11 @@ PrinterExt(Printer& P, T* s, unsigned level, const char* lb, rank<1>) {
if (s == nullptr) {
P.os << P.tab(level) << "nullptr" << lb;
} else {
llvm::raw_os_ostream os(P.os);
std::string text; // explicitly include <string> and LLVM raw_ostream headers
llvm::raw_string_ostream os(text);
s->print(os);
os.flush();
P.os << text;
}
}

Expand All @@ -167,9 +189,13 @@ typename std::enable_if<std::is_base_of<llvm::Function, T>::value, void>::type P
if (s == nullptr) {
P.os << P.tab(level) << "nullptr" << lb;
} else {
llvm::raw_os_ostream os(P.os);
os << P.tab(level) << "Function " << FgCyan << *s << Reset;
std::string text; // explicitly include <string> and LLVM raw_ostream headers
llvm::raw_string_ostream os(text);
P.os << P.tab(level) << "Function " << FgCyan;
os << *s;
os.flush();
P.os << text << Reset;
}
}
} // namespace zeroerr
```
```
43 changes: 34 additions & 9 deletions docs/pages/zh/5.print.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,29 @@ Printer MultiFunctor
====================
[TOC]

`Printer` 是一个用来打印任意类型数据的模板类。本身是一个有状态的MultiFunctor, 可以打印到`std::ostream` 或者 `std::stringstream`。
`Printer` 是一个有状态的模板打印类,默认使用内部 `StringBuffer` 保存文本,也可连接调用方显式提供的输出流。标准流适配需显式启用,参见[头文件依赖约定](../../dependencies.md)。

### 按能力匹配与头文件依赖

打印器通过类型提供的操作选择规则,不要求类型必须是某种 STL 模板:

- 容器提供 const `begin()/end()` 和可复制、可递增的迭代器;支持下标的容器使用方括号。
- 映射元素提供 `first/second`;复数提供返回算术值的 `real()/imag()`。
- 文本提供 `traits_type::char_type = char`、`data()/size()`,或可转换为 `const char*`。普通字符容器仍按容器打印。
- 指针包装提供可转换为 `const void*` 的 `get()`;弱引用提供返回这类包装的 `lock()`。
- tuple 协议提供 `std::tuple_size<T>` 和可通过 ADL 找到的 `get<I>(const T&)`。容器优先于 tuple 规则。

调用方自行包含 `<tuple>`、`<complex>`、`<memory>` 等类型定义;放在 `zeroerr/print.h` 之前或之后都可以,只需在打印调用前定义完整。打印不会复制对象或取得智能指针的所有权。

打印头仍保留现有 `std::ostream` 和 `std::string` 接口。stringstream 管理及类型名 demangle 的实现位于 `.cpp`:使用时链接 zeroerr 库,或在单头文件模式中于一个翻译单元定义 `ZEROERR_IMPLEMENTATION`。

### 构造函数

您可以选择打印到内置的 `stringstream` 或者您传入的一个 `std::ostream`。
可以选择将文本保存在内部缓冲区,或者连接调用方提供的流。`str()` 返回内部 `zeroerr::String`。

```c++
Printer(); // print to std::stringstream
Printer(std::ostream& os); // print to 'os'
Printer(); // capture into StringBuffer
template<class Stream> explicit Printer(Stream& os); // attach caller's stream
```
如果想快速获得一个能打印到标准输出流的对象,可以调用如下方法:

Expand Down Expand Up @@ -41,6 +55,10 @@ Output:
1 1 <int* at 0x7ffebc813ed4>
```

函数指针输出为 `<函数指针类型 at 地址>`,空函数指针输出为 `nullptr`。
`std::function` 输出为 `<包装类型 holding 目标类型>`,为空时输出 `nullptr`。
打印不会调用目标函数,也支持容器和元组中的这些类型。

同时支持 STL container:

```c++
Expand Down Expand Up @@ -126,7 +144,7 @@ Output:


```c++
Printer print(); // print to stringstream
Printer print; // capture into StringBuffer
std::cerr << print("hello world") << std::endl;
```

Expand All @@ -151,8 +169,11 @@ PrinterExt(Printer& P, T* s, unsigned level, const char* lb, rank<1>) {
if (s == nullptr) {
P.os << P.tab(level) << "nullptr" << lb;
} else {
llvm::raw_os_ostream os(P.os);
std::string text; // explicitly include <string> and LLVM raw_ostream headers
llvm::raw_string_ostream os(text);
s->print(os);
os.flush();
P.os << text;
}
}

Expand All @@ -166,9 +187,13 @@ typename std::enable_if<std::is_base_of<llvm::Function, T>::value, void>::type P
if (s == nullptr) {
P.os << P.tab(level) << "nullptr" << lb;
} else {
llvm::raw_os_ostream os(P.os);
os << P.tab(level) << "Function " << FgCyan << *s << Reset;
std::string text; // explicitly include <string> and LLVM raw_ostream headers
llvm::raw_string_ostream os(text);
P.os << P.tab(level) << "Function " << FgCyan;
os << *s;
os.flush();
P.os << text << Reset;
}
}
} // namespace zeroerr
```
```
40 changes: 27 additions & 13 deletions docs/pages/zh/6.unittest.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,17 +86,31 @@ SCENARIO("用户登录") {
### 配置选项

UnitTest提供了多个命令行配置选项:
- verbose: 输出测试结果
- quiet: 不输出测试结果
- bench: 启用定义的基准测试
- fuzz: 启用定义的模糊测试
- list-test-cases: 列出所有测试用例
- no-color: 不使用彩色输出
- log-to-report: 将测试结果记录到报告中
- correct_output_path: 存储黄金文件的路径
- reporters: 用于报告测试结果的报告器名称(支持console, xml两种)
- testcase: 运行指定名称的测试用例
- testcase-exclude: 排除指定名称的测试用例
- file: 运行指定文件的测试用例
- file-exclude: 排除指定文件的测试用例
- `-h, --help`: 显示命令行帮助
- `-v, --verbose`: 输出测试结果
- `-q, --quiet`: 不输出测试结果
- `-l, --list-test-cases`: 列出所有测试用例
- `-b, --bench`: 启用定义的基准测试
- `-f, --fuzz`: 启用定义的模糊测试
- `--list-format=FORMAT`: 列表输出格式,`console`(默认)或`plain`
- `--no-color`: 不使用彩色输出
- `--log-to-report`: 将测试结果记录到报告中
- `--reporters=NAME`: 报告器名称(支持`console`, `xml`两种)
- `-x`: `--reporters=xml` 的简写
- `--testcase=REGEX`: 运行名称匹配 `REGEX` 的测试用例
- `--testcase-exclude=REGEX`: 排除名称匹配 `REGEX` 的测试用例
- `--file=REGEX`: 运行文件匹配 `REGEX` 的测试用例
- `--file-exclude=REGEX`: 排除文件匹配 `REGEX` 的测试用例

`--testcase` / `--testcase-exclude` 等过滤条件使用**完整匹配**的正则表达式,
例如只运行 `data` 开头的用例应写作 `--testcase=^data\..*$`。

`--list-format=plain` 提供机器可读的测试列表,每行输出
`<用例名>\t<源文件名>:<行号>` 到标准输出,适合被 CTest 等构建工具解析,
例如:

```
data.ByteData.roundTrip data.cpp:42
data.JsonDocument.queryBoundaries data.cpp:88
```

7 changes: 4 additions & 3 deletions examples/2_log.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ TEST_CASE("1. basic log test") {
LOG("log with basic thype {} {} {} {}", 1, true, 1.0, "string");

std::vector<std::tuple<int, float, std::string>> data = {
{1, 1.0, "string"}, {2, 2.0, "string"}
{1, 1.0f, "string"}, {2, 2.0f, "string"}
};
LOG("log with complex type: {data}", data);

Expand All @@ -30,7 +30,7 @@ struct Expr {
virtual ~Expr() {}
};

Expr* parse_the_input(std::string input) {
Expr* parse_the_input(std::string /*input*/) {
return new Expr();
}

Expand All @@ -51,12 +51,13 @@ Expr* parseExpr(std::string input)
TEST_CASE("parsing test") {
zeroerr::suspendLog();
std::string log;
Expr* e1 = parseExpr("1 + 2");
parseExpr("1 + 2");
log = LOG_GET(parseExpr, "CacheHit", input, std::string);
CHECK(log == std::string{});
Expr* e2 = parseExpr("1 + 2");
log = zeroerr::LogStream::getDefault()
.getLog<std::string>("parseExpr", "CacheHit", "input");
delete e2;
CHECK(log == "1 + 2");
zeroerr::resumeLog();
}
Expand Down
4 changes: 4 additions & 0 deletions examples/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
macro(define_example name)
add_executable(${name} ${CMAKE_CURRENT_SOURCE_DIR}/${name}.cpp)
add_dependencies(${name} assemble_single_header)
target_compile_options(${name} PRIVATE
$<$<CXX_COMPILER_ID:MSVC>:/W4 /utf-8>
$<$<NOT:$<CXX_COMPILER_ID:MSVC>>:-Wall -Wextra -Wpedantic>
)
endmacro(define_example)

define_example(1_basic)
Expand Down
14 changes: 13 additions & 1 deletion include/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@

set(include_files
${CMAKE_CURRENT_SOURCE_DIR}/zeroerr/buffer.h
${CMAKE_CURRENT_SOURCE_DIR}/zeroerr/std_adapter.h
${CMAKE_CURRENT_SOURCE_DIR}/zeroerr/internal/time.h
${CMAKE_CURRENT_SOURCE_DIR}/zeroerr/internal/fuzz_signal.h
${CMAKE_CURRENT_SOURCE_DIR}/zeroerr/string.h
${CMAKE_CURRENT_SOURCE_DIR}/zeroerr/internal/text.h
${CMAKE_CURRENT_SOURCE_DIR}/zeroerr/internal/typetraits.h
${CMAKE_CURRENT_SOURCE_DIR}/zeroerr/internal/config.h
${CMAKE_CURRENT_SOURCE_DIR}/zeroerr/internal/console.h
${CMAKE_CURRENT_SOURCE_DIR}/zeroerr/internal/debugbreak.h
Expand All @@ -20,4 +27,9 @@ set(include_files
${CMAKE_CURRENT_SOURCE_DIR}/zeroerr/unittest.h
)

set(include_files ${include_files} PARENT_SCOPE)
set(include_files
${CMAKE_CURRENT_SOURCE_DIR}/zeroerr/buffer.h
${CMAKE_CURRENT_SOURCE_DIR}/zeroerr/std_adapter.h
${CMAKE_CURRENT_SOURCE_DIR}/zeroerr/internal/time.h
${CMAKE_CURRENT_SOURCE_DIR}/zeroerr/internal/fuzz_signal.h
${CMAKE_CURRENT_SOURCE_DIR}/zeroerr/string.h ${include_files} PARENT_SCOPE)
Loading
Loading