From f8acb6fc82686eca33918471528a45dc5b714d15 Mon Sep 17 00:00:00 2001 From: tz12323 <2760686250@qq.com> Date: Wed, 21 Oct 2026 21:56:37 +0800 Subject: [PATCH] add tl-optional --- .../docs/2026-10-21-add-tl-optional-plan.md | 53 ++++++++++++++ mcpp.toml | 1 + pkgs/c/compat.tl-optional.lua | 70 ++++++++++++++++++ tests/examples/tl-optional/mcpp.toml | 8 ++ tests/examples/tl-optional/tests/optional.cpp | 73 +++++++++++++++++++ 5 files changed, 205 insertions(+) create mode 100644 .agents/docs/2026-10-21-add-tl-optional-plan.md create mode 100644 pkgs/c/compat.tl-optional.lua create mode 100644 tests/examples/tl-optional/mcpp.toml create mode 100644 tests/examples/tl-optional/tests/optional.cpp diff --git a/.agents/docs/2026-10-21-add-tl-optional-plan.md b/.agents/docs/2026-10-21-add-tl-optional-plan.md new file mode 100644 index 00000000..cc51b361 --- /dev/null +++ b/.agents/docs/2026-10-21-add-tl-optional-plan.md @@ -0,0 +1,53 @@ +# Add tl::optional 1.1.0 as compat.tl-optional + +## Source and shape + +- Upstream: . +- Version: `1.1.0`, the newest stable tag observed with + `git ls-remote --tags --refs`. +- License: CC0-1.0. +- Shape: Form B, header-only. The single public header is + `include/tl/optional.hpp`; upstream's CMake INTERFACE target exposes + `include/`. The package uses `include_dirs = { "*/include" }` and a trivial + anchor C TU to provide a buildable `optional` lib target. +- No features: the library has no optional compilable source component. + Upstream's Catch2 tests are not part of the library. + +The header supports C++11/14/17. The package's own anchor is compiled as C++; +consumers choose their language mode. The workspace test uses C++23, and a +direct smoke test also compiles and runs the same API in C++14. + +## Download and mirror + +- GLOBAL: + `https://github.com/TartanLlama/optional/archive/refs/tags/v1.1.0.tar.gz` +- SHA-256: + `88ece79f3de5ccaec4191951a222f95cc80c4381dafd3163bdb1ff87cedf3118` +- The archive was downloaded twice and compared byte-for-byte; both copies had + the same digest. +- No verified `mcpp-res` release is available, so the descriptor uses the + upstream plain-string URL fallback rather than inventing a CN mirror. + +## Automatic updates + +The package meets the automatic-update criteria: it has GitHub numeric tags, +stable archive URLs, identical resources on all declared platforms, and future +versions do not require a build-recipe change. `extensions.autoupdate` uses the +prefixed `v${version}` tag spelling and the GitHub tag-archive URL template. + +## Test member + +`tests/examples/tl-optional/` is registered in the root workspace. It asserts: + +- value and empty construction, `value_or`, reset and emplace; +- constexpr construction; +- `map`, `and_then`, `or_else` and `map_or`; +- reference optional binding, rebinding and mutation; +- `take()` moving the value out and emptying the source; +- `make_optional` preserving reference optionals. + +Every assertion affects the process exit status (`return ok ? 0 : 1`). + +## Verification + +Pending local validation and updater declaration checks. diff --git a/mcpp.toml b/mcpp.toml index 9ca267b6..9d9ea35e 100644 --- a/mcpp.toml +++ b/mcpp.toml @@ -172,6 +172,7 @@ members = [ "tests/examples/websocket-features", "tests/examples/websocket-tls", "tests/examples/wolfssl", + "tests/examples/tl-optional", "tests/examples/tray", "tests/examples/xsimd", "tests/examples/xxhash", diff --git a/pkgs/c/compat.tl-optional.lua b/pkgs/c/compat.tl-optional.lua new file mode 100644 index 00000000..bf3fc42c --- /dev/null +++ b/pkgs/c/compat.tl-optional.lua @@ -0,0 +1,70 @@ +-- Form B inline descriptor for tl::optional — a single-header implementation +-- of std::optional with monadic extensions and optional references. +-- +-- HEADER-ONLY: upstream's CMake INTERFACE target exposes `include/`, and the +-- only public header is `include/tl/optional.hpp`. Tests and packaging files +-- stay outside the consumer's include path. A trivial anchor TU gives mcpp a +-- buildable `optional` lib target, following compat.gtl / compat.safeint. +-- +-- LANGUAGE FLOOR: upstream describes the library as C++11/14/17 and selects +-- its monadic overloads with TL_OPTIONAL_CXX14. The package's own anchor is +-- compiled as C++; consumers choose their language mode. The test uses the +-- workspace default C++23 mode and directly compiles the same API in C++14. +-- +-- No features: the library has one header and no optional compilable source. +-- Its tests fetch Catch2 and are not part of the library. +-- +-- No verified mcpp-res mirror is available, so the upstream URL is a plain +-- string rather than a fabricated GLOBAL/CN resource table. +package = { + spec = "1", + namespace = "compat", + name = "tl-optional", + description = "tl::optional — std::optional with monadic operations and reference support (header-only)", + licenses = {"CC0-1.0"}, + repo = "https://github.com/TartanLlama/optional", + type = "package", + + extensions = { + autoupdate = { + tag = "v${version}", + url = "https://github.com/TartanLlama/optional/archive/refs/tags/${tag}.tar.gz", + }, + }, + + xpm = { + linux = { + ["1.1.0"] = { + url = "https://github.com/TartanLlama/optional/archive/refs/tags/v1.1.0.tar.gz", + sha256 = "88ece79f3de5ccaec4191951a222f95cc80c4381dafd3163bdb1ff87cedf3118", + }, + }, + macosx = { + ["1.1.0"] = { + url = "https://github.com/TartanLlama/optional/archive/refs/tags/v1.1.0.tar.gz", + sha256 = "88ece79f3de5ccaec4191951a222f95cc80c4381dafd3163bdb1ff87cedf3118", + }, + }, + windows = { + ["1.1.0"] = { + url = "https://github.com/TartanLlama/optional/archive/refs/tags/v1.1.0.tar.gz", + sha256 = "88ece79f3de5ccaec4191951a222f95cc80c4381dafd3163bdb1ff87cedf3118", + }, + }, + }, + + mcpp = { + language = "c++23", + import_std = false, + c_standard = "c11", + include_dirs = { "*/include" }, + generated_files = { + ["mcpp_generated/tl_optional_anchor.c"] = [==[ +int mcpp_compat_tl_optional_headers_anchor(void) { return 0; } +]==], + }, + sources = { "mcpp_generated/tl_optional_anchor.c" }, + targets = { ["optional"] = { kind = "lib" } }, + deps = { }, + }, +} diff --git a/tests/examples/tl-optional/mcpp.toml b/tests/examples/tl-optional/mcpp.toml new file mode 100644 index 00000000..87473f16 --- /dev/null +++ b/tests/examples/tl-optional/mcpp.toml @@ -0,0 +1,8 @@ +# tl-optional test project: exercise the standard optional surface plus the +# extensions that distinguish this library from std::optional. +[package] +name = "tl-optional-tests" +version = "0.1.0" + +[dependencies.compat] +tl-optional = "1.1.0" diff --git a/tests/examples/tl-optional/tests/optional.cpp b/tests/examples/tl-optional/tests/optional.cpp new file mode 100644 index 00000000..27e0ba91 --- /dev/null +++ b/tests/examples/tl-optional/tests/optional.cpp @@ -0,0 +1,73 @@ +// compat.tl-optional — assert value/empty state, observers, mutation, monadic +// chaining, reference binding, and constexpr construction through the public +// header. The test uses only the standard library in addition to tl/optional. +#include + +#include +#include +#include + +int main() { + bool ok = true; + auto check = [&](bool condition, const char* what) { + if (!condition) { + std::printf("FAIL: %s\n", what); + ok = false; + } + }; + + tl::optional value = tl::make_optional(42); + tl::optional empty = tl::nullopt; + check(value.has_value() && *value == 42, "value construction and observer"); + check(!empty.has_value(), "nullopt constructs an empty optional"); + check(value.value_or(7) == 42 && empty.value_or(7) == 7, + "value_or handles both states"); + + constexpr tl::optional constexpr_value = tl::make_optional(11); + static_assert(constexpr_value.has_value(), "constexpr optional"); + + value.reset(); + check(!value, "reset clears the value"); + value.emplace(21); + check(value && *value == 21, "emplace constructs a new value"); + + const auto doubled = empty.map([](int x) { return x * 2; }); + check(!doubled, "map on an empty optional stays empty"); + const auto mapped = tl::make_optional(21).map([](int x) { return x * 2; }); + check(mapped && *mapped == 42, "map transforms a present value"); + + const auto chained = tl::make_optional(5).and_then([](int x) { + return tl::make_optional(x * 3); + }); + check(chained && *chained == 15, "and_then chains optional-producing calls"); + + const auto fallback = empty.or_else([] { return tl::make_optional(13); }); + check(fallback && *fallback == 13, "or_else supplies a fallback"); + check(tl::make_optional(42).map_or([](int x) { return x + 1; }, 0) == 43, + "map_or applies the mapper when present"); + check(empty.map_or([](int x) { return x + 1; }, 0) == 0, + "map_or returns the fallback when empty"); + + int first = 1; + int second = 2; + tl::optional reference = first; + check(&*reference == &first, "reference optional binds the original object"); + reference = second; + check(&*reference == &second, "assignment rebinds the reference"); + *reference = 9; + check(second == 9, "writing through a reference optional mutates the object"); + + tl::optional text = std::string("hello"); + auto taken = text.take(); + check(taken && *taken == "hello" && !text, + "take moves out the value and empties the source"); + + static_assert(std::is_same(first)), + tl::optional>::value, + "make_optional preserves reference optionals"); + + if (ok) { + std::puts("tl-optional OK"); + } + return ok ? 0 : 1; +}