Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
53 changes: 53 additions & 0 deletions .agents/docs/2026-10-21-add-tl-optional-plan.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# Add tl::optional 1.1.0 as compat.tl-optional

## Source and shape

- Upstream: <https://github.com/TartanLlama/optional>.
- 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.
1 change: 1 addition & 0 deletions mcpp.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
70 changes: 70 additions & 0 deletions pkgs/c/compat.tl-optional.lua
Original file line number Diff line number Diff line change
@@ -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 = { },
},
}
8 changes: 8 additions & 0 deletions tests/examples/tl-optional/mcpp.toml
Original file line number Diff line number Diff line change
@@ -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"
73 changes: 73 additions & 0 deletions tests/examples/tl-optional/tests/optional.cpp
Original file line number Diff line number Diff line change
@@ -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 <tl/optional.hpp>

#include <cstdio>
#include <string>
#include <type_traits>

int main() {
bool ok = true;
auto check = [&](bool condition, const char* what) {
if (!condition) {
std::printf("FAIL: %s\n", what);
ok = false;
}
};

tl::optional<int> value = tl::make_optional(42);
tl::optional<int> 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<int> 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<int&> 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<std::string> 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<decltype(tl::make_optional<int&>(first)),
tl::optional<int&>>::value,
"make_optional preserves reference optionals");

if (ok) {
std::puts("tl-optional OK");
}
return ok ? 0 : 1;
}
Loading