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,
|
2024-02-19 00:16:22 +01:00
|
|
|
"the same matcher cannot "
|
2021-02-14 01:59:06 +01:00
|
|
|
"be defined multiple times");
|
2023-02-12 12:45:49 +01:00
|
|
|
using type = std::conditional_t<is_matcher<T>::value, T,
|
2023-07-10 02:39:24 +02: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...> {
|
2023-02-12 12:45:49 +01:00
|
|
|
using type = std::conditional_t<is_instance_of_multiline<T>::value, T,
|
2023-07-10 02:39:24 +02:00
|
|
|
typename get_multiline<Ts...>::type>;
|
2021-02-20 15:53:18 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
template <>
|
|
|
|
struct get_multiline<> {
|
|
|
|
using type = multiline_restricted<0, false>;
|
|
|
|
};
|
|
|
|
|
|
|
|
template <typename... Ts>
|
|
|
|
using get_multiline_t = typename get_multiline<Ts...>::type;
|
|
|
|
|
|
|
|
////////////////
|
|
|
|
// string_error
|
|
|
|
////////////////
|
|
|
|
|
2024-02-25 02:06:48 +01:00
|
|
|
class string_error {};
|
2021-02-20 15:53:18 +01:00
|
|
|
|
2022-03-27 21:04:02 +02:00
|
|
|
////////////////
|
|
|
|
// ignore_header
|
|
|
|
////////////////
|
|
|
|
|
2024-02-25 02:06:48 +01:00
|
|
|
class ignore_header {};
|
2022-03-27 21:04:02 +02:00
|
|
|
|
2022-03-28 19:11:41 +02:00
|
|
|
////////////////
|
|
|
|
// ignore_empty
|
|
|
|
////////////////
|
|
|
|
|
2024-02-25 02:06:48 +01:00
|
|
|
class ignore_empty {};
|
2022-03-28 19:11:41 +02:00
|
|
|
|
2023-06-29 23:41:03 +02:00
|
|
|
////////////////
|
|
|
|
// throw_on_error
|
|
|
|
////////////////
|
|
|
|
|
2024-02-25 02:06:48 +01:00
|
|
|
class throw_on_error {};
|
2023-06-29 23:41:03 +02:00
|
|
|
|
2021-02-20 15:53:18 +01:00
|
|
|
////////////////
|
|
|
|
// setup implementation
|
|
|
|
////////////////
|
|
|
|
|
2023-06-29 23:41:03 +02:00
|
|
|
template <typename... Options>
|
2021-02-02 21:43:36 +01:00
|
|
|
struct setup {
|
2021-02-13 01:14:25 +01:00
|
|
|
private:
|
2023-06-29 23:41:03 +02:00
|
|
|
template <typename Option>
|
2021-02-14 01:59:06 +01:00
|
|
|
struct is_matcher
|
2023-06-29 23:41:03 +02:00
|
|
|
: std::disjunction<is_instance_of_matcher_t<Option, quote>,
|
|
|
|
is_instance_of_matcher_t<Option, escape>,
|
|
|
|
is_instance_of_matcher_t<Option, trim>,
|
|
|
|
is_instance_of_matcher_t<Option, trim_left>,
|
|
|
|
is_instance_of_matcher_t<Option, 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> {};
|
|
|
|
|
2023-06-29 23:41:03 +02:00
|
|
|
template <typename T>
|
|
|
|
struct is_throw_on_error : std::is_same<T, throw_on_error> {};
|
|
|
|
|
|
|
|
constexpr static auto count_matcher = count_v<is_matcher, Options...>;
|
2022-03-28 19:11:41 +02:00
|
|
|
|
2021-02-20 15:53:18 +01:00
|
|
|
constexpr static auto count_multiline =
|
2023-06-29 23:41:03 +02:00
|
|
|
count_v<is_instance_of_multiline, Options...>;
|
2022-03-28 19:11:41 +02:00
|
|
|
|
2023-07-10 02:39:24 +02:00
|
|
|
constexpr static auto count_string_error =
|
|
|
|
count_v<is_string_error, Options...>;
|
2022-03-28 19:11:41 +02:00
|
|
|
|
2022-03-27 21:04:02 +02:00
|
|
|
constexpr static auto count_ignore_header =
|
2023-06-29 23:41:03 +02:00
|
|
|
count_v<is_ignore_header, Options...>;
|
2021-02-14 01:59:06 +01:00
|
|
|
|
2023-06-29 23:41:03 +02:00
|
|
|
constexpr static auto count_throw_on_error =
|
|
|
|
count_v<is_throw_on_error, Options...>;
|
|
|
|
|
2023-07-10 02:39:24 +02:00
|
|
|
constexpr static auto count_ignore_empty =
|
|
|
|
count_v<is_ignore_empty, Options...>;
|
2022-03-28 19:11:41 +02:00
|
|
|
|
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 +
|
2023-06-29 23:41:03 +02:00
|
|
|
count_ignore_header + count_ignore_empty + count_throw_on_error;
|
2021-02-14 01:59:06 +01:00
|
|
|
|
2023-06-29 23:41:03 +02:00
|
|
|
using trim_left_only = get_matcher_t<trim_left, Options...>;
|
|
|
|
using trim_right_only = get_matcher_t<trim_right, Options...>;
|
|
|
|
using trim_all = get_matcher_t<trim, Options...>;
|
2021-02-13 01:14:25 +01:00
|
|
|
|
|
|
|
public:
|
2023-06-29 23:41:03 +02:00
|
|
|
using quote = get_matcher_t<quote, Options...>;
|
|
|
|
using escape = get_matcher_t<escape, Options...>;
|
2021-02-14 01:59:06 +01:00
|
|
|
|
2023-02-12 12:45:49 +01:00
|
|
|
using trim_left =
|
|
|
|
std::conditional_t<trim_all::enabled, trim_all, trim_left_only>;
|
|
|
|
using trim_right =
|
|
|
|
std::conditional_t<trim_all::enabled, trim_all, trim_right_only>;
|
2021-02-14 01:59:06 +01:00
|
|
|
|
2023-06-29 23:41:03 +02:00
|
|
|
using multiline = get_multiline_t<Options...>;
|
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);
|
2023-06-29 23:41:03 +02:00
|
|
|
constexpr static bool throw_on_error = (count_throw_on_error == 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)),
|
2023-07-28 00:17:22 +02:00
|
|
|
"to enable multiline either quote or escape needs 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");
|
2023-07-10 02:39:24 +02:00
|
|
|
|
2021-02-14 01:59:06 +01:00
|
|
|
static_assert(count_string_error <= 1,
|
|
|
|
"string_error defined multiple times");
|
|
|
|
|
2023-07-10 02:39:24 +02:00
|
|
|
static_assert(count_throw_on_error <= 1,
|
|
|
|
"throw_on_error defined multiple times");
|
|
|
|
|
|
|
|
static_assert(count_throw_on_error + count_string_error <= 1,
|
|
|
|
"cannot define both throw_on_error and string_error");
|
|
|
|
|
2023-06-29 23:41:03 +02:00
|
|
|
static_assert(number_of_valid_setup_types == sizeof...(Options),
|
2021-02-14 01:59:06 +01:00
|
|
|
"one or multiple invalid setup parameters defined");
|
2021-02-02 21:43:36 +01:00
|
|
|
};
|
|
|
|
|
2023-06-29 23:41:03 +02:00
|
|
|
template <typename... Options>
|
|
|
|
struct setup<setup<Options...>> : setup<Options...> {};
|
2021-02-02 21:43:36 +01:00
|
|
|
|
Updated and added new functions related to headers, resolved ODR issues, resolved clang-tidy warnings (#50)
* Bugfix/odr violations (#47)
* Make common non-member functions inline, remove unreachable line from get_line_buffer
* [skip ci] Fix namespace comments
* Resolve clang-tidy warnings (#48)
* Resolve clang-tidy warnings, update single_header_generator.py
* Update single header test, resolve additional clang-tidy warnings
* Add header and raw_header methods, update header usage methods error handling, write new and update existing unit tests
* Update parser error messages, fix parser tests
* Add [[nodiscard]] where fitting, update unit tests (#49)
* Add const where fitting, make splitter class members private, add #pragma once to ssp.hpp
* Modify header parsing for empty headers, update old and add new tests for header parsing
* Enable the parser to accept a header with one empty field, update unit tests
* Fix test CMakeLists.txt typo
2024-03-14 17:22:57 +01:00
|
|
|
template <typename... Options>
|
|
|
|
struct setup<std::tuple<Options...>> : setup<Options...> {};
|
|
|
|
|
|
|
|
} /* namespace ss */
|