mp: Implement metaprogramming library

This commit is contained in:
MerryMage 2018-07-15 14:25:31 +01:00
parent 4ab029c114
commit 7360a2579b
15 changed files with 412 additions and 0 deletions

View file

@ -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

27
src/common/mp/append.h Normal file
View file

@ -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... L>
struct append_impl;
template<template<class...> class LT, class... T1, class... T2>
struct append_impl<LT<T1...>, T2...> {
using type = LT<T1..., T2...>;
};
} // namespace detail
/// Append items T to list L
template<class L, class... T>
using append = typename detail::append_impl<L, T...>::type;
} // namespace Dynarmic::Common::mp

18
src/common/mp/bind.h Normal file
View file

@ -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<template<class...> class F, class... A>
struct bind {
template<class... T>
using type = F<A..., T...>;
};
} // namespace Dynarmic::Common::mp

View file

@ -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<class... Ls>
struct cartesian_product_impl{};
template<class RL>
struct cartesian_product_impl<RL> {
using type = RL;
};
template<template<class...> class LT, class... RT, class... T1>
struct cartesian_product_impl<LT<RT...>, LT<T1...>> {
using type = concat<
fmap<bind<append, RT>::template type, list<T1...>>...
>;
};
template<class RL, class L1, class L2, class... Ls>
struct cartesian_product_impl<RL, L1, L2, Ls...> {
using type = typename cartesian_product_impl<
typename cartesian_product_impl<RL, L1>::type,
L2,
Ls...
>::type;
};
} // namespace detail
/// Produces the cartesian product of a set of lists
/// For example:
/// cartesian_product<list<A, B>, list<D, E>> == list<list<A, D>, list<A, E>, list<B, D>, list<B, E>
template<typename L1, typename... Ls>
using cartesian_product = typename detail::cartesian_product_impl<fmap<list, L1>, Ls...>::type;
} // namespace Dynarmic::Common::mp

57
src/common/mp/concat.h Normal file
View file

@ -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<class... L>
struct concat_impl;
template<>
struct concat_impl<> {
using type = list<>;
};
template<class L>
struct concat_impl<L> {
using type = L;
};
template<template<class...> class LT, class... T1, class... T2, class... Ls>
struct concat_impl<LT<T1...>, LT<T2...>, Ls...> {
using type = typename concat_impl<LT<T1..., T2...>, Ls...>::type;
};
template<template<class...> 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<T1...>, LT<T2...>, LT<T3...>, LT<T4...>, LT<T5...>, LT<T6...>, LT<T7...>, LT<T8...>,
LT<T9...>, LT<T10...>, LT<T11...>, LT<T12...>, LT<T13...>, LT<T14...>, LT<T15...>, LT<T16...>,
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<class... L>
using concat = typename detail::concat_impl<L...>::type;
} // namespace Dynarmic::Common::mp

27
src/common/mp/fapply.h Normal file
View file

@ -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<template<class...> class F, class L>
struct fapply_impl;
template<template<class...> class F, template<class...> class LT, class... T>
struct fapply_impl<F, LT<T...>> {
using type = F<T...>;
};
} // namespace detail
/// Invokes metafunction F where the arguments are all the members of list L
template<template<class...> class F, class L>
using fapply = typename detail::fapply_impl<F, L>::type;
} // namespace Dynarmic::Common::mp

27
src/common/mp/fmap.h Normal file
View file

@ -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<template<class...> class F, class L>
struct fmap_impl;
template<template<class...> class F, template<class...> class LT, class... T>
struct fmap_impl<F, LT<T...>> {
using type = LT<F<T>...>;
};
} // namespace detail
/// Metafunction that applies each element of list L to metafunction F
template<template<class...> class F, class L>
using fmap = typename detail::fmap_impl<F, L>::type;
} // namespace Dynarmic::Common::mp

51
src/common/mp/integer.h Normal file
View file

@ -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 <cstddef>
#include <cstdint>
namespace Dynarmic::Common::mp {
namespace detail {
template<std::size_t size>
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<std::size_t size>
using unsigned_integer_of_size = typename detail::integer_of_size_impl<size>::unsigned_type;
template<std::size_t size>
using signed_integer_of_size = typename detail::integer_of_size_impl<size>::signed_type;
} // namespace Dynarmic::Common::mp

15
src/common/mp/list.h Normal file
View file

@ -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<class... T>
struct list {};
} // namespace Dynarmic::Common::mp

23
src/common/mp/lut.h Normal file
View file

@ -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 <array>
#include <map>
#include <type_traits>
#include "common/mp/list.h"
namespace Dynarmic::Common::mp {
template <typename KeyT, typename ValueT, typename Function, typename ...Values>
inline auto GenerateLookupTableFromList(Function f, list<Values...>) {
static const std::array<std::pair<KeyT, ValueT>, sizeof...(Values)> pair_array{f(Values{})...};
return std::map<KeyT, ValueT>(pair_array.begin(), pair_array.end());
}
} // namespace Dynarmic::Common::mp

29
src/common/mp/to_tuple.h Normal file
View file

@ -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 <tuple>
namespace Dynarmic::Common::mp {
namespace detail {
template<class L>
struct to_tuple_impl;
template<template<class...> class LT, class... T>
struct to_tuple_impl<LT<T...>> {
static constexpr auto value = std::make_tuple(static_cast<typename T::value_type>(T::value)...);
};
} // namespace detail
/// Metafunction that converts a list of metavalues to a tuple value.
template<class L>
constexpr auto to_tuple = detail::to_tuple_impl<L>::value;
} // namespace Dynarmic::Common::mp

17
src/common/mp/vlift.h Normal file
View file

@ -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 <type_traits>
namespace Dynarmic::Common::mp {
/// Lifts a value into a type
template<auto V>
using vlift = std::integral_constant<decltype(V), V>;
} // namespace Dynarmic::Common::mp

31
src/common/mp/vllift.h Normal file
View file

@ -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 <type_traits>
#include "common/mp/list.h"
namespace Dynarmic::Common::mp {
namespace detail {
template<class VL>
struct vllift_impl{};
template<class T, T... values>
struct vllift_impl<std::integer_sequence<T, values...>> {
using type = list<std::integral_constant<T, values>...>;
};
} // namespace detail
/// Lifts values in value list VL to create a type list.
template<class VL>
using vllift = typename detail::vllift_impl<VL>::type;
} // namespace Dynarmic::Common::mp

View file

@ -31,6 +31,7 @@ add_executable(dynarmic_tests
A64/testenv.h
fp/unpacked_tests.cpp
main.cpp
mp.cpp
rand_int.h
)

27
tests/mp.cpp Normal file
View file

@ -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 <type_traits>
#include "common/mp/cartesian_product.h"
using namespace Dynarmic::Common::mp;
static_assert(
std::is_same_v<
cartesian_product<list<int, bool>, list<double, float>, list<char, unsigned>>,
list<
list<int, double, char>,
list<int, double, unsigned>,
list<int, float, char>,
list<int, float, unsigned>,
list<bool, double, char>,
list<bool, double, unsigned>,
list<bool, float, char>,
list<bool, float, unsigned>
>
>
);