From 7360a2579b3ac3c19debd2ec4115e1805b0e9547 Mon Sep 17 00:00:00 2001 From: MerryMage Date: Sun, 15 Jul 2018 14:25:31 +0100 Subject: [PATCH] mp: Implement metaprogramming library --- src/CMakeLists.txt | 11 ++++++ src/common/mp/append.h | 27 +++++++++++++++ src/common/mp/bind.h | 18 ++++++++++ src/common/mp/cartesian_product.h | 51 +++++++++++++++++++++++++++ src/common/mp/concat.h | 57 +++++++++++++++++++++++++++++++ src/common/mp/fapply.h | 27 +++++++++++++++ src/common/mp/fmap.h | 27 +++++++++++++++ src/common/mp/integer.h | 51 +++++++++++++++++++++++++++ src/common/mp/list.h | 15 ++++++++ src/common/mp/lut.h | 23 +++++++++++++ src/common/mp/to_tuple.h | 29 ++++++++++++++++ src/common/mp/vlift.h | 17 +++++++++ src/common/mp/vllift.h | 31 +++++++++++++++++ tests/CMakeLists.txt | 1 + tests/mp.cpp | 27 +++++++++++++++ 15 files changed, 412 insertions(+) create mode 100644 src/common/mp/append.h create mode 100644 src/common/mp/bind.h create mode 100644 src/common/mp/cartesian_product.h create mode 100644 src/common/mp/concat.h create mode 100644 src/common/mp/fapply.h create mode 100644 src/common/mp/fmap.h create mode 100644 src/common/mp/integer.h create mode 100644 src/common/mp/list.h create mode 100644 src/common/mp/lut.h create mode 100644 src/common/mp/to_tuple.h create mode 100644 src/common/mp/vlift.h create mode 100644 src/common/mp/vllift.h create mode 100644 tests/mp.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index c282e8d8..38ad8601 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -33,6 +33,17 @@ add_library(dynarmic common/memory_pool.cpp common/memory_pool.h common/mp.h + common/mp/append.h + common/mp/bind.h + common/mp/cartesian_product.h + common/mp/concat.h + common/mp/fapply.h + common/mp/fmap.h + common/mp/list.h + common/mp/lut.h + common/mp/to_tuple.h + common/mp/vlift.h + common/mp/vllift.h common/safe_ops.h common/scope_exit.h common/sm4.cpp diff --git a/src/common/mp/append.h b/src/common/mp/append.h new file mode 100644 index 00000000..e6ad75ed --- /dev/null +++ b/src/common/mp/append.h @@ -0,0 +1,27 @@ +/* This file is part of the dynarmic project. + * Copyright (c) 2018 MerryMage + * This software may be used and distributed according to the terms of the GNU + * General Public License version 2 or any later version. + */ + +#pragma once + +namespace Dynarmic::Common::mp { + +namespace detail { + +template +struct append_impl; + +template class LT, class... T1, class... T2> +struct append_impl, T2...> { + using type = LT; +}; + +} // namespace detail + +/// Append items T to list L +template +using append = typename detail::append_impl::type; + +} // namespace Dynarmic::Common::mp diff --git a/src/common/mp/bind.h b/src/common/mp/bind.h new file mode 100644 index 00000000..3666ea5b --- /dev/null +++ b/src/common/mp/bind.h @@ -0,0 +1,18 @@ +/* This file is part of the dynarmic project. + * Copyright (c) 2018 MerryMage + * This software may be used and distributed according to the terms of the GNU + * General Public License version 2 or any later version. + */ + +#pragma once + +namespace Dynarmic::Common::mp { + +/// Binds the first sizeof...(A) arguments of metafunction F with arguments A +template class F, class... A> +struct bind { + template + using type = F; +}; + +} // namespace Dynarmic::Common::mp diff --git a/src/common/mp/cartesian_product.h b/src/common/mp/cartesian_product.h new file mode 100644 index 00000000..919c7eef --- /dev/null +++ b/src/common/mp/cartesian_product.h @@ -0,0 +1,51 @@ +/* This file is part of the dynarmic project. + * Copyright (c) 2018 MerryMage + * This software may be used and distributed according to the terms of the GNU + * General Public License version 2 or any later version. + */ + +#pragma once + +#include "common/mp/append.h" +#include "common/mp/bind.h" +#include "common/mp/concat.h" +#include "common/mp/fmap.h" +#include "common/mp/list.h" + +namespace Dynarmic::Common::mp { + +namespace detail { + +template +struct cartesian_product_impl{}; + +template +struct cartesian_product_impl { + using type = RL; +}; + +template class LT, class... RT, class... T1> +struct cartesian_product_impl, LT> { + using type = concat< + fmap::template type, list>... + >; +}; + +template +struct cartesian_product_impl { + using type = typename cartesian_product_impl< + typename cartesian_product_impl::type, + L2, + Ls... + >::type; +}; + +} // namespace detail + +/// Produces the cartesian product of a set of lists +/// For example: +/// cartesian_product, list> == list, list, list, list +template +using cartesian_product = typename detail::cartesian_product_impl, Ls...>::type; + +} // namespace Dynarmic::Common::mp diff --git a/src/common/mp/concat.h b/src/common/mp/concat.h new file mode 100644 index 00000000..e41dd9e6 --- /dev/null +++ b/src/common/mp/concat.h @@ -0,0 +1,57 @@ +/* This file is part of the dynarmic project. + * Copyright (c) 2018 MerryMage + * This software may be used and distributed according to the terms of the GNU + * General Public License version 2 or any later version. + */ + +#pragma once + +#include "common/mp/list.h" + +namespace Dynarmic::Common::mp { + +namespace detail { + +template +struct concat_impl; + +template<> +struct concat_impl<> { + using type = list<>; +}; + +template +struct concat_impl { + using type = L; +}; + +template class LT, class... T1, class... T2, class... Ls> +struct concat_impl, LT, Ls...> { + using type = typename concat_impl, Ls...>::type; +}; + +template class LT, + class... T1, class... T2, class... T3, class... T4, class... T5, class... T6, class... T7, class... T8, + class... T9, class... T10, class... T11, class... T12, class... T13, class... T14, class... T15, class... T16, + class... Ls> +struct concat_impl< + LT, LT, LT, LT, LT, LT, LT, LT, + LT, LT, LT, LT, LT, LT, LT, LT, + Ls...> +{ + using type = typename concat_impl< + LT< + T1..., T2..., T3..., T4..., T5..., T6..., T7..., T8..., + T9..., T10..., T11..., T12..., T13..., T14..., T15..., T16... + >, + Ls... + >::type; +}; + +} // namespace detail + +/// Concatenate lists together +template +using concat = typename detail::concat_impl::type; + +} // namespace Dynarmic::Common::mp diff --git a/src/common/mp/fapply.h b/src/common/mp/fapply.h new file mode 100644 index 00000000..1b84efc4 --- /dev/null +++ b/src/common/mp/fapply.h @@ -0,0 +1,27 @@ +/* This file is part of the dynarmic project. + * Copyright (c) 2018 MerryMage + * This software may be used and distributed according to the terms of the GNU + * General Public License version 2 or any later version. + */ + +#pragma once + +namespace Dynarmic::Common::mp { + +namespace detail { + +template class F, class L> +struct fapply_impl; + +template class F, template class LT, class... T> +struct fapply_impl> { + using type = F; +}; + +} // namespace detail + +/// Invokes metafunction F where the arguments are all the members of list L +template class F, class L> +using fapply = typename detail::fapply_impl::type; + +} // namespace Dynarmic::Common::mp diff --git a/src/common/mp/fmap.h b/src/common/mp/fmap.h new file mode 100644 index 00000000..d05766a6 --- /dev/null +++ b/src/common/mp/fmap.h @@ -0,0 +1,27 @@ +/* This file is part of the dynarmic project. + * Copyright (c) 2018 MerryMage + * This software may be used and distributed according to the terms of the GNU + * General Public License version 2 or any later version. + */ + +#pragma once + +namespace Dynarmic::Common::mp { + +namespace detail { + +template class F, class L> +struct fmap_impl; + +template class F, template class LT, class... T> +struct fmap_impl> { + using type = LT...>; +}; + +} // namespace detail + +/// Metafunction that applies each element of list L to metafunction F +template class F, class L> +using fmap = typename detail::fmap_impl::type; + +} // namespace Dynarmic::Common::mp diff --git a/src/common/mp/integer.h b/src/common/mp/integer.h new file mode 100644 index 00000000..ee9f6201 --- /dev/null +++ b/src/common/mp/integer.h @@ -0,0 +1,51 @@ +/* This file is part of the dynarmic project. + * Copyright (c) 2018 MerryMage + * This software may be used and distributed according to the terms of the GNU + * General Public License version 2 or any later version. + */ + +#pragma once + +#include +#include + +namespace Dynarmic::Common::mp { + +namespace detail { + +template +struct integer_of_size_impl{}; + +template<> +struct integer_of_size_impl<8> { + using unsigned_type = std::uint8_t; + using signed_type = std::int8_t; +}; + +template<> +struct integer_of_size_impl<16> { + using unsigned_type = std::uint16_t; + using signed_type = std::int16_t; +}; + +template<> +struct integer_of_size_impl<32> { + using unsigned_type = std::uint32_t; + using signed_type = std::int32_t; +}; + +template<> +struct integer_of_size_impl<64> { + using unsigned_type = std::uint64_t; + using signed_type = std::int64_t; +}; + +} // namespace detail + +template +using unsigned_integer_of_size = typename detail::integer_of_size_impl::unsigned_type; + +template +using signed_integer_of_size = typename detail::integer_of_size_impl::signed_type; + +} // namespace Dynarmic::Common::mp diff --git a/src/common/mp/list.h b/src/common/mp/list.h new file mode 100644 index 00000000..96c00697 --- /dev/null +++ b/src/common/mp/list.h @@ -0,0 +1,15 @@ +/* This file is part of the dynarmic project. + * Copyright (c) 2018 MerryMage + * This software may be used and distributed according to the terms of the GNU + * General Public License version 2 or any later version. + */ + +#pragma once + +namespace Dynarmic::Common::mp { + +/// Contains a list of types +template +struct list {}; + +} // namespace Dynarmic::Common::mp diff --git a/src/common/mp/lut.h b/src/common/mp/lut.h new file mode 100644 index 00000000..5d644197 --- /dev/null +++ b/src/common/mp/lut.h @@ -0,0 +1,23 @@ +/* This file is part of the dynarmic project. + * Copyright (c) 2018 MerryMage + * This software may be used and distributed according to the terms of the GNU + * General Public License version 2 or any later version. + */ + +#pragma once + +#include +#include +#include + +#include "common/mp/list.h" + +namespace Dynarmic::Common::mp { + +template +inline auto GenerateLookupTableFromList(Function f, list) { + static const std::array, sizeof...(Values)> pair_array{f(Values{})...}; + return std::map(pair_array.begin(), pair_array.end()); +} + +} // namespace Dynarmic::Common::mp diff --git a/src/common/mp/to_tuple.h b/src/common/mp/to_tuple.h new file mode 100644 index 00000000..1e782a1d --- /dev/null +++ b/src/common/mp/to_tuple.h @@ -0,0 +1,29 @@ +/* This file is part of the dynarmic project. + * Copyright (c) 2018 MerryMage + * This software may be used and distributed according to the terms of the GNU + * General Public License version 2 or any later version. + */ + +#pragma once + +#include + +namespace Dynarmic::Common::mp { + +namespace detail { + +template +struct to_tuple_impl; + +template class LT, class... T> +struct to_tuple_impl> { + static constexpr auto value = std::make_tuple(static_cast(T::value)...); +}; + +} // namespace detail + +/// Metafunction that converts a list of metavalues to a tuple value. +template +constexpr auto to_tuple = detail::to_tuple_impl::value; + +} // namespace Dynarmic::Common::mp diff --git a/src/common/mp/vlift.h b/src/common/mp/vlift.h new file mode 100644 index 00000000..c46874d3 --- /dev/null +++ b/src/common/mp/vlift.h @@ -0,0 +1,17 @@ +/* This file is part of the dynarmic project. + * Copyright (c) 2018 MerryMage + * This software may be used and distributed according to the terms of the GNU + * General Public License version 2 or any later version. + */ + +#pragma once + +#include + +namespace Dynarmic::Common::mp { + +/// Lifts a value into a type +template +using vlift = std::integral_constant; + +} // namespace Dynarmic::Common::mp diff --git a/src/common/mp/vllift.h b/src/common/mp/vllift.h new file mode 100644 index 00000000..25eb323d --- /dev/null +++ b/src/common/mp/vllift.h @@ -0,0 +1,31 @@ +/* This file is part of the dynarmic project. + * Copyright (c) 2018 MerryMage + * This software may be used and distributed according to the terms of the GNU + * General Public License version 2 or any later version. + */ + +#pragma once + +#include + +#include "common/mp/list.h" + +namespace Dynarmic::Common::mp { + +namespace detail { + +template +struct vllift_impl{}; + +template +struct vllift_impl> { + using type = list...>; +}; + +} // namespace detail + +/// Lifts values in value list VL to create a type list. +template +using vllift = typename detail::vllift_impl::type; + +} // namespace Dynarmic::Common::mp diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 2d1902ee..576bf9e6 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -31,6 +31,7 @@ add_executable(dynarmic_tests A64/testenv.h fp/unpacked_tests.cpp main.cpp + mp.cpp rand_int.h ) diff --git a/tests/mp.cpp b/tests/mp.cpp new file mode 100644 index 00000000..7f34a525 --- /dev/null +++ b/tests/mp.cpp @@ -0,0 +1,27 @@ +/* This file is part of the dynarmic project. + * Copyright (c) 2018 MerryMage + * This software may be used and distributed according to the terms of the GNU + * General Public License version 2 or any later version. + */ + +#include + +#include "common/mp/cartesian_product.h" + +using namespace Dynarmic::Common::mp; + +static_assert( + std::is_same_v< + cartesian_product, list, list>, + list< + list, + list, + list, + list, + list, + list, + list, + list + > + > +);