Skip to content

Commit

Permalink
Merge pull request audacity#4540 from Paul-Licameli/Typelists
Browse files Browse the repository at this point in the history
A small metprogramming library for type list manipulations
  • Loading branch information
Paul-Licameli committed Apr 16, 2023
2 parents 5a3f780 + 5053a57 commit d983207
Show file tree
Hide file tree
Showing 9 changed files with 638 additions and 17 deletions.
14 changes: 4 additions & 10 deletions libraries/lib-module-manager/PluginInterface.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
#include "ComponentInterface.h"
#include "Identifier.h"
#include "PluginProvider.h"
#include "TypeListVisitor.h"
#include <variant>

class PluginProvider;
Expand All @@ -57,7 +58,7 @@ enum ConfigurationType : unsigned {
};

//! Supported types for settings
using ConfigValueTypes = std::tuple<
using ConfigValueTypes = TypeList::List<
wxString
, int
, bool
Expand All @@ -66,17 +67,10 @@ using ConfigValueTypes = std::tuple<
>;

//! Define a reference to a variable of one of the types in ConfigValueTypes
/*! Avoid repetition of the list of types */
template<bool is_const, typename> struct ConfigReferenceGenerator;
template<bool is_const, typename... Types>
struct ConfigReferenceGenerator<is_const, std::tuple<Types...>> {
using type = std::variant< std::reference_wrapper<
std::conditional_t<is_const, const Types, Types> >... >;
};
using ConfigReference =
ConfigReferenceGenerator<false, ConfigValueTypes>::type;
TypeListVisitor::VariantOfReferences_t<false, ConfigValueTypes>;
using ConfigConstReference =
ConfigReferenceGenerator<true, ConfigValueTypes>::type;
TypeListVisitor::VariantOfReferences_t<true, ConfigValueTypes>;

}

Expand Down
3 changes: 3 additions & 0 deletions libraries/lib-utility/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ set( SOURCES
Observer.h
PackedArray.h
spinlock.h
TypeList.cpp
TypeList.h
TypeListVisitor.h
TypedAny.h
)
audacity_library( lib-utility "${SOURCES}" ""
Expand Down
144 changes: 144 additions & 0 deletions libraries/lib-utility/TypeList.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
/**********************************************************************
Audacity: A Digital Audio Editor
@file TypeList.cpp
@brief Examples as a compile-time unit test of metaprogramming utilities
Paul Licameli
**********************************************************************/
#include "TypeList.h"
#include <tuple>

// Enough examples to test compilation of all the templates
namespace { using namespace TypeList; using namespace std;

using Example = List<int, double>;

static_assert(Null_v<Nil>);
static_assert(!Null_v<Example>);

static_assert(0 == Length_v<Nil>);
static_assert(2 == Length_v<Example>);

static_assert(is_same_v<int, Head_t<Example>>);

// These compile even though Head_t<Nil> does not
using Unused = Head<Nil>;
static_assert(is_same_v<int, Head_t<conditional_t<true, Example, Nil>>>);
template <typename T> struct ShortCircuiting
: Head<conditional_t<Null_v<T>, Example, T>>{};
static_assert(is_same_v<int, ShortCircuiting<Nil>::type>);
static_assert(is_same_v<double, ShortCircuiting<List<double>>::type>);

static_assert(is_same_v<List<double>, Tail_t<Example>>);

static_assert(is_same_v<int, First_t<Example>>);
static_assert(is_same_v<double, Second_t<Example>>);

static_assert(is_same_v<Example, Cons_t<int, Cons_t<double, Nil>>>);
static_assert(is_same_v<Example, PushFront_t<PushFront_t<Nil, double>, int>>);
static_assert(is_same_v<Example, PushBack_t<PushBack_t<Nil, int>, double>>);

static_assert(is_same_v<double, Last_t<Example>>);
static_assert(is_same_v<List<int>, ButLast_t<Example>>);

static_assert(is_same_v<Example, Map_t<Identity, Example>>);
static_assert(is_same_v<List<const int, const double>,
Map_t<Fn<add_const_t>, Example>>);
static_assert(is_same_v<List<const int&, const double &>,
Map_t<Fn<add_lvalue_reference_t, add_const_t>, Example>>);
static_assert(is_same_v<List<const int*&, const double *&>,
Map_t<
Fn<add_lvalue_reference_t, add_pointer_t, add_const_t>,
Example>>);
static_assert(is_same_v<List<int *const &, double *const &>,
Map_t<
Compose<
Fn<add_lvalue_reference_t>,
Fn<add_const_t, add_pointer_t>>,
Example>>);

static_assert(is_same_v<tuple<int, double>, Apply_t<tuple, Example>>);
static_assert(is_same_v<tuple<const int, const double>,
Apply_t<tuple, Map_t<Fn<add_const_t>, Example>>>);

static_assert(is_same_v<Nil, Append_t<>>);
static_assert(is_same_v<Example, Append_t<Example>>);
static_assert(is_same_v<List<int, double, char>,
Append_t<Example, List<char>>>);

static_assert(is_same_v<List<double, int>, Reverse_t<Example>>);

static_assert(is_same_v<const int, Call_t<MaybeConst<true>, int>>);
static_assert(is_same_v<int, Call_t<MaybeConst<false>, int>>);

static_assert(is_same_v<List<const int, const double>,
MapConst_t<true, Example>>);
static_assert(is_same_v<Example, MapConst_t<false, Example>>);

static_assert(Is_v<Fn<Null>, Nil>);
static_assert(!Is_v<Fn<Null>, Example>);
static_assert(!Is_v<Not<Fn<Null>>, Nil>);
static_assert(Is_v<Not<Fn<Null>>, Example>);

using HeadIsInt = Compose<Bind1st<is_same, int>, Fn<Head_t>>;
static_assert(Is_v<HeadIsInt, Example>);
// static_assert(!Is_v<HeadIsInt, Nil>); // won't compile

//! Demonstrate short-circuiting behavior of Or and And
using StartsWithInt = And<Not<Fn<Null>>, HeadIsInt>;
static_assert(!Is_v<StartsWithInt, Nil>);
static_assert(Is_v<StartsWithInt, Example>);

using NullOrStartsWithInt = Or<Fn<Null>, HeadIsInt>;
static_assert(Is_v<NullOrStartsWithInt, Nil>);
static_assert(Is_v<NullOrStartsWithInt, Example>);

static_assert(Every_v<Fn<is_arithmetic>, Example>);
static_assert(is_base_of_v<true_type, Every<Fn<is_arithmetic>, Example>>);
static_assert(!Every_v<Fn<is_integral>, Example>);
static_assert(is_base_of_v<is_integral<double>,
Every<Fn<is_integral>, Example>>);

static_assert(Some_v<Fn<is_integral>, Example>);
static_assert(is_base_of_v<is_integral<int>,
Some<Fn<is_integral>, Example>>);
static_assert(!Some_v<Fn<is_void>, Example>);
static_assert(is_base_of_v<false_type, Some<Fn<is_void>, Example>>);

static_assert(NotEvery_v<Fn<is_floating_point>, Example>);
static_assert(NotAny_v<Fn<is_void>, Example>);

static_assert(!In_v<void, Example>);
static_assert(In_v<int, Example>);

struct B {};
struct D : B {};

static_assert(HasBaseIn_v<D, List<B>>);
static_assert(HasBaseIn_v<D, List<D>>);
static_assert(HasBaseIn_v<B, List<B>>);
static_assert(!HasBaseIn_v<B, List<D>>);
static_assert(HasBaseIn_v<B, List<B, D>>);

static_assert(is_same_v<List<Nil, Example>,
StablePartition_t<Fn<is_void>, Example>>);
static_assert(is_same_v<List<List<int>, List<double>>,
StablePartition_t<Fn<is_integral>, Example>>);
static_assert(is_same_v<List<Example, Nil>,
StablePartition_t<Fn<is_arithmetic>, Example>>);

static_assert(is_same_v<Nil, Filter_t<Fn<is_void>, Example>>);
static_assert(is_same_v<List<int>, Filter_t<Fn<is_integral>, Example>>);
static_assert(is_same_v<Example, Filter_t<Fn<is_arithmetic>, Example>>);

using Example2 = Cons_t<unsigned, Example>;
static_assert(is_same_v<List<unsigned>,
Filter_t<And<Not<Fn<is_signed>>, Fn<is_integral>>, Example2>>);
static_assert(is_same_v<List<unsigned, double>,
Filter_t<Or<Not<Fn<is_signed>>, Fn<is_floating_point>>, Example2>>);

// To do: more cases
}
Loading

0 comments on commit d983207

Please sign in to comment.