Date: Wed, 28 Sep 2022 12:03:19 +0200

On Sat, Sep 24, 2022 at 4:05 AM Barry Revzin <barry.revzin_at_[hidden]> wrote:

>

> On Fri, Sep 23, 2022 at 12:29 PM Sébastien Bini via Std-Proposals <

> std-proposals_at_[hidden]> wrote:

>

>> Hello,

>>

>> When dealing with variants and tuples, I often find myself in need to

>> retrieve a variant element or a tuple element from a runtime index.

>>

>> For instance, consider variant serialisation. To serialize, you first

>> write the index, then serialize the contained data. Problems come with

>> deserialization: you first read the index and then... you realize that with

>> the existing APIs, you cannot rebuild the variant element from the index we

>> just read.

>>

>> So I managed to write the following function:

>>

>> // Func must have the following member function:

>> // template <auto N>

>> // void operator()(std::integral_constant<decltype(N), N>);

>> template <auto From, auto To, class Int, class Func>

>> void find_integral_constant(Int at, Func&& func);

>>

>

>> In my implementation, it performs a binary search to retrieve the

>> integral constant that matches the given run-time index `at`, within the

>> supplied range. If the index is not found (because out-of-bounds) then the

>> functor is not called.

>> It could also return a boolean that indicates if the supplied index is in

>> the template range (true) or not (false). However I find it unnecessary as

>> users can already get that information by checking whether the functor has

>> been called, should they be interested in knowing that.

>>

>> Back to our deserialization problem, it is easily solved:

>> std::find_integral_constant<0,

>> std::variant_size_v<Variant>>(deserialized_index, [&](auto ID)

>> { deserialize(variant_.template emplace<ID()>(), stream); });

>>

>

>> I believe such an API is missing in the STL. Also, having it standardized

>> could allow for more optimization. We could use a jump table to the right

>> integral_constant (like a compiler-generated switch with a case for each

>> integral constant) rather than doing a binary search.

>>

>

> This is mp_with_index in Boost.Mp11 (

> https://www.boost.org/doc/libs/master/libs/mp11/doc/html/mp11.html#mp_with_indexni_f).

> It doesn't take a range [From, To) but rather just a single number that is

> the upper bound [0, N), which is sufficient.

>

> Peter's implementation has lots of manually written switch statements, so

> it's quite efficient.

>

> Barry

>

Damn, I hadn't seen that one. At least I am not the only one that needs it

and came up with a similar API.

The range is just for convenience, just an upper bound is indeed

sufficient. To be honest I never used it with a non-zero range start. But

as it performs a binary search behind the scene, and as such needs a range,

I figured it cost nothing to expose the range in the public API as well.

I don't know if I am thrilled by the return type though. What happens if

the runtime index is outside the range? If this aims to be standardized

then the API needs to be failure-tolerant.

Regards,

Sébastien Bini

>

> On Fri, Sep 23, 2022 at 12:29 PM Sébastien Bini via Std-Proposals <

> std-proposals_at_[hidden]> wrote:

>

>> Hello,

>>

>> When dealing with variants and tuples, I often find myself in need to

>> retrieve a variant element or a tuple element from a runtime index.

>>

>> For instance, consider variant serialisation. To serialize, you first

>> write the index, then serialize the contained data. Problems come with

>> deserialization: you first read the index and then... you realize that with

>> the existing APIs, you cannot rebuild the variant element from the index we

>> just read.

>>

>> So I managed to write the following function:

>>

>> // Func must have the following member function:

>> // template <auto N>

>> // void operator()(std::integral_constant<decltype(N), N>);

>> template <auto From, auto To, class Int, class Func>

>> void find_integral_constant(Int at, Func&& func);

>>

>

>> In my implementation, it performs a binary search to retrieve the

>> integral constant that matches the given run-time index `at`, within the

>> supplied range. If the index is not found (because out-of-bounds) then the

>> functor is not called.

>> It could also return a boolean that indicates if the supplied index is in

>> the template range (true) or not (false). However I find it unnecessary as

>> users can already get that information by checking whether the functor has

>> been called, should they be interested in knowing that.

>>

>> Back to our deserialization problem, it is easily solved:

>> std::find_integral_constant<0,

>> std::variant_size_v<Variant>>(deserialized_index, [&](auto ID)

>> { deserialize(variant_.template emplace<ID()>(), stream); });

>>

>

>> I believe such an API is missing in the STL. Also, having it standardized

>> could allow for more optimization. We could use a jump table to the right

>> integral_constant (like a compiler-generated switch with a case for each

>> integral constant) rather than doing a binary search.

>>

>

> This is mp_with_index in Boost.Mp11 (

> https://www.boost.org/doc/libs/master/libs/mp11/doc/html/mp11.html#mp_with_indexni_f).

> It doesn't take a range [From, To) but rather just a single number that is

> the upper bound [0, N), which is sufficient.

>

> Peter's implementation has lots of manually written switch statements, so

> it's quite efficient.

>

> Barry

>

Damn, I hadn't seen that one. At least I am not the only one that needs it

and came up with a similar API.

The range is just for convenience, just an upper bound is indeed

sufficient. To be honest I never used it with a non-zero range start. But

as it performs a binary search behind the scene, and as such needs a range,

I figured it cost nothing to expose the range in the public API as well.

I don't know if I am thrilled by the return type though. What happens if

the runtime index is outside the range? If this aims to be standardized

then the API needs to be failure-tolerant.

Regards,

Sébastien Bini

Received on 2022-09-28 10:03:31