From 7640c038f32789e74a17ad8e45e0ce60fa2bec42 Mon Sep 17 00:00:00 2001 From: ado <adnan.abd0124@gmail.com> Date: Tue, 2 Feb 2021 21:43:36 +0100 Subject: [PATCH] move setup to seperate header, add static asserts --- include/ss/setup.hpp | 111 ++++++++++++++++++++++++++++++++++++++++ include/ss/splitter.hpp | 73 +------------------------- 2 files changed, 112 insertions(+), 72 deletions(-) create mode 100644 include/ss/setup.hpp diff --git a/include/ss/setup.hpp b/include/ss/setup.hpp new file mode 100644 index 0000000..4474d96 --- /dev/null +++ b/include/ss/setup.hpp @@ -0,0 +1,111 @@ +#pragma once +#include "type_traits.hpp" +#include <array> + +namespace ss { + +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> +constexpr bool matches_intersect() { + 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; +} + +template <> +class matcher<'\0'> { +public: + constexpr static bool enabled = false; + constexpr static std::array<char, 1> matches{'\0'}; + static bool match(char c) = delete; +}; + +template <char C> +struct quote : matcher<C> {}; + +template <char... Cs> +struct trim : matcher<Cs...> {}; + +template <char... Cs> +struct escape : matcher<Cs...> {}; + +template <typename T, template <char...> class Template> +struct is_instance_of_matcher { + constexpr static bool value = false; +}; + +template <char... Ts, template <char...> class Template> +struct is_instance_of_matcher<Template<Ts...>, Template> { + constexpr static bool value = true; +}; + +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...> { + using type = + typename ternary<is_instance_of_matcher<T, Matcher>::value, T, + typename get_matcher<Matcher, Ts...>::type>::type; +}; + +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; + +template <typename... Ts> +struct setup { + using quote = get_matcher_t<quote, Ts...>; + using trim = get_matcher_t<trim, Ts...>; + using escape = get_matcher_t<escape, Ts...>; + +#define ASSERT_MSG "cannot have the same character in multiple matchers" + static_assert(!matches_intersect<quote, trim>(), ASSERT_MSG); + static_assert(!matches_intersect<trim, escape>(), ASSERT_MSG); + static_assert(!matches_intersect<escape, quote>(), ASSERT_MSG); +#undef ASSERT_MSG +}; + +template <typename... Ts> +struct setup<setup<Ts...>> : setup<Ts...> {}; + +} /* ss */ diff --git a/include/ss/splitter.hpp b/include/ss/splitter.hpp index 8180590..aa35109 100644 --- a/include/ss/splitter.hpp +++ b/include/ss/splitter.hpp @@ -1,4 +1,5 @@ #pragma once +#include "setup.hpp" #include "type_traits.hpp" #include <cstdlib> #include <cstring> @@ -6,78 +7,6 @@ #include <vector> namespace ss { -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); - } - -public: - static bool match(char c) { - return match_impl<Cs...>(c); - } - constexpr static bool enabled = true; -}; - -template <> -class matcher<'\0'> { -public: - constexpr static bool enabled = false; - static bool match(char c) = delete; -}; - -template <char C> -struct quote : matcher<C> {}; - -template <char... Cs> -struct trim : matcher<Cs...> {}; - -template <char... Cs> -struct escape : matcher<Cs...> {}; - -template <typename T, template <char...> class Template> -struct is_instance_of_matcher { - constexpr static bool value = false; -}; - -template <char... Ts, template <char...> class Template> -struct is_instance_of_matcher<Template<Ts...>, Template> { - constexpr static bool value = true; -}; - -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...> { - using type = - typename ternary<is_instance_of_matcher<T, Matcher>::value, T, - typename get_matcher<Matcher, Ts...>::type>::type; -}; - -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; - -// TODO add static asserts -template <typename... Ts> -struct setup { - using quote = get_matcher_t<quote, Ts...>; - using trim = get_matcher_t<trim, Ts...>; - using escape = get_matcher_t<escape, Ts...>; -}; - -template <typename... Ts> -struct setup<setup<Ts...>> : setup<Ts...> {}; using string_range = std::pair<const char*, const char*>; using split_input = std::vector<string_range>;