Refactor option_from_string to return directly the option value

This commit is contained in:
Maxime Coste 2018-05-27 13:00:04 +10:00
parent 2617f5e022
commit b5693c6253
12 changed files with 73 additions and 114 deletions

View File

@ -81,9 +81,9 @@ String option_to_string(Color color)
return to_string(color); return to_string(color);
} }
void option_from_string(StringView str, Color& color) Color option_from_string(Meta::Type<Color>, StringView str)
{ {
color = str_to_color(str); return str_to_color(str);
} }
} }

View File

@ -2,6 +2,7 @@
#define color_hh_INCLUDED #define color_hh_INCLUDED
#include "hash.hh" #include "hash.hh"
#include "meta.hh"
namespace Kakoune namespace Kakoune
{ {
@ -59,7 +60,7 @@ Color str_to_color(StringView color);
String to_string(Color color); String to_string(Color color);
String option_to_string(Color color); String option_to_string(Color color);
void option_from_string(StringView str, Color& color); Color option_from_string(Meta::Type<Color>, StringView str);
bool is_color_name(StringView color); bool is_color_name(StringView color);

View File

@ -1379,7 +1379,7 @@ String option_to_string(InclusiveBufferRange range)
range.last.line+1, range.last.column+1); range.last.line+1, range.last.column+1);
} }
void option_from_string(StringView str, InclusiveBufferRange& opt) InclusiveBufferRange option_from_string(Meta::Type<InclusiveBufferRange>, StringView str)
{ {
auto sep = find_if(str, [](char c){ return c == ',' or c == '+'; }); auto sep = find_if(str, [](char c){ return c == ',' or c == '+'; });
auto dot_beg = find(StringView{str.begin(), sep}, '.'); auto dot_beg = find(StringView{str.begin(), sep}, '.');
@ -1400,7 +1400,7 @@ void option_from_string(StringView str, InclusiveBufferRange& opt)
if (first.line < 0 or first.column < 0 or last.line < 0 or last.column < 0) if (first.line < 0 or first.column < 0 or last.line < 0 or last.column < 0)
throw runtime_error("coordinates elements should be >= 1"); throw runtime_error("coordinates elements should be >= 1");
opt = { std::min(first, last), std::max(first, last) }; return { std::min(first, last), std::max(first, last) };
} }
BufferCoord& get_first(RangeAndString& r) { return std::get<0>(r).first; } BufferCoord& get_first(RangeAndString& r) { return std::get<0>(r).first; }

View File

@ -17,7 +17,7 @@ inline bool operator==(const InclusiveBufferRange& lhs, const InclusiveBufferRan
return lhs.first == rhs.first and lhs.last == rhs.last; return lhs.first == rhs.first and lhs.last == rhs.last;
} }
String option_to_string(InclusiveBufferRange range); String option_to_string(InclusiveBufferRange range);
void option_from_string(StringView str, InclusiveBufferRange& opt); InclusiveBufferRange option_from_string(Meta::Type<InclusiveBufferRange>, StringView str);
using LineAndSpec = std::tuple<LineCount, String>; using LineAndSpec = std::tuple<LineCount, String>;
using LineAndSpecList = TimestampedList<LineAndSpec>; using LineAndSpecList = TimestampedList<LineAndSpec>;

View File

@ -40,39 +40,23 @@ String option_to_string(const InsertCompleterDesc& opt)
return ""; return "";
} }
void option_from_string(StringView str, InsertCompleterDesc& opt) InsertCompleterDesc option_from_string(Meta::Type<InsertCompleterDesc>, StringView str)
{ {
if (str.substr(0_byte, 7_byte) == "option=") if (str.substr(0_byte, 7_byte) == "option=")
{ return {InsertCompleterDesc::Option, str.substr(7_byte).str()};
opt.mode = InsertCompleterDesc::Option;
opt.param = str.substr(7_byte).str();
return;
}
else if (str.substr(0_byte, 5_byte) == "word=") else if (str.substr(0_byte, 5_byte) == "word=")
{ {
auto param = str.substr(5_byte); auto param = str.substr(5_byte);
if (param == "all" or param == "buffer") if (param == "all" or param == "buffer")
{ return {InsertCompleterDesc::Word, param.str()};
opt.mode = InsertCompleterDesc::Word;
opt.param = param.str();
return;
}
} }
else if (str == "filename") else if (str == "filename")
{ return {InsertCompleterDesc::Filename, {}};
opt.mode = InsertCompleterDesc::Filename;
opt.param = Optional<String>{};
return;
}
else if (str.substr(0_byte, 5_byte) == "line=") else if (str.substr(0_byte, 5_byte) == "line=")
{ {
auto param = str.substr(5_byte); auto param = str.substr(5_byte);
if (param == "all" or param == "buffer") if (param == "all" or param == "buffer")
{ return {InsertCompleterDesc::Line, param.str()};
opt.mode = InsertCompleterDesc::Line;
opt.param = param.str();
return;
}
} }
throw runtime_error(format("invalid completer description: '{}'", str)); throw runtime_error(format("invalid completer description: '{}'", str));
} }

View File

@ -38,7 +38,7 @@ struct InsertCompleterDesc
using InsertCompleterDescList = Vector<InsertCompleterDesc, MemoryDomain::Options>; using InsertCompleterDescList = Vector<InsertCompleterDesc, MemoryDomain::Options>;
String option_to_string(const InsertCompleterDesc& opt); String option_to_string(const InsertCompleterDesc& opt);
void option_from_string(StringView str, InsertCompleterDesc& opt); InsertCompleterDesc option_from_string(Meta::Type<InsertCompleterDesc>, StringView str);
inline StringView option_type_name(Meta::Type<InsertCompleterDesc>) inline StringView option_type_name(Meta::Type<InsertCompleterDesc>)
{ {

View File

@ -147,9 +147,7 @@ public:
} }
void set_from_string(StringView str) override void set_from_string(StringView str) override
{ {
T val; set(option_from_string(Meta::Type<T>{}, str));
option_from_string(str, val);
set(std::move(val));
} }
void add_from_string(StringView str) override void add_from_string(StringView str) override
{ {

View File

@ -9,8 +9,7 @@ UnitTest test_option_parsing{[]{
{ {
auto repr = option_to_string(value); auto repr = option_to_string(value);
kak_assert(repr == str); kak_assert(repr == str);
std::decay_t<decltype(value)> parsed; auto parsed = option_from_string(Meta::Type<std::decay_t<decltype(value)>>{}, str);
option_from_string(str, parsed);
kak_assert(parsed == value); kak_assert(parsed == value);
}; };

View File

@ -34,7 +34,7 @@ option_type_name(Meta::Type<Enum>)
} }
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 int option_from_string(Meta::Type<int>, StringView str) { return str_to_int(str); }
inline bool option_add(int& opt, StringView str) inline bool option_add(int& opt, StringView str)
{ {
auto val = str_to_int(str); auto val = str_to_int(str);
@ -44,26 +44,26 @@ inline bool option_add(int& opt, StringView str)
constexpr StringView option_type_name(Meta::Type<int>) { return "int"; } constexpr 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 size_t option_from_string(Meta::Type<size_t>, StringView str) { return str_to_int(str); }
inline String option_to_string(bool opt) { return opt ? "true" : "false"; } inline String option_to_string(bool opt) { return opt ? "true" : "false"; }
inline void option_from_string(StringView str, bool& opt) inline bool option_from_string(Meta::Type<bool>, StringView str)
{ {
if (str == "true" or str == "yes") if (str == "true" or str == "yes")
opt = true; return true;
else if (str == "false" or str == "no") else if (str == "false" or str == "no")
opt = false; return false;
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");
} }
constexpr StringView option_type_name(Meta::Type<bool>) { return "bool"; } constexpr StringView option_type_name(Meta::Type<bool>) { return "bool"; }
inline String option_to_string(Codepoint opt) { return to_string(opt); } inline String option_to_string(Codepoint opt) { return to_string(opt); }
inline void option_from_string(StringView str, Codepoint& opt) inline Codepoint option_from_string(Meta::Type<Codepoint>, StringView str)
{ {
if (str.char_length() != 1) if (str.char_length() != 1)
throw runtime_error{format("'{}' is not a single codepoint", str)}; throw runtime_error{format("'{}' is not a single codepoint", str)};
opt = str[0_char]; return str[0_char];
} }
constexpr StringView option_type_name(Meta::Type<Codepoint>) { return "codepoint"; } constexpr StringView option_type_name(Meta::Type<Codepoint>) { return "codepoint"; }
@ -81,24 +81,20 @@ void option_list_postprocess(Vector<T, domain>& opt)
{} {}
template<typename T, MemoryDomain domain> template<typename T, MemoryDomain domain>
void option_from_string(StringView str, Vector<T, domain>& opt) Vector<T, domain> option_from_string(Meta::Type<Vector<T, domain>>, StringView str)
{ {
opt.clear(); auto res = str | split<StringView>(list_separator, '\\')
for (auto&& elem : str | split<StringView>(list_separator, '\\') | transform(unescape<list_separator, '\\'>)
| transform(unescape<list_separator, '\\'>)) | transform([](auto&& s) { return option_from_string(Meta::Type<T>{}, s); })
{ | gather<Vector<T, domain>>();
T opt_elem; option_list_postprocess(res);
option_from_string(elem, opt_elem); return res;
opt.push_back(opt_elem);
}
option_list_postprocess(opt);
} }
template<typename T, MemoryDomain domain> template<typename T, MemoryDomain domain>
bool option_add(Vector<T, domain>& opt, StringView str) bool option_add(Vector<T, domain>& opt, StringView str)
{ {
Vector<T, domain> vec; auto vec = option_from_string(Meta::Type<Vector<T, domain>>{}, str);
option_from_string(str, vec);
opt.insert(opt.end(), opt.insert(opt.end(),
std::make_move_iterator(vec.begin()), std::make_move_iterator(vec.begin()),
std::make_move_iterator(vec.end())); std::make_move_iterator(vec.end()));
@ -139,20 +135,18 @@ bool option_add(HashMap<Key, Value, domain>& opt, StringView str)
| transform(unescape<'=', '\\'>) | transform(unescape<'=', '\\'>)
| static_gather<error, 2>(); | static_gather<error, 2>();
HashItem<Key, Value> item; opt[option_from_string(Meta::Type<Key>{}, key_value[0])] = option_from_string(Meta::Type<Value>{}, key_value[1]);
option_from_string(key_value[0], item.key);
option_from_string(key_value[1], item.value);
opt[std::move(item.key)] = std::move(item.value);
changed = true; changed = true;
} }
return changed; return changed;
} }
template<typename Key, typename Value, MemoryDomain domain> template<typename Key, typename Value, MemoryDomain domain>
void option_from_string(StringView str, HashMap<Key, Value, domain>& opt) HashMap<Key, Value, domain> option_from_string(Meta::Type<HashMap<Key, Value, domain>>, StringView str)
{ {
opt.clear(); HashMap<Key, Value, domain> res;
option_add(opt, str); option_add(res, str);
return res;
} }
template<typename K, typename V, MemoryDomain D> template<typename K, typename V, MemoryDomain D>
@ -164,44 +158,21 @@ String option_type_name(Meta::Type<HashMap<K, V, D>>)
constexpr char tuple_separator = '|'; constexpr char tuple_separator = '|';
template<size_t I, typename... Types> template<typename... Types, size_t... I>
struct TupleOptionDetail String option_to_string_impl(const std::tuple<Types...>& opt, std::index_sequence<I...>)
{ {
static String to_string(const std::tuple<Types...>& opt) return join(make_array({option_to_string(std::get<I>(opt))...}), tuple_separator);
{ }
return TupleOptionDetail<I-1, Types...>::to_string(opt) +
tuple_separator + escape(option_to_string(std::get<I>(opt)), tuple_separator, '\\');
}
static void from_string(ConstArrayView<String> elems, std::tuple<Types...>& opt)
{
option_from_string(elems[I], std::get<I>(opt));
TupleOptionDetail<I-1, Types...>::from_string(elems, opt);
}
};
template<typename... Types>
struct TupleOptionDetail<0, Types...>
{
static String to_string(const std::tuple<Types...>& opt)
{
return option_to_string(std::get<0>(opt));
}
static void from_string(ConstArrayView<String> elems, std::tuple<Types...>& opt)
{
option_from_string(elems[0], std::get<0>(opt));
}
};
template<typename... Types> template<typename... Types>
String option_to_string(const std::tuple<Types...>& opt) String option_to_string(const std::tuple<Types...>& opt)
{ {
return TupleOptionDetail<sizeof...(Types)-1, Types...>::to_string(opt); return option_to_string_impl(opt, std::make_index_sequence<sizeof...(Types)>());
} }
template<typename... Types> template<typename... Types, size_t... I>
void option_from_string(StringView str, std::tuple<Types...>& opt) std::tuple<Types...> option_from_string_impl(Meta::Type<std::tuple<Types...>>, StringView str,
std::index_sequence<I...>)
{ {
struct error : runtime_error struct error : runtime_error
{ {
@ -212,8 +183,14 @@ void option_from_string(StringView str, std::tuple<Types...>& opt)
auto elems = str | split<StringView>(tuple_separator, '\\') auto elems = str | split<StringView>(tuple_separator, '\\')
| transform(unescape<tuple_separator, '\\'>) | transform(unescape<tuple_separator, '\\'>)
| static_gather<error, sizeof...(Types)>(); | static_gather<error, sizeof...(Types)>();
return {option_from_string(Meta::Type<Types>{}, elems[I])...};
}
TupleOptionDetail<sizeof...(Types)-1, Types...>::from_string(elems, opt); template<typename... Types>
std::tuple<Types...> option_from_string(Meta::Type<std::tuple<Types...>>, StringView str)
{
return option_from_string_impl(Meta::Type<std::tuple<Types...>>{}, str,
std::make_index_sequence<sizeof...(Types)>());
} }
template<typename RealType, typename ValueType> template<typename RealType, typename ValueType>
@ -222,15 +199,15 @@ inline String option_to_string(const StronglyTypedNumber<RealType, ValueType>& o
return to_string(opt); return to_string(opt);
} }
template<typename RealType, typename ValueType> template<typename Number>
inline void option_from_string(StringView str, StronglyTypedNumber<RealType, ValueType>& opt) std::enable_if_t<std::is_base_of<StronglyTypedNumber<Number, int>, Number>::value, Number>
option_from_string(Meta::Type<Number>, StringView str)
{ {
opt = StronglyTypedNumber<RealType, ValueType>{str_to_int(str)}; return Number{str_to_int(str)};
} }
template<typename RealType, typename ValueType> template<typename RealType, typename ValueType>
inline bool option_add(StronglyTypedNumber<RealType, ValueType>& opt, inline bool option_add(StronglyTypedNumber<RealType, ValueType>& opt, StringView str)
StringView str)
{ {
int val = str_to_int(str); int val = str_to_int(str);
opt += val; opt += val;
@ -251,14 +228,14 @@ inline void option_update(WorstMatch, const Context&)
throw runtime_error("no update operation supported for this option type"); throw runtime_error("no update operation supported for this option type");
} }
template<typename EffectiveType, typename LineType, typename ColumnType> template<typename Coord>
inline void option_from_string(StringView str, LineAndColumn<EffectiveType, LineType, ColumnType>& opt) std::enable_if_t<std::is_base_of<LineAndColumn<Coord, decltype(Coord::line), decltype(Coord::column)>, Coord>::value, Coord>
option_from_string(Meta::Type<Coord>, StringView str)
{ {
struct error : runtime_error { error(size_t) : runtime_error{"expected <line>,<column>"} {} }; struct error : runtime_error { error(size_t) : runtime_error{"expected <line>,<column>"} {} };
auto vals = str | split<StringView>(',') auto vals = str | split<StringView>(',')
| static_gather<error, 2>(); | static_gather<error, 2>();
opt.line = str_to_int(vals[0]); return {str_to_int(vals[0]), str_to_int(vals[1])};
opt.column = str_to_int(vals[1]);
} }
template<typename EffectiveType, typename LineType, typename ColumnType> template<typename EffectiveType, typename LineType, typename ColumnType>
@ -295,10 +272,10 @@ EnableIfWithoutBitOps<Enum, String> option_to_string(Enum e)
} }
template<typename Flags, typename = decltype(enum_desc(Meta::Type<Flags>{}))> template<typename Flags, typename = decltype(enum_desc(Meta::Type<Flags>{}))>
EnableIfWithBitOps<Flags> option_from_string(StringView str, Flags& flags) EnableIfWithBitOps<Flags, Flags> option_from_string(Meta::Type<Flags>, StringView str)
{ {
constexpr auto desc = enum_desc(Meta::Type<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>('|'))
{ {
auto it = find_if(desc, [s](const EnumDesc<Flags>& d) { return d.name == s; }); auto it = find_if(desc, [s](const EnumDesc<Flags>& d) { return d.name == s; });
@ -306,23 +283,23 @@ EnableIfWithBitOps<Flags> option_from_string(StringView str, Flags& flags)
throw runtime_error(format("invalid flag value '{}'", s)); throw runtime_error(format("invalid flag value '{}'", s));
flags |= it->value; flags |= it->value;
} }
return flags;
} }
template<typename Enum, typename = decltype(enum_desc(Meta::Type<Enum>{}))> template<typename Enum, typename = decltype(enum_desc(Meta::Type<Enum>{}))>
EnableIfWithoutBitOps<Enum> option_from_string(StringView str, Enum& e) EnableIfWithoutBitOps<Enum, Enum> option_from_string(Meta::Type<Enum>, StringView str)
{ {
constexpr auto desc = enum_desc(Meta::Type<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; return it->value;
} }
template<typename Flags, typename = decltype(enum_desc(Meta::Type<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{}; const Flags res = option_from_string(Meta::Type<Flags>{}, str);
option_from_string(str, res);
opt |= res; opt |= res;
return res != (Flags)0; return res != (Flags)0;
} }
@ -338,12 +315,12 @@ inline String option_to_string(const PrefixedList<P, T>& opt)
} }
template<typename P, typename T> template<typename P, typename T>
inline void option_from_string(StringView str, PrefixedList<P, T>& opt) inline PrefixedList<P, T> option_from_string(Meta::Type<PrefixedList<P, T>>, StringView str)
{ {
using VecType = Vector<T, MemoryDomain::Options>;
auto it = find(str, list_separator); auto it = find(str, list_separator);
option_from_string(StringView{str.begin(), it}, opt.prefix); return {option_from_string(Meta::Type<P>{}, StringView{str.begin(), it}),
if (it != str.end()) it != str.end() ? option_from_string(Meta::Type<VecType>{}, {it+1, str.end()}) : VecType{}};
option_from_string({it+1, str.end()}, opt.list);
} }
template<typename P, typename T> template<typename P, typename T>

View File

@ -13,9 +13,9 @@ String option_to_string(const Regex& re)
return re.str(); return re.str();
} }
void option_from_string(StringView str, Regex& re) Regex option_from_string(Meta::Type<Regex>, StringView str)
{ {
re = Regex{str}; return Regex{str};
} }
} }

View File

@ -161,7 +161,7 @@ bool backward_regex_search(It begin, It end, It subject_begin, It subject_end,
} }
String option_to_string(const Regex& re); String option_to_string(const Regex& re);
void option_from_string(StringView str, Regex& re); Regex option_from_string(Meta::Type<Regex>, StringView str);
template<typename Iterator, MatchDirection direction = MatchDirection::Forward> template<typename Iterator, MatchDirection direction = MatchDirection::Forward>
struct RegexIterator struct RegexIterator

View File

@ -66,7 +66,7 @@ int str_to_int(StringView str); // throws on error
Optional<int> str_to_int_ifp(StringView str); Optional<int> str_to_int_ifp(StringView str);
inline String option_to_string(StringView opt) { return opt.str(); } inline String option_to_string(StringView opt) { return opt.str(); }
inline void option_from_string(StringView str, String& opt) { opt = str.str(); } inline String option_from_string(Meta::Type<String>, StringView str) { return str.str(); }
inline bool option_add(String& opt, StringView val) { opt += val; return not val.empty(); } inline bool option_add(String& opt, StringView val) { opt += val; return not val.empty(); }
template<size_t N> template<size_t N>