Migrate to a more value based meta programming model

Introduce Meta::Type<T> to store a type as value, and pass it
around, migrate enum_desc and option_type_name to this.
This commit is contained in:
Maxime Coste 2017-03-15 17:42:02 +00:00
parent a88e58763b
commit a49e175727
9 changed files with 62 additions and 53 deletions

View File

@ -21,7 +21,7 @@ enum class EolFormat
Crlf Crlf
}; };
constexpr Array<EnumDesc<EolFormat>, 2> enum_desc(EolFormat) constexpr Array<EnumDesc<EolFormat>, 2> enum_desc(Meta::Type<EolFormat>)
{ {
return { { return { {
{ EolFormat::Lf, "lf" }, { EolFormat::Lf, "lf" },
@ -35,7 +35,7 @@ enum class ByteOrderMark
Utf8 Utf8
}; };
constexpr Array<EnumDesc<ByteOrderMark>, 2> enum_desc(ByteOrderMark) constexpr Array<EnumDesc<ByteOrderMark>, 2> enum_desc(Meta::Type<ByteOrderMark>)
{ {
return { { return { {
{ ByteOrderMark::None, "none" }, { ByteOrderMark::None, "none" },

View File

@ -131,7 +131,7 @@ enum class Autoreload
Ask Ask
}; };
constexpr Array<EnumDesc<Autoreload>, 5> enum_desc(Autoreload) constexpr Array<EnumDesc<Autoreload>, 5> enum_desc(Meta::Type<Autoreload>)
{ {
return { { return { {
{ Autoreload::Yes, "yes" }, { Autoreload::Yes, "yes" },

View File

@ -43,17 +43,15 @@
namespace Kakoune namespace Kakoune
{ {
template<> StringView option_type_name(Meta::Type<TimestampedList<LineAndFlag>>)
struct option_type_name<TimestampedList<LineAndFlag>>
{ {
static StringView name() { return "line-flags"; } return "line-flags";
}; }
template<> StringView option_type_name(Meta::Type<TimestampedList<RangeAndFace>>)
struct option_type_name<TimestampedList<RangeAndFace>>
{ {
static StringView name() { return "range-faces"; } return "range-faces";
}; }
namespace namespace
{ {

View File

@ -5,6 +5,7 @@
#include "string.hh" #include "string.hh"
#include "exception.hh" #include "exception.hh"
#include "containers.hh" #include "containers.hh"
#include "meta.hh"
namespace Kakoune namespace Kakoune
{ {
@ -22,10 +23,10 @@ struct Array
template<typename T> struct EnumDesc { T value; StringView name; }; template<typename T> struct EnumDesc { T value; StringView name; };
template<typename Flags, typename = decltype(enum_desc(Flags{}))> template<typename Flags, typename = decltype(enum_desc(Meta::Type<Flags>{}))>
EnableIfWithBitOps<Flags, String> option_to_string(Flags flags) EnableIfWithBitOps<Flags, String> option_to_string(Flags flags)
{ {
constexpr auto desc = enum_desc(Flags{}); constexpr auto desc = enum_desc(Meta::Type<Flags>{});
String res; String res;
for (int i = 0; i < desc.size(); ++i) for (int i = 0; i < desc.size(); ++i)
{ {
@ -38,10 +39,10 @@ EnableIfWithBitOps<Flags, String> option_to_string(Flags flags)
return res; return res;
} }
template<typename Enum, typename = decltype(enum_desc(Enum{}))> template<typename Enum, typename = decltype(enum_desc(Meta::Type<Enum>{}))>
EnableIfWithoutBitOps<Enum, String> option_to_string(Enum e) EnableIfWithoutBitOps<Enum, String> option_to_string(Enum e)
{ {
constexpr auto desc = enum_desc(Enum{}); constexpr auto desc = enum_desc(Meta::Type<Enum>{});
auto it = find_if(desc, [e](const EnumDesc<Enum>& d) { return d.value == e; }); auto it = find_if(desc, [e](const EnumDesc<Enum>& d) { return d.value == e; });
if (it != desc.end()) if (it != desc.end())
return it->name.str(); return it->name.str();
@ -49,10 +50,10 @@ EnableIfWithoutBitOps<Enum, String> option_to_string(Enum e)
return {}; return {};
} }
template<typename Flags, typename = decltype(enum_desc(Flags{}))> template<typename Flags, typename = decltype(enum_desc(Meta::Type<Flags>{}))>
EnableIfWithBitOps<Flags> option_from_string(StringView str, Flags& flags) EnableIfWithBitOps<Flags> option_from_string(StringView str, Flags& flags)
{ {
constexpr auto desc = enum_desc(Flags{}); constexpr auto desc = enum_desc(Meta::Type<Flags>{});
flags = Flags{}; flags = Flags{};
for (auto s : str | split<StringView>('|')) for (auto s : str | split<StringView>('|'))
{ {
@ -63,17 +64,17 @@ EnableIfWithBitOps<Flags> option_from_string(StringView str, Flags& flags)
} }
} }
template<typename Enum, typename = decltype(enum_desc(Enum{}))> template<typename Enum, typename = decltype(enum_desc(Meta::Type<Enum>{}))>
EnableIfWithoutBitOps<Enum> option_from_string(StringView str, Enum& e) EnableIfWithoutBitOps<Enum> option_from_string(StringView str, Enum& e)
{ {
constexpr auto desc = enum_desc(Enum{}); constexpr auto desc = enum_desc(Meta::Type<Enum>{});
auto it = find_if(desc, [str](const EnumDesc<Enum>& d) { return d.name == str; }); auto it = find_if(desc, [str](const EnumDesc<Enum>& d) { return d.name == str; });
if (it == desc.end()) if (it == desc.end())
throw runtime_error(format("invalid enum value '{}'", str)); throw runtime_error(format("invalid enum value '{}'", str));
e = it->value; e = it->value;
} }
template<typename Flags, typename = decltype(enum_desc(Flags{}))> template<typename Flags, typename = decltype(enum_desc(Meta::Type<Flags>{}))>
EnableIfWithBitOps<Flags, bool> option_add(Flags& opt, StringView str) EnableIfWithBitOps<Flags, bool> option_add(Flags& opt, StringView str)
{ {
Flags res = Flags{}; Flags res = Flags{};

View File

@ -134,7 +134,7 @@ enum class AutoInfo
template<> template<>
struct WithBitOps<AutoInfo> : std::true_type {}; struct WithBitOps<AutoInfo> : std::true_type {};
constexpr Array<EnumDesc<AutoInfo>, 3> enum_desc(AutoInfo) constexpr Array<EnumDesc<AutoInfo>, 3> enum_desc(Meta::Type<AutoInfo>)
{ {
return { { return { {
{ AutoInfo::Command, "command"}, { AutoInfo::Command, "command"},

View File

@ -37,18 +37,18 @@ using InsertCompleterDescList = Vector<InsertCompleterDesc, MemoryDomain::Option
String option_to_string(const InsertCompleterDesc& opt); String option_to_string(const InsertCompleterDesc& opt);
void option_from_string(StringView str, InsertCompleterDesc& opt); void option_from_string(StringView str, InsertCompleterDesc& opt);
template<> struct option_type_name<InsertCompleterDesc> inline StringView option_type_name(Meta::Type<InsertCompleterDesc>)
{ {
static constexpr StringView name() { return "completer"; } return "completer";
}; }
using CompletionCandidate = std::tuple<String, String, String>; using CompletionCandidate = std::tuple<String, String, String>;
using CompletionList = PrefixedList<String, CompletionCandidate>; using CompletionList = PrefixedList<String, CompletionCandidate>;
template<> struct option_type_name<CompletionList> inline StringView option_type_name(Meta::Type<CompletionList>)
{ {
static constexpr StringView name() { return "completions"; } return "completions";
}; }
struct InsertCompletion struct InsertCompletion
{ {

14
src/meta.hh Normal file
View File

@ -0,0 +1,14 @@
#ifndef meta_hh_INCLUDED
#define meta_hh_INCLUDED
namespace Kakoune
{
namespace Meta
{
template<typename T> struct Type {};
}
}
#endif // meta_hh_INCLUDED

View File

@ -221,8 +221,8 @@ public:
return **it; return **it;
throw runtime_error{format("option '{}' already declared with different type or flags", name)}; throw runtime_error{format("option '{}' already declared with different type or flags", name)};
} }
String doc = docstring.empty() ? format("[{}]", option_type_name<T>::name()) String doc = docstring.empty() ? format("[{}]", option_type_name(Meta::Type<T>{}))
: format("[{}] - {}", option_type_name<T>::name(), docstring); : format("[{}] - {}", option_type_name(Meta::Type<T>{}), docstring);
m_descs.emplace_back(new OptionDesc{name.str(), std::move(doc), flags}); m_descs.emplace_back(new OptionDesc{name.str(), std::move(doc), flags});
opts.emplace_back(new TypedCheckedOption<T, validator>{m_global_manager, *m_descs.back(), value}); opts.emplace_back(new TypedCheckedOption<T, validator>{m_global_manager, *m_descs.back(), value});
return *opts.back(); return *opts.back();

View File

@ -16,25 +16,22 @@
namespace Kakoune namespace Kakoune
{ {
template<typename T, typename = void> struct option_type_name; template<typename T> using valid = std::true_type;
template<typename T> using void_t = void;
template<typename T> template<typename T>
struct option_type_name<T, void_t<decltype(T::option_type_name)>> constexpr decltype(T::option_type_name) option_type_name(Meta::Type<T>)
{ {
static decltype(T::option_type_name) name() { return T::option_type_name; } return T::option_type_name;
}; }
template<typename Enum> template<typename Enum>
struct option_type_name<Enum, typename std::enable_if<std::is_enum<Enum>::value>::type> typename std::enable_if<std::is_enum<Enum>::value, String>::type
option_type_name(Meta::Type<Enum>)
{ {
static String name() constexpr StringView type = WithBitOps<Enum>::value ? "flags" : "enum";
{ auto name = enum_desc(Meta::Type<Enum>{});
constexpr StringView type = WithBitOps<Enum>::value ? "flags" : "enum"; return type + "(" + join(name | transform(std::mem_fn(&EnumDesc<Enum>::name)), '|') + ")";
auto name = enum_desc(Enum{}); }
return type + "(" + join(name | transform(std::mem_fn(&EnumDesc<Enum>::name)), '|') + ")";
}
};
inline String option_to_string(int opt) { return to_string(opt); } inline String option_to_string(int opt) { return to_string(opt); }
inline void option_from_string(StringView str, int& opt) { opt = str_to_int(str); } inline void option_from_string(StringView str, int& opt) { opt = str_to_int(str); }
@ -44,7 +41,7 @@ inline bool option_add(int& opt, StringView str)
opt += val; opt += val;
return val != 0; return val != 0;
} }
template<> struct option_type_name<int> { static StringView name() { return "int"; } }; inline StringView option_type_name(Meta::Type<int>) { return "int"; }
inline String option_to_string(size_t opt) { return to_string(opt); } inline String option_to_string(size_t opt) { return to_string(opt); }
inline void option_from_string(StringView str, size_t& opt) { opt = str_to_int(str); } inline void option_from_string(StringView str, size_t& opt) { opt = str_to_int(str); }
@ -59,7 +56,7 @@ inline void option_from_string(StringView str, bool& opt)
else else
throw runtime_error("boolean values are either true, yes, false or no"); throw runtime_error("boolean values are either true, yes, false or no");
} }
template<> struct option_type_name<bool> { static StringView name() { return "bool"; } }; inline StringView option_type_name(Meta::Type<bool>) { return "bool"; }
constexpr char list_separator = ':'; constexpr char list_separator = ':';
@ -101,10 +98,10 @@ bool option_add(Vector<T, domain>& opt, StringView str)
} }
template<typename T, MemoryDomain D> template<typename T, MemoryDomain D>
struct option_type_name<Vector<T, D>> String option_type_name(Meta::Type<Vector<T, D>>)
{ {
static String name() { return option_type_name<T>::name() + StringView{"-list"}; } return option_type_name(Meta::Type<T>{}) + StringView{"-list"};
}; }
template<typename Key, typename Value, MemoryDomain domain> template<typename Key, typename Value, MemoryDomain domain>
String option_to_string(const HashMap<Key, Value, domain>& opt) String option_to_string(const HashMap<Key, Value, domain>& opt)
@ -139,12 +136,11 @@ void option_from_string(StringView str, HashMap<Key, Value, domain>& opt)
} }
template<typename K, typename V, MemoryDomain D> template<typename K, typename V, MemoryDomain D>
struct option_type_name<HashMap<K, V, D>> String option_type_name(Meta::Type<HashMap<K, V, D>>)
{ {
static String name() { return format("{}-to-{}-map", return format("{}-to-{}-map", option_type_name(Meta::Type<K>{}),
option_type_name<K>::name(), option_type_name(Meta::Type<V>{}));
option_type_name<V>::name()); } }
};
constexpr char tuple_separator = '|'; constexpr char tuple_separator = '|';
@ -251,7 +247,7 @@ enum class DebugFlags
template<> template<>
struct WithBitOps<DebugFlags> : std::true_type {}; struct WithBitOps<DebugFlags> : std::true_type {};
constexpr Array<EnumDesc<DebugFlags>, 4> enum_desc(DebugFlags) constexpr Array<EnumDesc<DebugFlags>, 4> enum_desc(Meta::Type<DebugFlags>)
{ {
return { { return { {
{ DebugFlags::Hooks, "hooks" }, { DebugFlags::Hooks, "hooks" },