mirror of
https://github.com/shadowsocks/shadowsocks-libev.git
synced 2026-10-20 12:51:50 +00:00
* Enable C++20 alongside C11 in the build Add CXX to the project with C++20 (no extensions) and build C++ sources with -Wextra -fno-exceptions -fno-rtti -fno-threadsafe-statics on top of the existing warning flags. Give every toolchain a C++ compiler: the zig Windows toolchain, the static macOS/Windows CI jobs, the static musl image (clang++ plus libstdc++ headers) and the RPM spec. * Add C++20 ownership and allocation core Header-only primitives for the no-heap-after-startup design: Result/Status, Region, ObjectPool with PoolPtr (std::unique_ptr with a pool deleter), generation-checked Handle and asynchronous close support, intrusive RefPtr, FixedBuffer, MonotonicArena, FixedHashMap and FixedLru, IntrusiveList, and a bounded FixedHeap for third-party allocator hooks. Unit tests cover each primitive (test_core_*). scripts/check_no_heap.py rejects heap allocation in C++ sources under src/ and runs as a ctest. clang-tidy now also analyses C++ sources and the core headers. * Add heap allocation audit for relayed connections alloc_counter is a preloadable malloc counter (glibc, macOS) that writes a snapshot on SIGUSR2. measure_alloc.py warms ss-local and ss-server up, snapshots both, relays more connections and reports allocations per connection. It runs report-only as the alloc_audit_report ctest. interop.peers() now yields the started processes. * Document the C++20 port and allocation baseline docs/cpp-core.md describes the language profile, the core primitives, the phase plan and the measured C baseline (77-89 allocations per connection in ss-server, 27-39 in ss-local). The compatibility contract now keeps the C11 public header instead of a C11 code base. CLAUDE.md drops stale libev, submodule and gnu99 references. * Fix CI for the C++ core: libstdc++ headers, static unwinder, newer clang - docker/static: Alpine's libstdc++ headers come with g++, and the C++ tests' static libstdc++ needs an unwinder that compiler-rt lacks; add g++ and llvm-libunwind. - FixedBuffer: drop the unused kCapacity (clang-tidy 18 reports it as a dynamically initialized header static). - ss-server on Windows: manager_addr was only read in POSIX-only code, which newer clang rejects (-Wunused-but-set-global); say that the option is ignored there. * CI: allow running the test and build workflows by hand Stacked PRs target their parent branch, which these workflows do not trigger on; workflow_dispatch lets each layer run the full matrix. * CI: let clang-tidy ignore GCC-only warning flags The compile database comes from a GCC build, whose flags (for example -Wno-class-memaccess) clang-tidy does not know and reports as errors.
80 lines
1.7 KiB
C++
80 lines
1.7 KiB
C++
/* SPDX-License-Identifier: GPL-3.0-or-later */
|
|
#include <memory>
|
|
#include <utility>
|
|
|
|
#include "core/result.hpp"
|
|
#include "test_helpers.hpp"
|
|
|
|
namespace {
|
|
|
|
ss::Result<int> parse_positive(int v)
|
|
{
|
|
if (v <= 0) {
|
|
return ss::fail(ss::Errc::invalid);
|
|
}
|
|
return v;
|
|
}
|
|
|
|
ss::Status check_twice(int v)
|
|
{
|
|
SS_TRY(parse_positive(v));
|
|
SS_TRY(parse_positive(v - 1));
|
|
return {};
|
|
}
|
|
|
|
void test_value_and_error()
|
|
{
|
|
auto ok = parse_positive(5);
|
|
SS_CHECK(ok.has_value());
|
|
SS_CHECK(*ok == 5);
|
|
SS_CHECK(ok.value_or(0) == 5);
|
|
|
|
auto bad = parse_positive(-1);
|
|
SS_CHECK(!bad);
|
|
SS_CHECK(bad.error().code == ss::Errc::invalid);
|
|
SS_CHECK(bad.value_or(42) == 42);
|
|
}
|
|
|
|
void test_status_and_try()
|
|
{
|
|
SS_CHECK(check_twice(3).has_value());
|
|
auto r = check_twice(1);
|
|
SS_CHECK(!r);
|
|
SS_CHECK(r.error() == ss::Error{ ss::Errc::invalid, 0 });
|
|
}
|
|
|
|
void test_move_only_value()
|
|
{
|
|
auto make = []() -> ss::Result<std::unique_ptr<int> > { return std::make_unique<int>(7); };
|
|
auto r = make();
|
|
SS_CHECK(r);
|
|
std::unique_ptr<int> p = std::move(r).value();
|
|
SS_CHECK(*p == 7);
|
|
}
|
|
|
|
void test_monadic()
|
|
{
|
|
auto doubled = parse_positive(4).transform([](int v) { return v * 2; });
|
|
SS_CHECK(doubled && *doubled == 8);
|
|
auto chained = parse_positive(4).and_then([](int v) { return parse_positive(v - 10); });
|
|
SS_CHECK(!chained && chained.error().code == ss::Errc::invalid);
|
|
}
|
|
|
|
void test_sys_errno()
|
|
{
|
|
ss::Result<int> r = ss::fail(ss::Errc::io, 104);
|
|
SS_CHECK(r.error().sys == 104);
|
|
}
|
|
|
|
} // namespace
|
|
|
|
int main()
|
|
{
|
|
SS_RUN(test_value_and_error);
|
|
SS_RUN(test_status_and_try);
|
|
SS_RUN(test_move_only_value);
|
|
SS_RUN(test_monadic);
|
|
SS_RUN(test_sys_errno);
|
|
return 0;
|
|
}
|