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

View File

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

View File

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

View File

@ -5,6 +5,7 @@
#include "string.hh"
#include "exception.hh"
#include "containers.hh"
#include "meta.hh"
namespace Kakoune
{
@ -22,10 +23,10 @@ struct Array
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)
{
constexpr auto desc = enum_desc(Flags{});
constexpr auto desc = enum_desc(Meta::Type<Flags>{});
String res;
for (int i = 0; i < desc.size(); ++i)
{
@ -38,10 +39,10 @@ EnableIfWithBitOps<Flags, String> option_to_string(Flags flags)
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)
{
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; });
if (it != desc.end())
return it->name.str();
@ -49,10 +50,10 @@ EnableIfWithoutBitOps<Enum, String> option_to_string(Enum e)
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)
{
constexpr auto desc = enum_desc(Flags{});
constexpr auto desc = enum_desc(Meta::Type<Flags>{});
flags = Flags{};
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)
{
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; });
if (it == desc.end())
throw runtime_error(format("invalid enum value '{}'", str));
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)
{
Flags res = Flags{};

View File

@ -134,7 +134,7 @@ enum class AutoInfo
template<>
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 { {
{ AutoInfo::Command, "command"},

View File

@ -37,18 +37,18 @@ using InsertCompleterDescList = Vector<InsertCompleterDesc, MemoryDomain::Option
String option_to_string(const 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 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
{

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;
throw runtime_error{format("option '{}' already declared with different type or flags", name)};
}
String doc = docstring.empty() ? format("[{}]", option_type_name<T>::name())
: format("[{}] - {}", option_type_name<T>::name(), docstring);
String doc = docstring.empty() ? format("[{}]", option_type_name(Meta::Type<T>{}))
: format("[{}] - {}", option_type_name(Meta::Type<T>{}), docstring);
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});
return *opts.back();

View File

@ -16,25 +16,22 @@
namespace Kakoune
{
template<typename T, typename = void> struct option_type_name;
template<typename T> using void_t = void;
template<typename T> using valid = std::true_type;
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>
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(Enum{});
auto name = enum_desc(Meta::Type<Enum>{});
return type + "(" + join(name | transform(std::mem_fn(&EnumDesc<Enum>::name)), '|') + ")";
}
};
}
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); }
@ -44,7 +41,7 @@ inline bool option_add(int& opt, StringView str)
opt += val;
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 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
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 = ':';
@ -101,10 +98,10 @@ bool option_add(Vector<T, domain>& opt, StringView str)
}
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>
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>
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",
option_type_name<K>::name(),
option_type_name<V>::name()); }
};
return format("{}-to-{}-map", option_type_name(Meta::Type<K>{}),
option_type_name(Meta::Type<V>{}));
}
constexpr char tuple_separator = '|';
@ -251,7 +247,7 @@ enum class DebugFlags
template<>
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 { {
{ DebugFlags::Hooks, "hooks" },