refactor splitter

This commit is contained in:
ado 2021-01-17 14:53:07 +01:00
parent 263dba7626
commit 024e5d3810
4 changed files with 57 additions and 62 deletions

View File

@ -33,6 +33,7 @@ std::enable_if_t<std::is_floating_point_v<T>, T> pow10(int n) {
return ret; return ret;
} }
// TODO not working with large number of digits
template <typename T> template <typename T>
std::enable_if_t<std::is_floating_point_v<T>, std::optional<T>> to_num( std::enable_if_t<std::is_floating_point_v<T>, std::optional<T>> to_num(
const char* begin, const char* const end) { const char* begin, const char* const end) {

View File

@ -31,22 +31,6 @@ public:
static bool match(char c) = delete; static bool match(char c) = delete;
}; };
////////////////
// is instance of
////////////////
template <typename T, template <char...> class Template>
struct is_instance_of_char {
constexpr static bool value = false;
};
template <char... Ts, template <char...> class Template>
struct is_instance_of_char<Template<Ts...>, Template> {
constexpr static bool value = true;
};
///////////////////////////////////////////////////
template <char... Cs> template <char... Cs>
struct quote : matcher<Cs...> {}; struct quote : matcher<Cs...> {};
@ -56,30 +40,24 @@ struct trim : matcher<Cs...> {};
template <char... Cs> template <char... Cs>
struct escape : matcher<Cs...> {}; struct escape : matcher<Cs...> {};
///////////////////////////////////////////////// template <typename T, template <char...> class Template>
// -> type traits struct is_instance_of_matcher {
template <bool B, typename T, typename U> constexpr static bool value = false;
struct if_then_else;
template <typename T, typename U>
struct if_then_else<true, T, U> {
using type = T;
}; };
template <typename T, typename U> template <char... Ts, template <char...> class Template>
struct if_then_else<false, T, U> { struct is_instance_of_matcher<Template<Ts...>, Template> {
using type = U; constexpr static bool value = true;
}; };
//////////////////////////////////////////////
template <template <char...> class Matcher, typename... Ts> template <template <char...> class Matcher, typename... Ts>
struct get_matcher; struct get_matcher;
template <template <char...> class Matcher, typename T, typename... Ts> template <template <char...> class Matcher, typename T, typename... Ts>
struct get_matcher<Matcher, T, Ts...> { struct get_matcher<Matcher, T, Ts...> {
using type = using type =
typename if_then_else<is_instance_of_char<T, Matcher>::value, T, typename ternary<is_instance_of_matcher<T, Matcher>::value, T,
typename get_matcher<Matcher, Ts...>::type>::type; typename get_matcher<Matcher, Ts...>::type>::type;
}; };
template <template <char...> class Matcher> template <template <char...> class Matcher>
@ -87,21 +65,21 @@ struct get_matcher<Matcher> {
using type = Matcher<'\0'>; using type = Matcher<'\0'>;
}; };
/////////////////////////////////////////////// template <template <char...> class Matcher, typename... Ts>
// TODO add restriction using get_matcher_t = typename get_matcher<Matcher, Ts...>::type;
// TODO add static asserts
template <typename... Ts> template <typename... Ts>
struct setup { struct setup {
using quote = typename get_matcher<quote, Ts...>::type; using quote = get_matcher_t<quote, Ts...>;
using trim = typename get_matcher<trim, Ts...>::type; using trim = get_matcher_t<trim, Ts...>;
using escape = typename get_matcher<escape, Ts...>::type; using escape = get_matcher_t<escape, Ts...>;
}; };
template <typename... Ts> template <typename... Ts>
struct setup<setup<Ts...>> : setup<Ts...> {}; struct setup<setup<Ts...>> : setup<Ts...> {};
///////////////////////////////////////////////////////////////////////////// enum class state { begin, reading, quoting, finished };
enum class State { finished, begin, reading, quoting };
using range = std::pair<const char*, const char*>; using range = std::pair<const char*, const char*>;
using string_range = std::pair<const char*, const char*>; using string_range = std::pair<const char*, const char*>;
@ -109,10 +87,9 @@ using split_input = std::vector<string_range>;
template <typename... Ts> template <typename... Ts>
class splitter { class splitter {
using Setup = setup<Ts...>; using quote = typename setup<Ts...>::quote;
using quote = typename Setup::quote; using trim = typename setup<Ts...>::trim;
using trim = typename Setup::trim; using escape = typename setup<Ts...>::escape;
using escape = typename Setup::escape;
bool match(const char* end_i, char delim) { bool match(const char* end_i, char delim) {
return *end_i == delim; return *end_i == delim;
@ -187,6 +164,12 @@ class splitter {
return {end_i - begin, true}; return {end_i - begin, true};
} }
void push_and_start_next(size_t n) {
output_.emplace_back(begin, curr);
begin = end + n;
state_ = state::begin;
}
public: public:
bool valid() { bool valid() {
return error_.empty(); return error_.empty();
@ -208,21 +191,21 @@ public:
template <typename Delim> template <typename Delim>
std::vector<range>& split_impl(const Delim& delim) { std::vector<range>& split_impl(const Delim& delim) {
state = State::begin; state_ = state::begin;
begin = line; begin = line;
trim_if_enabled(begin); trim_if_enabled(begin);
while (state != State::finished) { while (state_ != state::finished) {
curr = end = begin; curr = end = begin;
switch (state) { switch (state_) {
case (State::begin): case (state::begin):
state_begin(); state_begin();
break; break;
case (State::reading): case (state::reading):
state_reading(delim); state_reading(delim);
break; break;
case (State::quoting): case (state::quoting):
state_quoting(delim); state_quoting(delim);
break; break;
default: default:
@ -237,11 +220,11 @@ public:
if constexpr (quote::enabled) { if constexpr (quote::enabled) {
if (quote::match(*begin)) { if (quote::match(*begin)) {
++begin; ++begin;
state = State::quoting; state_ = state::quoting;
return; return;
} }
} }
state = State::reading; state_ = state::reading;
} }
template <typename Delim> template <typename Delim>
@ -254,7 +237,7 @@ public:
if (width == 0) { if (width == 0) {
// eol // eol
output_.emplace_back(begin, curr); output_.emplace_back(begin, curr);
state = State::finished; state_ = state::finished;
break; break;
} else { } else {
shift(width); shift(width);
@ -294,7 +277,7 @@ public:
// missmatched quote // missmatched quote
// eg: ...,"hel"lo,... -> error // eg: ...,"hel"lo,... -> error
} }
state = State::finished; state_ = state::finished;
break; break;
} }
@ -315,27 +298,21 @@ public:
// eg: ..."hell\0 -> quote not terminated // eg: ..."hell\0 -> quote not terminated
if (*end == '\0') { if (*end == '\0') {
*curr = '\0'; *curr = '\0';
state = State::finished; state_ = state::finished;
break; break;
} }
shift(); shift();
} }
} else { } else {
// set error impossible scenario // set error impossible scenario
state = State::finished; state_ = state::finished;
} }
} }
void push_and_start_next(size_t n) {
output_.emplace_back(begin, curr);
begin = end + n;
state = State::begin;
}
private: private:
std::vector<range> output_; std::vector<range> output_;
std::string error_ = ""; std::string error_ = "";
State state; state state_;
char* curr; char* curr;
char* end; char* end;
char* begin; char* begin;

View File

@ -314,6 +314,23 @@ struct is_instance_of<Template<Ts...>, Template> {
constexpr static bool value = true; constexpr static bool value = true;
}; };
////////////////
// ternary
////////////////
template <bool B, typename T, typename U>
struct ternary;
template <typename T, typename U>
struct ternary<true, T, U> {
using type = T;
};
template <typename T, typename U>
struct ternary<false, T, U> {
using type = U;
};
//////////////// ////////////////
// tuple to struct // tuple to struct
//////////////// ////////////////

View File

@ -1,4 +1,4 @@
CXX=clang++ CXX=g++
CXXFLAGS=-Wall -Wextra -std=c++17 -lstdc++fs CXXFLAGS=-Wall -Wextra -std=c++17 -lstdc++fs
TESTS=test_parser test_converter test_extractions test_splitter TESTS=test_parser test_converter test_extractions test_splitter