Date: Wed, 28 Sep 2022 12:52:19 +0200
śr., 28 wrz 2022 o 12:03 Sébastien Bini via Std-Proposals
<std-proposals_at_[hidden]> napisał(a):
>
>
>
> 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.
Add two callbacks, one with correct index and other for "default"
case, then the user can handle it anyway he wants:
throw, return default value, terminate or mark it as unreachable code.
>
> Regards,
> Sébastien Bini
> --
> Std-Proposals mailing list
> Std-Proposals_at_[hidden]
> https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals
<std-proposals_at_[hidden]> napisał(a):
>
>
>
> 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.
Add two callbacks, one with correct index and other for "default"
case, then the user can handle it anyway he wants:
throw, return default value, terminate or mark it as unreachable code.
>
> Regards,
> Sébastien Bini
> --
> Std-Proposals mailing list
> Std-Proposals_at_[hidden]
> https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals
Received on 2022-09-28 10:52:31