From 3bf77f01a7fda13090af8f47c9c1db82c1e837f3 Mon Sep 17 00:00:00 2001 From: Andrew Kaster Date: Tue, 29 Dec 2020 22:40:21 -0700 Subject: [PATCH] AK: Add a TypeList class for expanded compile-time tools Also add IndexSequence and associated helpers. The TypeList class can be queried for what type is at a certain index, and there are two helper functions: for_each_type, and for_each_type_zipped. for_each_type will invoke a lambda with a TypeWrapper object for each type in the type list. The original type can be obtained by extracting the ::Type from the type of your generic lambda's one argument. for_each_type_zipped will walk two TypeLists in lockstep and pass a TypeWrapper object for the current index in each list to a generic lambda. The original type from the TypeList can again be extracted via the ::Type of the generic lambda's two parameters. --- AK/StdLibExtras.h | 28 ++++++++++++++ AK/TypeList.h | 93 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 121 insertions(+) create mode 100644 AK/TypeList.h diff --git a/AK/StdLibExtras.h b/AK/StdLibExtras.h index c2130303260..74c2f590d94 100644 --- a/AK/StdLibExtras.h +++ b/AK/StdLibExtras.h @@ -517,6 +517,30 @@ using IsArithmetic = IntegralConstant::value || IsFloatingPo template using IsFundamental = IntegralConstant::value || IsVoid::value || IsNullPointer::value>; +template +struct IntegerSequence { + using Type = T; + static constexpr unsigned size() noexcept { return sizeof...(Ts); }; +}; + +template +using IndexSequence = IntegerSequence; + +template +auto make_integer_sequence_impl() +{ + if constexpr (N == 0) + return IntegerSequence {}; + else + return make_integer_sequence_impl(); +} + +template +using MakeIntegerSequence = decltype(make_integer_sequence_impl()); + +template +using MakeIndexSequence = MakeIntegerSequence; + } using AK::AddConst; @@ -528,6 +552,8 @@ using AK::declval; using AK::DependentFalse; using AK::exchange; using AK::forward; +using AK::IndexSequence; +using AK::IntegerSequence; using AK::is_trivial; using AK::is_trivially_copyable; using AK::IsArithmetic; @@ -539,6 +565,8 @@ using AK::IsNullPointer; using AK::IsSame; using AK::IsUnion; using AK::IsVoid; +using AK::MakeIndexSequence; +using AK::MakeIntegerSequence; using AK::MakeSigned; using AK::MakeUnsigned; using AK::max; diff --git a/AK/TypeList.h b/AK/TypeList.h new file mode 100644 index 00000000000..d5ee78db1b0 --- /dev/null +++ b/AK/TypeList.h @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2020, the SerenityOS developers. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include + +namespace AK { + +template +struct TypeList; + +template +struct TypeListElement; + +template +struct TypeListElement> + : TypeListElement> { +}; + +template +struct TypeListElement<0, TypeList> { + using Type = Head; +}; + +template +struct TypeList { + static constexpr unsigned size = sizeof...(Types); + + template + using Type = typename TypeListElement>::Type; +}; + +template +struct TypeWrapper { + using Type = T; +}; + +template +constexpr void for_each_type_impl(F&& f, IndexSequence) +{ + (forward(f)(TypeWrapper> {}), ...); +} + +template +constexpr void for_each_type(F&& f) +{ + for_each_type_impl(forward(f), MakeIndexSequence {}); +} + +template +constexpr void for_each_type_zipped_impl(F&& f, IndexSequence) +{ + (forward(f)(TypeWrapper> {}, TypeWrapper> {}), ...); +} + +template +constexpr void for_each_type_zipped(F&& f) +{ + static_assert(ListA::size == ListB::size, "Can't zip TypeLists that aren't the same size!"); + for_each_type_zipped_impl(forward(f), MakeIndexSequence {}); +} + +} + +using AK::for_each_type; +using AK::for_each_type_zipped; +using AK::TypeList; +using AK::TypeListElement; +using AK::TypeWrapper;