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