/* * Copyright (C) 2023-present ScyllaDB * */ /* * SPDX-License-Identifier: (AGPL-3.0-or-later and Apache-2.0) */ #pragma once #include #include namespace utils { template constexpr auto tuple_ex_size_v = std::tuple_size_v>; template concept Tuple = requires(T item) { std::invoke([](const std::tuple& t) {}, item); }; // Insert a new item of type NewItem into SourceTuple to produce ResultTuple. // ResultTuple mirrors SourceTuple, with the inclusion of an extra element of type NewItem. // SourceTuple and ResultTuple can be arbitrary specialisations of std::tuple or rpc::tuple. template requires (tuple_ex_size_v + 1 == tuple_ex_size_v) static ResultTuple tuple_insert(SourceTuple&& source_tuple, NewItem&& new_item) { constexpr auto source_size = tuple_ex_size_v; constexpr auto result_size = tuple_ex_size_v; constexpr auto match = std::invoke([](std::index_sequence) { auto index = result_size; const auto count = (0 + ... + (std::is_same_v, NewItem> ? (index = Is, 1) : 0)); return std::pair(index, count); }, std::make_index_sequence()); static_assert(match.second == 1, "ResultTuple should contain exactly one NewItem"); constexpr auto item_index = match.first; return std::invoke([&](std::index_sequence, std::index_sequence) { return ResultTuple { std::get(std::forward(source_tuple))..., std::forward(new_item), std::get(std::forward(source_tuple))... }; }, std::make_index_sequence(), std::make_index_sequence()); } }