2021-02-02 21:43:36 +01:00
|
|
|
#pragma once
|
|
|
|
#include "type_traits.hpp"
|
|
|
|
#include <array>
|
|
|
|
|
|
|
|
namespace ss {
|
|
|
|
|
2021-02-14 01:59:06 +01:00
|
|
|
////////////////
|
|
|
|
// matcher
|
|
|
|
////////////////
|
|
|
|
|
2021-02-02 21:43:36 +01:00
|
|
|
template <char... Cs>
|
|
|
|
struct matcher {
|
|
|
|
private:
|
|
|
|
template <char X, char... Xs>
|
|
|
|
static bool match_impl(char c) {
|
|
|
|
if constexpr (sizeof...(Xs) != 0) {
|
|
|
|
return (c == X) || match_impl<Xs...>(c);
|
|
|
|
}
|
|
|
|
return (c == X);
|
|
|
|
}
|
|
|
|
|
|
|
|
constexpr static bool contains_string_terminator() {
|
|
|
|
for (const auto& match : matches) {
|
|
|
|
if (match == '\0') {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
public:
|
|
|
|
static bool match(char c) {
|
|
|
|
return match_impl<Cs...>(c);
|
|
|
|
}
|
|
|
|
|
|
|
|
constexpr static bool enabled = true;
|
|
|
|
constexpr static std::array<char, sizeof...(Cs)> matches{Cs...};
|
|
|
|
static_assert(contains_string_terminator(),
|
|
|
|
"string terminator cannot be used as a match character");
|
|
|
|
};
|
|
|
|
|
|
|
|
template <typename FirstMatcher, typename SecondMatcher>
|
2021-02-14 01:59:06 +01:00
|
|
|
inline constexpr bool matches_intersect() {
|
2021-02-02 21:43:36 +01:00
|
|
|
for (const auto& first_match : FirstMatcher::matches) {
|
|
|
|
for (const auto& second_match : SecondMatcher::matches) {
|
|
|
|
if (first_match != '\0' && first_match == second_match) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2021-02-14 01:59:06 +01:00
|
|
|
template <typename FirstMatcher, typename SecondMatcher1,
|
|
|
|
typename SecondMatcher2>
|
|
|
|
inline constexpr bool matches_intersect_union() {
|
|
|
|
return matches_intersect<FirstMatcher, SecondMatcher1>() ||
|
|
|
|
matches_intersect<FirstMatcher, SecondMatcher2>();
|
|
|
|
}
|
|
|
|
|
2021-02-02 21:43:36 +01:00
|
|
|
template <>
|
|
|
|
class matcher<'\0'> {
|
|
|
|
public:
|
|
|
|
constexpr static bool enabled = false;
|
|
|
|
constexpr static std::array<char, 1> matches{'\0'};
|
|
|
|
static bool match(char c) = delete;
|
|
|
|
};
|
|
|
|
|
2021-02-14 01:59:06 +01:00
|
|
|
////////////////
|
2021-02-20 15:53:18 +01:00
|
|
|
// setup
|
|
|
|
////////////////
|
|
|
|
|
|
|
|
////////////////
|
|
|
|
// matcher
|
2021-02-14 01:59:06 +01:00
|
|
|
////////////////
|
|
|
|
|
2021-02-02 21:43:36 +01:00
|
|
|
template <char C>
|
|
|
|
struct quote : matcher<C> {};
|
|
|
|
|
|
|
|
template <char... Cs>
|
|
|
|
struct trim : matcher<Cs...> {};
|
|
|
|
|
2021-02-14 01:59:06 +01:00
|
|
|
template <char... Cs>
|
|
|
|
struct trim_left : matcher<Cs...> {};
|
|
|
|
|
|
|
|
template <char... Cs>
|
|
|
|
struct trim_right : matcher<Cs...> {};
|
|
|
|
|
2021-02-02 21:43:36 +01:00
|
|
|
template <char... Cs>
|
|
|
|
struct escape : matcher<Cs...> {};
|
|
|
|
|
|
|
|
template <typename T, template <char...> class Template>
|
2021-02-14 01:59:06 +01:00
|
|
|
struct is_instance_of_matcher : std::false_type {};
|
2021-02-02 21:43:36 +01:00
|
|
|
|
|
|
|
template <char... Ts, template <char...> class Template>
|
2021-02-14 01:59:06 +01:00
|
|
|
struct is_instance_of_matcher<Template<Ts...>, Template> : std::true_type {};
|
|
|
|
|
|
|
|
template <typename T, template <char...> class Template>
|
|
|
|
using is_instance_of_matcher_t =
|
|
|
|
typename is_instance_of_matcher<T, Template>::type;
|
2021-02-02 21:43:36 +01:00
|
|
|
|
|
|
|
template <template <char...> class Matcher, typename... Ts>
|
|
|
|
struct get_matcher;
|
|
|
|
|
|
|
|
template <template <char...> class Matcher, typename T, typename... Ts>
|
|
|
|
struct get_matcher<Matcher, T, Ts...> {
|
2021-02-14 01:59:06 +01:00
|
|
|
|
|
|
|
template <typename U>
|
|
|
|
struct is_matcher : is_instance_of_matcher<U, Matcher> {};
|
|
|
|
|
|
|
|
static_assert(count_v<is_matcher, T, Ts...> <= 1,
|
|
|
|
"the same matcher is cannot"
|
|
|
|
"be defined multiple times");
|
|
|
|
using type = ternary_t<is_matcher<T>::value, T,
|
2021-02-13 01:14:25 +01:00
|
|
|
typename get_matcher<Matcher, Ts...>::type>;
|
2021-02-02 21:43:36 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
template <template <char...> class Matcher>
|
|
|
|
struct get_matcher<Matcher> {
|
|
|
|
using type = Matcher<'\0'>;
|
|
|
|
};
|
|
|
|
|
|
|
|
template <template <char...> class Matcher, typename... Ts>
|
|
|
|
using get_matcher_t = typename get_matcher<Matcher, Ts...>::type;
|
|
|
|
|
2021-02-20 15:53:18 +01:00
|
|
|
////////////////
|
|
|
|
// multiline
|
|
|
|
////////////////
|
|
|
|
|
|
|
|
template <size_t S, bool B = true>
|
|
|
|
struct multiline_restricted {
|
|
|
|
constexpr static auto size = S;
|
|
|
|
constexpr static auto enabled = B;
|
|
|
|
};
|
|
|
|
|
|
|
|
using multiline = multiline_restricted<0>;
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
struct is_instance_of_multiline : std::false_type {};
|
|
|
|
|
|
|
|
template <size_t S, bool B>
|
|
|
|
struct is_instance_of_multiline<multiline_restricted<S, B>> : std::true_type {};
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
using is_instance_of_multiline_t = typename is_instance_of_multiline<T>::type;
|
|
|
|
|
|
|
|
template <typename... Ts>
|
|
|
|
struct get_multiline;
|
|
|
|
|
|
|
|
template <typename T, typename... Ts>
|
|
|
|
struct get_multiline<T, Ts...> {
|
|
|
|
using type = ternary_t<is_instance_of_multiline<T>::value, T,
|
|
|
|
typename get_multiline<Ts...>::type>;
|
|
|
|
};
|
|
|
|
|
|
|
|
template <>
|
|
|
|
struct get_multiline<> {
|
|
|
|
using type = multiline_restricted<0, false>;
|
|
|
|
};
|
|
|
|
|
|
|
|
template <typename... Ts>
|
|
|
|
using get_multiline_t = typename get_multiline<Ts...>::type;
|
|
|
|
|
|
|
|
////////////////
|
|
|
|
// string_error
|
|
|
|
////////////////
|
|
|
|
|
|
|
|
class string_error;
|
|
|
|
|
2022-03-27 21:04:02 +02:00
|
|
|
////////////////
|
|
|
|
// ignore_header
|
|
|
|
////////////////
|
|
|
|
|
|
|
|
class ignore_header;
|
|
|
|
|
2022-03-28 19:11:41 +02:00
|
|
|
////////////////
|
|
|
|
// ignore_empty
|
|
|
|
////////////////
|
|
|
|
|
|
|
|
class ignore_empty;
|
|
|
|
|
2021-02-20 15:53:18 +01:00
|
|
|
////////////////
|
|
|
|
// setup implementation
|
|
|
|
////////////////
|
|
|
|
|
2021-02-02 21:43:36 +01:00
|
|
|
template <typename... Ts>
|
|
|
|
struct setup {
|
2021-02-13 01:14:25 +01:00
|
|
|
private:
|
|
|
|
template <typename T>
|
2021-02-14 01:59:06 +01:00
|
|
|
struct is_matcher
|
|
|
|
: std::disjunction<is_instance_of_matcher_t<T, quote>,
|
|
|
|
is_instance_of_matcher_t<T, escape>,
|
|
|
|
is_instance_of_matcher_t<T, trim>,
|
|
|
|
is_instance_of_matcher_t<T, trim_left>,
|
|
|
|
is_instance_of_matcher_t<T, trim_right>> {};
|
2021-02-13 01:14:25 +01:00
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
struct is_string_error : std::is_same<T, string_error> {};
|
|
|
|
|
2022-03-27 21:04:02 +02:00
|
|
|
template <typename T>
|
|
|
|
struct is_ignore_header : std::is_same<T, ignore_header> {};
|
|
|
|
|
2022-03-28 19:11:41 +02:00
|
|
|
template <typename T>
|
|
|
|
struct is_ignore_empty : std::is_same<T, ignore_empty> {};
|
|
|
|
|
2021-02-14 01:59:06 +01:00
|
|
|
constexpr static auto count_matcher = count_v<is_matcher, Ts...>;
|
2022-03-28 19:11:41 +02:00
|
|
|
|
2021-02-20 15:53:18 +01:00
|
|
|
constexpr static auto count_multiline =
|
|
|
|
count_v<is_instance_of_multiline, Ts...>;
|
2022-03-28 19:11:41 +02:00
|
|
|
|
2021-02-14 01:59:06 +01:00
|
|
|
constexpr static auto count_string_error = count_v<is_string_error, Ts...>;
|
2022-03-28 19:11:41 +02:00
|
|
|
|
2022-03-27 21:04:02 +02:00
|
|
|
constexpr static auto count_ignore_header =
|
|
|
|
count_v<is_ignore_header, Ts...>;
|
2021-02-14 01:59:06 +01:00
|
|
|
|
2022-03-28 19:11:41 +02:00
|
|
|
constexpr static auto count_ignore_empty = count_v<is_ignore_empty, Ts...>;
|
|
|
|
|
2021-02-14 01:59:06 +01:00
|
|
|
constexpr static auto number_of_valid_setup_types =
|
2022-03-27 21:04:02 +02:00
|
|
|
count_matcher + count_multiline + count_string_error +
|
2022-03-28 19:11:41 +02:00
|
|
|
count_ignore_header + count_ignore_empty;
|
2021-02-14 01:59:06 +01:00
|
|
|
|
|
|
|
using trim_left_only = get_matcher_t<trim_left, Ts...>;
|
|
|
|
using trim_right_only = get_matcher_t<trim_right, Ts...>;
|
|
|
|
using trim_all = get_matcher_t<trim, Ts...>;
|
2021-02-13 01:14:25 +01:00
|
|
|
|
|
|
|
public:
|
2021-02-02 21:43:36 +01:00
|
|
|
using quote = get_matcher_t<quote, Ts...>;
|
|
|
|
using escape = get_matcher_t<escape, Ts...>;
|
2021-02-14 01:59:06 +01:00
|
|
|
|
|
|
|
using trim_left = ternary_t<trim_all::enabled, trim_all, trim_left_only>;
|
|
|
|
using trim_right = ternary_t<trim_all::enabled, trim_all, trim_right_only>;
|
|
|
|
|
2021-02-20 15:53:18 +01:00
|
|
|
using multiline = get_multiline_t<Ts...>;
|
2021-02-13 01:14:25 +01:00
|
|
|
constexpr static bool string_error = (count_string_error == 1);
|
2022-03-27 21:04:02 +02:00
|
|
|
constexpr static bool ignore_header = (count_ignore_header == 1);
|
2022-03-28 19:11:41 +02:00
|
|
|
constexpr static bool ignore_empty = (count_ignore_empty == 1);
|
2021-02-13 01:14:25 +01:00
|
|
|
|
2021-02-14 01:59:06 +01:00
|
|
|
private:
|
|
|
|
#define ASSERT_MSG "cannot have the same match character in multiple matchers"
|
|
|
|
static_assert(!matches_intersect<escape, quote>(), ASSERT_MSG);
|
|
|
|
|
|
|
|
constexpr static auto quote_trim_intersect =
|
|
|
|
matches_intersect_union<quote, trim_left, trim_right>();
|
|
|
|
static_assert(!quote_trim_intersect, ASSERT_MSG);
|
|
|
|
|
|
|
|
constexpr static auto escape_trim_intersect =
|
|
|
|
matches_intersect_union<escape, trim_left, trim_right>();
|
|
|
|
static_assert(!escape_trim_intersect, ASSERT_MSG);
|
|
|
|
|
|
|
|
#undef ASSERT_MSG
|
|
|
|
|
2021-02-13 01:14:25 +01:00
|
|
|
static_assert(
|
2021-02-20 15:53:18 +01:00
|
|
|
!multiline::enabled ||
|
|
|
|
(multiline::enabled && (quote::enabled || escape::enabled)),
|
2021-02-13 01:14:25 +01:00
|
|
|
"to enable multiline either quote or escape need to be enabled");
|
2021-02-02 21:43:36 +01:00
|
|
|
|
2021-02-14 01:59:06 +01:00
|
|
|
static_assert(!(trim_all::enabled && trim_left_only::enabled) &&
|
|
|
|
!(trim_all::enabled && trim_right_only::enabled),
|
|
|
|
"ambiguous trim setup");
|
|
|
|
|
|
|
|
static_assert(count_multiline <= 1, "mutliline defined multiple times");
|
|
|
|
static_assert(count_string_error <= 1,
|
|
|
|
"string_error defined multiple times");
|
|
|
|
|
|
|
|
static_assert(number_of_valid_setup_types == sizeof...(Ts),
|
|
|
|
"one or multiple invalid setup parameters defined");
|
2021-02-02 21:43:36 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
template <typename... Ts>
|
|
|
|
struct setup<setup<Ts...>> : setup<Ts...> {};
|
|
|
|
|
|
|
|
} /* ss */
|