object-introspection/types/std_variant.toml
Jake Hillion a4723fb2ef tbv2: update std::variant
`std::variant` is the last archetypal container missing in TreeBuilder-v2. The
code for it isn't hugely complicated and relies on pack expansion.

This change introduces a new field to the container specification:
`scoped_extra`. This field allows you to write extra code that will be included
within the TypeHandler in CodeGen. This means it will not have collisions with
other containers, unlike the existing `extra` field. It's used here to write
the recursive `getSizeType` function for `std::variant`.

Tech debt is introduced here by comparing the container name to `std::variant`
in CodeGen to conditionally generate some code. We've worked hard to remove
references to containers in code and move them to `.toml` files. On balance,
this is worth having to include the example of `std::variant`. It should be
moved into a container spec field at some point, the design of which is still
to be determined.

Test plan:
- Activated the OIL `std::variant` tests.
- CI
2024-02-23 16:16:22 +00:00

90 lines
2.3 KiB
TOML

[info]
type_name = "std::variant"
ctype = "STD_VARIANT_TYPE"
header = "variant"
# Old:
typeName = "std::variant"
ns = ["namespace std"]
[codegen]
decl = """
template<class... Types>
void getSizeType(const %1%<Types...> &container, size_t& returnArg);
"""
func = """
template<class... Types>
void getSizeType(const %1%<Types...> &container, size_t& returnArg)
{
SAVE_SIZE(sizeof(%1%<Types...>));
SAVE_DATA(container.index());
// This check should be `container.valueless_by_exception()` but it doesn't
// work with the variable sized integers used in `std::variant`. For fewer
// than 256 options it uses a `uint8_t` index but checks against -1 of
// `uintptr_t`. Manually check for any out of bounds indices as a workaround.
if (container.index() >= sizeof...(Types)) {
return;
}
std::visit([&returnArg](auto &&arg) {
// Account for inline contents
SAVE_SIZE(-sizeof(arg));
getSizeType(arg, returnArg);
}, container);
}
"""
scoped_extra = """
template <size_t I = 0>
static types::st::Unit<DB>
getSizeTypeRecursive(
Ctx& ctx,
const container_type& container,
typename TypeHandler<Ctx, container_type>::type returnArg
) {
if constexpr (I < sizeof...(Types)) {
if (I == container.index()) {
return returnArg.template delegate<I>([&ctx, &container](auto ret) {
return OIInternal::getSizeType<Ctx>(ctx, std::get<I>(container), ret);
});
} else {
return getSizeTypeRecursive<I+1>(ctx, container, returnArg);
}
} else {
return returnArg.template delegate<sizeof...(Types)>(std::identity());
}
}
"""
handler_header = """
template <typename Ctx, typename... Types>
struct TypeHandler<Ctx, std::variant<Types...>>
"""
traversal_func = """
return getSizeTypeRecursive(ctx, container, returnArg);
"""
[[codegen.processor]]
type = "types::st::Sum<DB, typename TypeHandler<Ctx, Types>::type..., types::st::Unit<DB>>"
func = """
static constexpr std::array<inst::Field, sizeof...(Types)> children{
make_field<Ctx, Types>("*")...,
};
auto sum = std::get<ParsedData::Sum>(d.val);
el.container_stats = result::Element::ContainerStats {
.capacity = 1,
.length = sum.index == sizeof...(Types) ? 0u : 1u,
};
if (el.container_stats->length == 0)
return;
el.exclusive_size -= children[sum.index].static_size;
stack_ins(children[sum.index]);
"""