mirror of
				https://github.com/red0124/ssp.git
				synced 2025-11-04 14:46:45 +01:00 
			
		
		
		
	add trim_left and trim_right, add setup static asserts, update type_traits, refactor some code, add unit tests
This commit is contained in:
		
							parent
							
								
									ea42948c42
								
							
						
					
					
						commit
						2985027505
					
				
							
								
								
									
										19
									
								
								include/ss/common.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								include/ss/common.hpp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,19 @@
 | 
				
			|||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					#include <vector>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace ss {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct none {};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using string_range = std::pair<const char*, const char*>;
 | 
				
			||||||
 | 
					using split_data = std::vector<string_range>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					constexpr inline auto default_delimiter = ",";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template <bool StringError>
 | 
				
			||||||
 | 
					inline void assert_string_error_defined() {
 | 
				
			||||||
 | 
					    static_assert(StringError,
 | 
				
			||||||
 | 
					                  "'string_error' needs to be enabled to use 'error_msg'");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					} /* ss */
 | 
				
			||||||
@ -40,19 +40,13 @@ template <typename T>
 | 
				
			|||||||
using no_validator_t = typename no_validator<T>::type;
 | 
					using no_validator_t = typename no_validator<T>::type;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template <typename... Ts>
 | 
					template <typename... Ts>
 | 
				
			||||||
struct no_validator_tup {
 | 
					struct no_validator_tup : apply_trait<no_validator, std::tuple<Ts...>> {};
 | 
				
			||||||
    using type = typename apply_trait<no_validator, std::tuple<Ts...>>::type;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
template <typename... Ts>
 | 
					template <typename... Ts>
 | 
				
			||||||
struct no_validator_tup<std::tuple<Ts...>> {
 | 
					struct no_validator_tup<std::tuple<Ts...>> : no_validator_tup<Ts...> {};
 | 
				
			||||||
    using type = typename no_validator_tup<Ts...>::type;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
template <typename T>
 | 
					template <typename T>
 | 
				
			||||||
struct no_validator_tup<std::tuple<T>> {
 | 
					struct no_validator_tup<std::tuple<T>> : no_validator<T> {};
 | 
				
			||||||
    using type = no_validator_t<T>;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
template <typename... Ts>
 | 
					template <typename... Ts>
 | 
				
			||||||
using no_validator_tup_t = typename no_validator_tup<Ts...>::type;
 | 
					using no_validator_tup_t = typename no_validator_tup<Ts...>::type;
 | 
				
			||||||
@ -62,10 +56,7 @@ using no_validator_tup_t = typename no_validator_tup<Ts...>::type;
 | 
				
			|||||||
////////////////
 | 
					////////////////
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template <typename... Ts>
 | 
					template <typename... Ts>
 | 
				
			||||||
struct no_void_tup {
 | 
					struct no_void_tup : filter_not<std::is_void, no_validator_tup_t<Ts...>> {};
 | 
				
			||||||
    using type =
 | 
					 | 
				
			||||||
        typename filter_not<std::is_void, no_validator_tup_t<Ts...>>::type;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
template <typename... Ts>
 | 
					template <typename... Ts>
 | 
				
			||||||
using no_void_tup_t = filter_not_t<std::is_void, Ts...>;
 | 
					using no_void_tup_t = filter_not_t<std::is_void, Ts...>;
 | 
				
			||||||
@ -76,14 +67,11 @@ using no_void_tup_t = filter_not_t<std::is_void, Ts...>;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// replace 'validators' and remove void from tuple
 | 
					// replace 'validators' and remove void from tuple
 | 
				
			||||||
template <typename... Ts>
 | 
					template <typename... Ts>
 | 
				
			||||||
struct no_void_validator_tup {
 | 
					struct no_void_validator_tup : no_validator_tup<no_void_tup_t<Ts...>> {};
 | 
				
			||||||
    using type = no_validator_tup_t<no_void_tup_t<Ts...>>;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
template <typename... Ts>
 | 
					template <typename... Ts>
 | 
				
			||||||
struct no_void_validator_tup<std::tuple<Ts...>> {
 | 
					struct no_void_validator_tup<std::tuple<Ts...>>
 | 
				
			||||||
    using type = no_validator_tup_t<no_void_tup_t<Ts...>>;
 | 
					    : no_validator_tup<no_void_tup_t<Ts...>> {};
 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
template <typename... Ts>
 | 
					template <typename... Ts>
 | 
				
			||||||
using no_void_validator_tup_t = typename no_void_validator_tup<Ts...>::type;
 | 
					using no_void_validator_tup_t = typename no_void_validator_tup<Ts...>::type;
 | 
				
			||||||
@ -131,12 +119,12 @@ public:
 | 
				
			|||||||
    no_void_validator_tup_t<Ts...> convert(
 | 
					    no_void_validator_tup_t<Ts...> convert(
 | 
				
			||||||
        line_ptr_type line, const std::string& delim = default_delimiter) {
 | 
					        line_ptr_type line, const std::string& delim = default_delimiter) {
 | 
				
			||||||
        split(line, delim);
 | 
					        split(line, delim);
 | 
				
			||||||
        return convert<Ts...>(splitter_.split_input_);
 | 
					        return convert<Ts...>(splitter_.split_data_);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // parses already split line, returns 'T' object with extracted values
 | 
					    // parses already split line, returns 'T' object with extracted values
 | 
				
			||||||
    template <typename T, typename... Ts>
 | 
					    template <typename T, typename... Ts>
 | 
				
			||||||
    T convert_object(const split_input& elems) {
 | 
					    T convert_object(const split_data& elems) {
 | 
				
			||||||
        return to_object<T>(convert<Ts...>(elems));
 | 
					        return to_object<T>(convert<Ts...>(elems));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -151,17 +139,12 @@ public:
 | 
				
			|||||||
    // one argument is given which is a class which has a tied
 | 
					    // one argument is given which is a class which has a tied
 | 
				
			||||||
    // method which returns a tuple, returns that type
 | 
					    // method which returns a tuple, returns that type
 | 
				
			||||||
    template <typename T, typename... Ts>
 | 
					    template <typename T, typename... Ts>
 | 
				
			||||||
    no_void_validator_tup_t<T, Ts...> convert(const split_input& elems) {
 | 
					    no_void_validator_tup_t<T, Ts...> convert(const split_data& elems) {
 | 
				
			||||||
        if constexpr (sizeof...(Ts) == 0 &&
 | 
					        if constexpr (sizeof...(Ts) == 0 && is_instance_of_v<std::tuple, T>) {
 | 
				
			||||||
                      is_instance_of<T, std::tuple>::value) {
 | 
					 | 
				
			||||||
            return convert_impl(elems, static_cast<T*>(nullptr));
 | 
					            return convert_impl(elems, static_cast<T*>(nullptr));
 | 
				
			||||||
 | 
					 | 
				
			||||||
        } else if constexpr (tied_class_v<T, Ts...>) {
 | 
					        } else if constexpr (tied_class_v<T, Ts...>) {
 | 
				
			||||||
            using arg_ref_tuple =
 | 
					            using arg_ref_tuple = std::result_of_t<decltype (&T::tied)(T)>;
 | 
				
			||||||
                typename std::result_of_t<decltype (&T::tied)(T)>;
 | 
					            using arg_tuple = apply_trait_t<std::decay, arg_ref_tuple>;
 | 
				
			||||||
 | 
					 | 
				
			||||||
            using arg_tuple =
 | 
					 | 
				
			||||||
                typename apply_trait<std::decay, arg_ref_tuple>::type;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            return to_object<T>(
 | 
					            return to_object<T>(
 | 
				
			||||||
                convert_impl(elems, static_cast<arg_tuple*>(nullptr)));
 | 
					                convert_impl(elems, static_cast<arg_tuple*>(nullptr)));
 | 
				
			||||||
@ -173,7 +156,7 @@ public:
 | 
				
			|||||||
    // same as above, but uses cached split line
 | 
					    // same as above, but uses cached split line
 | 
				
			||||||
    template <typename T, typename... Ts>
 | 
					    template <typename T, typename... Ts>
 | 
				
			||||||
    no_void_validator_tup_t<T, Ts...> convert() {
 | 
					    no_void_validator_tup_t<T, Ts...> convert() {
 | 
				
			||||||
        return convert<T, Ts...>(splitter_.split_input_);
 | 
					        return convert<T, Ts...>(splitter_.split_data_);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    bool valid() const {
 | 
					    bool valid() const {
 | 
				
			||||||
@ -185,8 +168,7 @@ public:
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const std::string& error_msg() const {
 | 
					    const std::string& error_msg() const {
 | 
				
			||||||
        static_assert(string_error,
 | 
					        assert_string_error_defined<string_error>();
 | 
				
			||||||
                      "'string_error' needs to be enabled to use 'error_msg'");
 | 
					 | 
				
			||||||
        return error_;
 | 
					        return error_;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -196,11 +178,11 @@ public:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    // 'splits' string by given delimiter, returns vector of pairs which
 | 
					    // 'splits' string by given delimiter, returns vector of pairs which
 | 
				
			||||||
    // contain the beginnings and the ends of each column of the string
 | 
					    // contain the beginnings and the ends of each column of the string
 | 
				
			||||||
    const split_input& split(line_ptr_type line,
 | 
					    const split_data& split(line_ptr_type line,
 | 
				
			||||||
                            const std::string& delim = default_delimiter) {
 | 
					                            const std::string& delim = default_delimiter) {
 | 
				
			||||||
        splitter_.split_input_.clear();
 | 
					        splitter_.split_data_.clear();
 | 
				
			||||||
        if (line[0] == '\0') {
 | 
					        if (line[0] == '\0') {
 | 
				
			||||||
            return splitter_.split_input_;
 | 
					            return splitter_.split_data_;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return splitter_.split(line, delim);
 | 
					        return splitter_.split(line, delim);
 | 
				
			||||||
@ -211,7 +193,7 @@ private:
 | 
				
			|||||||
    // resplit
 | 
					    // resplit
 | 
				
			||||||
    ////////////////
 | 
					    ////////////////
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const split_input& resplit(line_ptr_type new_line, ssize_t new_size,
 | 
					    const split_data& resplit(line_ptr_type new_line, ssize_t new_size,
 | 
				
			||||||
                              const std::string& delim = default_delimiter) {
 | 
					                              const std::string& delim = default_delimiter) {
 | 
				
			||||||
        return splitter_.resplit(new_line, new_size, delim);
 | 
					        return splitter_.resplit(new_line, new_size, delim);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -285,7 +267,7 @@ private:
 | 
				
			|||||||
    ////////////////
 | 
					    ////////////////
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    template <typename... Ts>
 | 
					    template <typename... Ts>
 | 
				
			||||||
    no_void_validator_tup_t<Ts...> convert_impl(const split_input& elems) {
 | 
					    no_void_validator_tup_t<Ts...> convert_impl(const split_data& elems) {
 | 
				
			||||||
        clear_error();
 | 
					        clear_error();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (!splitter_.valid()) {
 | 
					        if (!splitter_.valid()) {
 | 
				
			||||||
@ -306,7 +288,7 @@ private:
 | 
				
			|||||||
    // do not know how to specialize by return type :(
 | 
					    // do not know how to specialize by return type :(
 | 
				
			||||||
    template <typename... Ts>
 | 
					    template <typename... Ts>
 | 
				
			||||||
    no_void_validator_tup_t<std::tuple<Ts...>> convert_impl(
 | 
					    no_void_validator_tup_t<std::tuple<Ts...>> convert_impl(
 | 
				
			||||||
        const split_input& elems, const std::tuple<Ts...>*) {
 | 
					        const split_data& elems, const std::tuple<Ts...>*) {
 | 
				
			||||||
        return convert_impl<Ts...>(elems);
 | 
					        return convert_impl<Ts...>(elems);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -345,11 +327,11 @@ private:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    template <size_t ArgN, size_t TupN, typename... Ts>
 | 
					    template <size_t ArgN, size_t TupN, typename... Ts>
 | 
				
			||||||
    void extract_multiple(no_void_validator_tup_t<Ts...>& tup,
 | 
					    void extract_multiple(no_void_validator_tup_t<Ts...>& tup,
 | 
				
			||||||
                          const split_input& elems) {
 | 
					                          const split_data& elems) {
 | 
				
			||||||
        using elem_t = std::tuple_element_t<ArgN, std::tuple<Ts...>>;
 | 
					        using elem_t = std::tuple_element_t<ArgN, std::tuple<Ts...>>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        constexpr bool not_void = !std::is_void_v<elem_t>;
 | 
					        constexpr bool not_void = !std::is_void_v<elem_t>;
 | 
				
			||||||
        constexpr bool one_element = count_not<std::is_void, Ts...>::size == 1;
 | 
					        constexpr bool one_element = count_not_v<std::is_void, Ts...> == 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if constexpr (not_void) {
 | 
					        if constexpr (not_void) {
 | 
				
			||||||
            if constexpr (one_element) {
 | 
					            if constexpr (one_element) {
 | 
				
			||||||
@ -367,8 +349,8 @@ private:
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    template <typename... Ts>
 | 
					    template <typename... Ts>
 | 
				
			||||||
    no_void_validator_tup_t<Ts...> extract_tuple(const split_input& elems) {
 | 
					    no_void_validator_tup_t<Ts...> extract_tuple(const split_data& elems) {
 | 
				
			||||||
        static_assert(!all_of<std::is_void, Ts...>::value,
 | 
					        static_assert(!all_of_v<std::is_void, Ts...>,
 | 
				
			||||||
                      "at least one parameter must be non void");
 | 
					                      "at least one parameter must be non void");
 | 
				
			||||||
        no_void_validator_tup_t<Ts...> ret{};
 | 
					        no_void_validator_tup_t<Ts...> ret{};
 | 
				
			||||||
        extract_multiple<0, 0, Ts...>(ret, elems);
 | 
					        extract_multiple<0, 0, Ts...>(ret, elems);
 | 
				
			||||||
@ -379,7 +361,7 @@ private:
 | 
				
			|||||||
    // members
 | 
					    // members
 | 
				
			||||||
    ////////////////
 | 
					    ////////////////
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    error_type error_;
 | 
					    error_type error_{};
 | 
				
			||||||
    splitter<Matchers...> splitter_;
 | 
					    splitter<Matchers...> splitter_;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    template <typename...>
 | 
					    template <typename...>
 | 
				
			||||||
 | 
				
			|||||||
@ -225,8 +225,8 @@ struct unsupported_type {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
template <typename T>
 | 
					template <typename T>
 | 
				
			||||||
std::enable_if_t<!std::is_integral_v<T> && !std::is_floating_point_v<T> &&
 | 
					std::enable_if_t<!std::is_integral_v<T> && !std::is_floating_point_v<T> &&
 | 
				
			||||||
                     !is_instance_of<T, std::optional>::value &&
 | 
					                     !is_instance_of_v<std::optional, T> &&
 | 
				
			||||||
                     !is_instance_of<T, std::variant>::value,
 | 
					                     !is_instance_of_v<std::variant, T>,
 | 
				
			||||||
                 bool>
 | 
					                 bool>
 | 
				
			||||||
extract(const char*, const char*, T&) {
 | 
					extract(const char*, const char*, T&) {
 | 
				
			||||||
    static_assert(error::unsupported_type<T>::value,
 | 
					    static_assert(error::unsupported_type<T>::value,
 | 
				
			||||||
@ -246,7 +246,7 @@ extract(const char* begin, const char* end, T& value) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template <typename T>
 | 
					template <typename T>
 | 
				
			||||||
std::enable_if_t<is_instance_of<T, std::optional>::value, bool> extract(
 | 
					std::enable_if_t<is_instance_of_v<std::optional, T>, bool> extract(
 | 
				
			||||||
    const char* begin, const char* end, T& value) {
 | 
					    const char* begin, const char* end, T& value) {
 | 
				
			||||||
    typename T::value_type raw_value;
 | 
					    typename T::value_type raw_value;
 | 
				
			||||||
    if (extract(begin, end, raw_value)) {
 | 
					    if (extract(begin, end, raw_value)) {
 | 
				
			||||||
@ -271,7 +271,7 @@ bool extract_variant(const char* begin, const char* end, T& value) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template <typename T>
 | 
					template <typename T>
 | 
				
			||||||
std::enable_if_t<is_instance_of<T, std::variant>::value, bool> extract(
 | 
					std::enable_if_t<is_instance_of_v<std::variant, T>, bool> extract(
 | 
				
			||||||
    const char* begin, const char* end, T& value) {
 | 
					    const char* begin, const char* end, T& value) {
 | 
				
			||||||
    return extract_variant<T, 0>(begin, end, value);
 | 
					    return extract_variant<T, 0>(begin, end, value);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -13,8 +13,6 @@ namespace ss {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
template <typename... Matchers>
 | 
					template <typename... Matchers>
 | 
				
			||||||
class parser {
 | 
					class parser {
 | 
				
			||||||
    struct none {};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    constexpr static auto string_error = setup<Matchers...>::string_error;
 | 
					    constexpr static auto string_error = setup<Matchers...>::string_error;
 | 
				
			||||||
    constexpr static auto multiline = setup<Matchers...>::multiline;
 | 
					    constexpr static auto multiline = setup<Matchers...>::multiline;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -48,8 +46,7 @@ public:
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const std::string& error_msg() const {
 | 
					    const std::string& error_msg() const {
 | 
				
			||||||
        static_assert(string_error,
 | 
					        assert_string_error_defined<string_error>();
 | 
				
			||||||
                      "'string_error' needs to be enabled to use 'error_msg'");
 | 
					 | 
				
			||||||
        return error_;
 | 
					        return error_;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -157,11 +154,13 @@ public:
 | 
				
			|||||||
                if (!parser_.valid()) {
 | 
					                if (!parser_.valid()) {
 | 
				
			||||||
                    return;
 | 
					                    return;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                if constexpr (!std::is_same_v<U, decltype(tuple_output)>) {
 | 
					                if constexpr (!std::is_same_v<U, decltype(tuple_output)>) {
 | 
				
			||||||
                    value = to_object<U>(std::move(tuple_output));
 | 
					                    value = to_object<U>(std::move(tuple_output));
 | 
				
			||||||
                } else {
 | 
					                } else {
 | 
				
			||||||
                    value = std::move(tuple_output);
 | 
					                    value = std::move(tuple_output);
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                parser_.try_invoke(*value, std::forward<Fun>(fun));
 | 
					                parser_.try_invoke(*value, std::forward<Fun>(fun));
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@ -177,6 +176,10 @@ public:
 | 
				
			|||||||
            return value;
 | 
					            return value;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        ////////////////
 | 
				
			||||||
 | 
					        // members
 | 
				
			||||||
 | 
					        ////////////////
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        std::tuple<Ts...> values_;
 | 
					        std::tuple<Ts...> values_;
 | 
				
			||||||
        parser& parser_;
 | 
					        parser& parser_;
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
@ -488,7 +491,7 @@ private:
 | 
				
			|||||||
    ////////////////
 | 
					    ////////////////
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    std::string file_name_;
 | 
					    std::string file_name_;
 | 
				
			||||||
    error_type error_;
 | 
					    error_type error_{};
 | 
				
			||||||
    reader reader_;
 | 
					    reader reader_;
 | 
				
			||||||
    size_t line_number_{0};
 | 
					    size_t line_number_{0};
 | 
				
			||||||
    bool eof_{false};
 | 
					    bool eof_{false};
 | 
				
			||||||
 | 
				
			|||||||
@ -4,6 +4,10 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
namespace ss {
 | 
					namespace ss {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					////////////////
 | 
				
			||||||
 | 
					// matcher
 | 
				
			||||||
 | 
					////////////////
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template <char... Cs>
 | 
					template <char... Cs>
 | 
				
			||||||
struct matcher {
 | 
					struct matcher {
 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
@ -36,7 +40,7 @@ public:
 | 
				
			|||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template <typename FirstMatcher, typename SecondMatcher>
 | 
					template <typename FirstMatcher, typename SecondMatcher>
 | 
				
			||||||
constexpr bool matches_intersect() {
 | 
					inline constexpr bool matches_intersect() {
 | 
				
			||||||
    for (const auto& first_match : FirstMatcher::matches) {
 | 
					    for (const auto& first_match : FirstMatcher::matches) {
 | 
				
			||||||
        for (const auto& second_match : SecondMatcher::matches) {
 | 
					        for (const auto& second_match : SecondMatcher::matches) {
 | 
				
			||||||
            if (first_match != '\0' && first_match == second_match) {
 | 
					            if (first_match != '\0' && first_match == second_match) {
 | 
				
			||||||
@ -47,6 +51,13 @@ constexpr bool matches_intersect() {
 | 
				
			|||||||
    return false;
 | 
					    return false;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template <typename FirstMatcher, typename SecondMatcher1,
 | 
				
			||||||
 | 
					          typename SecondMatcher2>
 | 
				
			||||||
 | 
					inline constexpr bool matches_intersect_union() {
 | 
				
			||||||
 | 
					    return matches_intersect<FirstMatcher, SecondMatcher1>() ||
 | 
				
			||||||
 | 
					           matches_intersect<FirstMatcher, SecondMatcher2>();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template <>
 | 
					template <>
 | 
				
			||||||
class matcher<'\0'> {
 | 
					class matcher<'\0'> {
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
@ -55,31 +66,57 @@ public:
 | 
				
			|||||||
    static bool match(char c) = delete;
 | 
					    static bool match(char c) = delete;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					////////////////
 | 
				
			||||||
 | 
					// setup parameters
 | 
				
			||||||
 | 
					////////////////
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template <char C>
 | 
					template <char C>
 | 
				
			||||||
struct quote : matcher<C> {};
 | 
					struct quote : matcher<C> {};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template <char... Cs>
 | 
					template <char... Cs>
 | 
				
			||||||
struct trim : matcher<Cs...> {};
 | 
					struct trim : matcher<Cs...> {};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template <char... Cs>
 | 
				
			||||||
 | 
					struct trim_left : matcher<Cs...> {};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template <char... Cs>
 | 
				
			||||||
 | 
					struct trim_right : matcher<Cs...> {};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template <char... Cs>
 | 
					template <char... Cs>
 | 
				
			||||||
struct escape : matcher<Cs...> {};
 | 
					struct escape : matcher<Cs...> {};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// TODO add limit
 | 
				
			||||||
 | 
					class multiline;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class string_error;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					////////////////
 | 
				
			||||||
 | 
					// setup implementation
 | 
				
			||||||
 | 
					////////////////
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template <typename T, template <char...> class Template>
 | 
					template <typename T, template <char...> class Template>
 | 
				
			||||||
struct is_instance_of_matcher {
 | 
					struct is_instance_of_matcher : std::false_type {};
 | 
				
			||||||
    constexpr static bool value = false;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
template <char... Ts, template <char...> class Template>
 | 
					template <char... Ts, template <char...> class Template>
 | 
				
			||||||
struct is_instance_of_matcher<Template<Ts...>, Template> {
 | 
					struct is_instance_of_matcher<Template<Ts...>, Template> : std::true_type {};
 | 
				
			||||||
    constexpr static bool value = true;
 | 
					
 | 
				
			||||||
};
 | 
					template <typename T, template <char...> class Template>
 | 
				
			||||||
 | 
					using is_instance_of_matcher_t =
 | 
				
			||||||
 | 
					    typename is_instance_of_matcher<T, Template>::type;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
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 = ternary_t<is_instance_of_matcher<T, Matcher>::value, T,
 | 
					
 | 
				
			||||||
 | 
					    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,
 | 
				
			||||||
                           typename get_matcher<Matcher, Ts...>::type>;
 | 
					                           typename get_matcher<Matcher, Ts...>::type>;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -91,39 +128,72 @@ struct get_matcher<Matcher> {
 | 
				
			|||||||
template <template <char...> class Matcher, typename... Ts>
 | 
					template <template <char...> class Matcher, typename... Ts>
 | 
				
			||||||
using get_matcher_t = typename get_matcher<Matcher, Ts...>::type;
 | 
					using get_matcher_t = typename get_matcher<Matcher, Ts...>::type;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class multiline;
 | 
					 | 
				
			||||||
class string_error;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
template <typename... Ts>
 | 
					template <typename... Ts>
 | 
				
			||||||
struct setup {
 | 
					struct setup {
 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
    template <typename T>
 | 
					    template <typename T>
 | 
				
			||||||
    struct is_multiline : std::is_same<T, multiline> {};
 | 
					    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>> {};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    constexpr static auto count_multiline = count<is_multiline, Ts...>::size;
 | 
					    template <typename T>
 | 
				
			||||||
 | 
					    struct is_multiline : std::is_same<T, multiline> {};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    template <typename T>
 | 
					    template <typename T>
 | 
				
			||||||
    struct is_string_error : std::is_same<T, string_error> {};
 | 
					    struct is_string_error : std::is_same<T, string_error> {};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    constexpr static auto count_string_error =
 | 
					    constexpr static auto count_matcher = count_v<is_matcher, Ts...>;
 | 
				
			||||||
        count<is_string_error, Ts...>::size;
 | 
					    constexpr static auto count_multiline = count_v<is_multiline, Ts...>;
 | 
				
			||||||
 | 
					    constexpr static auto count_string_error = count_v<is_string_error, Ts...>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    constexpr static auto number_of_valid_setup_types =
 | 
				
			||||||
 | 
					        count_matcher + count_multiline + count_string_error;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    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...>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
    using quote = get_matcher_t<quote, Ts...>;
 | 
					    using quote = get_matcher_t<quote, Ts...>;
 | 
				
			||||||
    using trim = get_matcher_t<trim, Ts...>;
 | 
					 | 
				
			||||||
    using escape = get_matcher_t<escape, Ts...>;
 | 
					    using escape = get_matcher_t<escape, Ts...>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    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>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    constexpr static bool multiline = (count_multiline == 1);
 | 
					    constexpr static bool multiline = (count_multiline == 1);
 | 
				
			||||||
    constexpr static bool string_error = (count_string_error == 1);
 | 
					    constexpr static bool string_error = (count_string_error == 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    static_assert(
 | 
					    static_assert(
 | 
				
			||||||
        !multiline || (multiline && (quote::enabled || escape::enabled)),
 | 
					        !multiline || (multiline && (quote::enabled || escape::enabled)),
 | 
				
			||||||
        "to enable multiline either quote or escape need to be enabled");
 | 
					        "to enable multiline either quote or escape need to be enabled");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define ASSERT_MSG "cannot have the same match character in multiple matchers"
 | 
					    static_assert(!(trim_all::enabled && trim_left_only::enabled) &&
 | 
				
			||||||
    static_assert(!matches_intersect<quote, trim>(), ASSERT_MSG);
 | 
					                      !(trim_all::enabled && trim_right_only::enabled),
 | 
				
			||||||
    static_assert(!matches_intersect<trim, escape>(), ASSERT_MSG);
 | 
					                  "ambiguous trim setup");
 | 
				
			||||||
    static_assert(!matches_intersect<escape, quote>(), ASSERT_MSG);
 | 
					
 | 
				
			||||||
#undef ASSERT_MSG
 | 
					    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");
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template <typename... Ts>
 | 
					template <typename... Ts>
 | 
				
			||||||
 | 
				
			|||||||
@ -1,4 +1,5 @@
 | 
				
			|||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					#include "common.hpp"
 | 
				
			||||||
#include "setup.hpp"
 | 
					#include "setup.hpp"
 | 
				
			||||||
#include "type_traits.hpp"
 | 
					#include "type_traits.hpp"
 | 
				
			||||||
#include <algorithm>
 | 
					#include <algorithm>
 | 
				
			||||||
@ -10,16 +11,12 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
namespace ss {
 | 
					namespace ss {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// TODO move to common or something
 | 
					 | 
				
			||||||
using string_range = std::pair<const char*, const char*>;
 | 
					 | 
				
			||||||
using split_input = std::vector<string_range>;
 | 
					 | 
				
			||||||
constexpr static auto default_delimiter = ",";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
template <typename... Ts>
 | 
					template <typename... Ts>
 | 
				
			||||||
class splitter {
 | 
					class splitter {
 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
    using quote = typename setup<Ts...>::quote;
 | 
					    using quote = typename setup<Ts...>::quote;
 | 
				
			||||||
    using trim = typename setup<Ts...>::trim;
 | 
					    using trim_left = typename setup<Ts...>::trim_left;
 | 
				
			||||||
 | 
					    using trim_right = typename setup<Ts...>::trim_right;
 | 
				
			||||||
    using escape = typename setup<Ts...>::escape;
 | 
					    using escape = typename setup<Ts...>::escape;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    constexpr static auto string_error = setup<Ts...>::string_error;
 | 
					    constexpr static auto string_error = setup<Ts...>::string_error;
 | 
				
			||||||
@ -39,8 +36,7 @@ public:
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const std::string& error_msg() const {
 | 
					    const std::string& error_msg() const {
 | 
				
			||||||
        static_assert(string_error,
 | 
					        assert_string_error_defined<string_error>();
 | 
				
			||||||
                      "'string_error' needs to be enabled to use 'error_msg'");
 | 
					 | 
				
			||||||
        return error_;
 | 
					        return error_;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -48,9 +44,9 @@ public:
 | 
				
			|||||||
        return unterminated_quote_;
 | 
					        return unterminated_quote_;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const split_input& split(line_ptr_type new_line,
 | 
					    const split_data& split(line_ptr_type new_line,
 | 
				
			||||||
                            const std::string& delimiter = default_delimiter) {
 | 
					                            const std::string& delimiter = default_delimiter) {
 | 
				
			||||||
        split_input_.clear();
 | 
					        split_data_.clear();
 | 
				
			||||||
        return resplit(new_line, -1, delimiter);
 | 
					        return resplit(new_line, -1, delimiter);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -60,33 +56,35 @@ private:
 | 
				
			|||||||
    ////////////////
 | 
					    ////////////////
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void adjust_ranges(const char* old_line) {
 | 
					    void adjust_ranges(const char* old_line) {
 | 
				
			||||||
        for (auto& [begin, end] : split_input_) {
 | 
					        for (auto& [begin, end] : split_data_) {
 | 
				
			||||||
            begin = begin - old_line + line_;
 | 
					            begin = begin - old_line + line_;
 | 
				
			||||||
            end = end - old_line + line_;
 | 
					            end = end - old_line + line_;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const split_input& resplit(
 | 
					    const split_data& resplit(
 | 
				
			||||||
        line_ptr_type new_line, ssize_t new_size,
 | 
					        line_ptr_type new_line, ssize_t new_size,
 | 
				
			||||||
        const std::string& delimiter = default_delimiter) {
 | 
					        const std::string& delimiter = default_delimiter) {
 | 
				
			||||||
        line_ = new_line;
 | 
					        line_ = new_line;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // resplitting, continue from last slice
 | 
					        // resplitting, continue from last slice
 | 
				
			||||||
        if (!split_input_.empty() && unterminated_quote()) {
 | 
					        if constexpr (quote::enabled) {
 | 
				
			||||||
            const auto& last = std::prev(split_input_.end());
 | 
					            if (!split_data_.empty() && unterminated_quote()) {
 | 
				
			||||||
 | 
					                const auto& last = std::prev(split_data_.end());
 | 
				
			||||||
                const auto [old_line, old_begin] = *last;
 | 
					                const auto [old_line, old_begin] = *last;
 | 
				
			||||||
                size_t begin = old_begin - old_line - 1;
 | 
					                size_t begin = old_begin - old_line - 1;
 | 
				
			||||||
            split_input_.pop_back();
 | 
					                split_data_.pop_back();
 | 
				
			||||||
                adjust_ranges(old_line);
 | 
					                adjust_ranges(old_line);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                // safety measure
 | 
					                // safety measure
 | 
				
			||||||
                if (new_size != -1 && static_cast<size_t>(new_size) < begin) {
 | 
					                if (new_size != -1 && static_cast<size_t>(new_size) < begin) {
 | 
				
			||||||
                    set_error_invalid_resplit();
 | 
					                    set_error_invalid_resplit();
 | 
				
			||||||
                return split_input_;
 | 
					                    return split_data_;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                begin_ = line_ + begin;
 | 
					                begin_ = line_ + begin;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return split_impl_select_delim(delimiter);
 | 
					        return split_impl_select_delim(delimiter);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -163,9 +161,17 @@ private:
 | 
				
			|||||||
        return delim.size();
 | 
					        return delim.size();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void trim_if_enabled(line_ptr_type& curr) {
 | 
					    void trim_left_if_enabled(line_ptr_type& curr) {
 | 
				
			||||||
        if constexpr (trim::enabled) {
 | 
					        if constexpr (trim_left::enabled) {
 | 
				
			||||||
            while (trim::match(*curr)) {
 | 
					            while (trim_left::match(*curr)) {
 | 
				
			||||||
 | 
					                ++curr;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void trim_right_if_enabled(line_ptr_type& curr) {
 | 
				
			||||||
 | 
					        if constexpr (trim_right::enabled) {
 | 
				
			||||||
 | 
					            while (trim_right::match(*curr)) {
 | 
				
			||||||
                ++curr;
 | 
					                ++curr;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@ -176,7 +182,7 @@ private:
 | 
				
			|||||||
                                             const Delim& delim) {
 | 
					                                             const Delim& delim) {
 | 
				
			||||||
        line_ptr_type end = begin;
 | 
					        line_ptr_type end = begin;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        trim_if_enabled(end);
 | 
					        trim_right_if_enabled(end);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // just spacing
 | 
					        // just spacing
 | 
				
			||||||
        if (*end == '\0') {
 | 
					        if (*end == '\0') {
 | 
				
			||||||
@ -190,7 +196,7 @@ private:
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        end += delimiter_size(delim);
 | 
					        end += delimiter_size(delim);
 | 
				
			||||||
        trim_if_enabled(end);
 | 
					        trim_left_if_enabled(end);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // delimiter
 | 
					        // delimiter
 | 
				
			||||||
        return {end - begin, true};
 | 
					        return {end - begin, true};
 | 
				
			||||||
@ -213,7 +219,7 @@ private:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    void shift_and_push() {
 | 
					    void shift_and_push() {
 | 
				
			||||||
        shift_and_set_current();
 | 
					        shift_and_set_current();
 | 
				
			||||||
        split_input_.emplace_back(begin_, curr_);
 | 
					        split_data_.emplace_back(begin_, curr_);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void shift_if_escaped(line_ptr_type& curr) {
 | 
					    void shift_if_escaped(line_ptr_type& curr) {
 | 
				
			||||||
@ -241,13 +247,13 @@ private:
 | 
				
			|||||||
    // split impl
 | 
					    // split impl
 | 
				
			||||||
    ////////////////
 | 
					    ////////////////
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const split_input& split_impl_select_delim(
 | 
					    const split_data& split_impl_select_delim(
 | 
				
			||||||
        const std::string& delimiter = default_delimiter) {
 | 
					        const std::string& delimiter = default_delimiter) {
 | 
				
			||||||
        clear_error();
 | 
					        clear_error();
 | 
				
			||||||
        switch (delimiter.size()) {
 | 
					        switch (delimiter.size()) {
 | 
				
			||||||
        case 0:
 | 
					        case 0:
 | 
				
			||||||
            set_error_empty_delimiter();
 | 
					            set_error_empty_delimiter();
 | 
				
			||||||
            return split_input_;
 | 
					            return split_data_;
 | 
				
			||||||
        case 1:
 | 
					        case 1:
 | 
				
			||||||
            return split_impl(delimiter[0]);
 | 
					            return split_impl(delimiter[0]);
 | 
				
			||||||
        default:
 | 
					        default:
 | 
				
			||||||
@ -256,18 +262,18 @@ private:
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    template <typename Delim>
 | 
					    template <typename Delim>
 | 
				
			||||||
    const split_input& split_impl(const Delim& delim) {
 | 
					    const split_data& split_impl(const Delim& delim) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (split_input_.empty()) {
 | 
					        if (split_data_.empty()) {
 | 
				
			||||||
            begin_ = line_;
 | 
					            begin_ = line_;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        trim_if_enabled(begin_);
 | 
					        trim_left_if_enabled(begin_);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        for (done_ = false; !done_; read(delim))
 | 
					        for (done_ = false; !done_; read(delim))
 | 
				
			||||||
            ;
 | 
					            ;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return split_input_;
 | 
					        return split_data_;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ////////////////
 | 
					    ////////////////
 | 
				
			||||||
@ -329,7 +335,7 @@ private:
 | 
				
			|||||||
                    // eg: ..."hell\0 -> quote not terminated
 | 
					                    // eg: ..."hell\0 -> quote not terminated
 | 
				
			||||||
                    if (*end_ == '\0') {
 | 
					                    if (*end_ == '\0') {
 | 
				
			||||||
                        set_error_unterminated_quote();
 | 
					                        set_error_unterminated_quote();
 | 
				
			||||||
                        split_input_.emplace_back(line_, begin_);
 | 
					                        split_data_.emplace_back(line_, begin_);
 | 
				
			||||||
                        done_ = true;
 | 
					                        done_ = true;
 | 
				
			||||||
                        break;
 | 
					                        break;
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
@ -363,7 +369,7 @@ private:
 | 
				
			|||||||
                    // mismatched quote
 | 
					                    // mismatched quote
 | 
				
			||||||
                    // eg: ...,"hel"lo,... -> error
 | 
					                    // eg: ...,"hel"lo,... -> error
 | 
				
			||||||
                    set_error_mismatched_quote(end_ - line_);
 | 
					                    set_error_mismatched_quote(end_ - line_);
 | 
				
			||||||
                    split_input_.emplace_back(line_, begin_);
 | 
					                    split_data_.emplace_back(line_, begin_);
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                done_ = true;
 | 
					                done_ = true;
 | 
				
			||||||
                break;
 | 
					                break;
 | 
				
			||||||
@ -375,17 +381,16 @@ private:
 | 
				
			|||||||
    // members
 | 
					    // members
 | 
				
			||||||
    ////////////////
 | 
					    ////////////////
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    static_assert(std::is_same_v<error_type, bool> ||
 | 
					    error_type error_{};
 | 
				
			||||||
                  std::is_same_v<error_type, std::string>);
 | 
					 | 
				
			||||||
    error_type error_;
 | 
					 | 
				
			||||||
    bool unterminated_quote_{false};
 | 
					    bool unterminated_quote_{false};
 | 
				
			||||||
 | 
					    bool done_;
 | 
				
			||||||
 | 
					    size_t escaped_{0};
 | 
				
			||||||
 | 
					    split_data split_data_;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    line_ptr_type begin_;
 | 
					    line_ptr_type begin_;
 | 
				
			||||||
    line_ptr_type curr_;
 | 
					    line_ptr_type curr_;
 | 
				
			||||||
    line_ptr_type end_;
 | 
					    line_ptr_type end_;
 | 
				
			||||||
    line_ptr_type line_;
 | 
					    line_ptr_type line_;
 | 
				
			||||||
    bool done_;
 | 
					 | 
				
			||||||
    size_t escaped_{0};
 | 
					 | 
				
			||||||
    split_input split_input_;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    template <typename...>
 | 
					    template <typename...>
 | 
				
			||||||
    friend class converter;
 | 
					    friend class converter;
 | 
				
			||||||
 | 
				
			|||||||
@ -103,6 +103,9 @@ struct apply_trait<Trait, std::tuple<T>> {
 | 
				
			|||||||
    using type = std::tuple<typename Trait<T>::type>;
 | 
					    using type = std::tuple<typename Trait<T>::type>;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template <template <typename...> class Trait, typename... Ts>
 | 
				
			||||||
 | 
					using apply_trait_t = typename apply_trait<Trait, Ts...>::type;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
////////////////
 | 
					////////////////
 | 
				
			||||||
// apply optional trait
 | 
					// apply optional trait
 | 
				
			||||||
////////////////
 | 
					////////////////
 | 
				
			||||||
@ -143,6 +146,9 @@ struct apply_optional_trait<Trait, std::tuple<T>> {
 | 
				
			|||||||
        std::tuple<typename optional_trait<typename Trait<T>::type, T>::type>;
 | 
					        std::tuple<typename optional_trait<typename Trait<T>::type, T>::type>;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template <template <typename...> class Trait, typename... Ts>
 | 
				
			||||||
 | 
					using apply_trait_optional_t = apply_optional_trait<Trait, Ts...>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
////////////////
 | 
					////////////////
 | 
				
			||||||
// filter false_type
 | 
					// filter false_type
 | 
				
			||||||
////////////////
 | 
					////////////////
 | 
				
			||||||
@ -192,6 +198,9 @@ struct negate_impl {
 | 
				
			|||||||
    using type = std::integral_constant<bool, !Trait<Ts...>::value>;
 | 
					    using type = std::integral_constant<bool, !Trait<Ts...>::value>;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template <template <typename...> class Trait>
 | 
				
			||||||
 | 
					using negate_impl_t = typename negate_impl<Trait>::type;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
////////////////
 | 
					////////////////
 | 
				
			||||||
// filter by trait
 | 
					// filter by trait
 | 
				
			||||||
////////////////
 | 
					////////////////
 | 
				
			||||||
@ -235,20 +244,23 @@ struct count;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
template <template <typename...> class Trait, typename T, typename... Ts>
 | 
					template <template <typename...> class Trait, typename T, typename... Ts>
 | 
				
			||||||
struct count<Trait, T, Ts...> {
 | 
					struct count<Trait, T, Ts...> {
 | 
				
			||||||
    static constexpr size_t size =
 | 
					    static constexpr size_t value =
 | 
				
			||||||
        std::tuple_size<filter_if_t<Trait, T, Ts...>>::value;
 | 
					        std::tuple_size<filter_if_t<Trait, T, Ts...>>::value;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template <template <typename...> class Trait, typename T>
 | 
					template <template <typename...> class Trait, typename T>
 | 
				
			||||||
struct count<Trait, T> {
 | 
					struct count<Trait, T> {
 | 
				
			||||||
    static constexpr size_t size = Trait<T>::value;
 | 
					    static constexpr size_t value = Trait<T>::value;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template <template <typename...> class Trait>
 | 
					template <template <typename...> class Trait>
 | 
				
			||||||
struct count<Trait> {
 | 
					struct count<Trait> {
 | 
				
			||||||
    static constexpr size_t size = 0;
 | 
					    static constexpr size_t value = 0;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template <template <typename...> class Trait, typename... Ts>
 | 
				
			||||||
 | 
					constexpr size_t count_v = count<Trait, Ts...>::value;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
////////////////
 | 
					////////////////
 | 
				
			||||||
// count not
 | 
					// count not
 | 
				
			||||||
////////////////
 | 
					////////////////
 | 
				
			||||||
@ -258,34 +270,40 @@ struct count_not;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
template <template <typename...> class Trait, typename T, typename... Ts>
 | 
					template <template <typename...> class Trait, typename T, typename... Ts>
 | 
				
			||||||
struct count_not<Trait, T, Ts...> {
 | 
					struct count_not<Trait, T, Ts...> {
 | 
				
			||||||
    static constexpr size_t size =
 | 
					    static constexpr size_t value =
 | 
				
			||||||
        std::tuple_size<filter_not_t<Trait, T, Ts...>>::value;
 | 
					        std::tuple_size<filter_not_t<Trait, T, Ts...>>::value;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template <template <typename...> class Trait, typename T>
 | 
					template <template <typename...> class Trait, typename T>
 | 
				
			||||||
struct count_not<Trait, T> {
 | 
					struct count_not<Trait, T> {
 | 
				
			||||||
    static constexpr size_t size = !Trait<T>::value;
 | 
					    static constexpr size_t value = !Trait<T>::value;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template <template <typename...> class Trait>
 | 
					template <template <typename...> class Trait>
 | 
				
			||||||
struct count_not<Trait> {
 | 
					struct count_not<Trait> {
 | 
				
			||||||
    static constexpr size_t size = 0;
 | 
					    static constexpr size_t value = 0;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template <template <typename...> class Trait, typename... Ts>
 | 
				
			||||||
 | 
					constexpr size_t count_not_v = count_not<Trait, Ts...>::value;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
////////////////
 | 
					////////////////
 | 
				
			||||||
// all of
 | 
					// all of
 | 
				
			||||||
////////////////
 | 
					////////////////
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template <template <typename...> class Trait, typename... Ts>
 | 
					template <template <typename...> class Trait, typename... Ts>
 | 
				
			||||||
struct all_of {
 | 
					struct all_of {
 | 
				
			||||||
    static constexpr bool value = count<Trait, Ts...>::size == sizeof...(Ts);
 | 
					    static constexpr bool value = count_v<Trait, Ts...> == sizeof...(Ts);
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template <template <typename...> class Trait, typename... Ts>
 | 
					template <template <typename...> class Trait, typename... Ts>
 | 
				
			||||||
struct all_of<Trait, std::tuple<Ts...>> {
 | 
					struct all_of<Trait, std::tuple<Ts...>> {
 | 
				
			||||||
    static constexpr bool value = count<Trait, Ts...>::size == sizeof...(Ts);
 | 
					    static constexpr bool value = count_v<Trait, Ts...> == sizeof...(Ts);
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template <template <typename...> class Trait, typename... Ts>
 | 
				
			||||||
 | 
					constexpr bool all_of_v = all_of<Trait, Ts...>::value;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
////////////////
 | 
					////////////////
 | 
				
			||||||
// any of
 | 
					// any of
 | 
				
			||||||
////////////////
 | 
					////////////////
 | 
				
			||||||
@ -293,43 +311,52 @@ struct all_of<Trait, std::tuple<Ts...>> {
 | 
				
			|||||||
template <template <typename...> class Trait, typename... Ts>
 | 
					template <template <typename...> class Trait, typename... Ts>
 | 
				
			||||||
struct any_of {
 | 
					struct any_of {
 | 
				
			||||||
    static_assert(sizeof...(Ts) > 0);
 | 
					    static_assert(sizeof...(Ts) > 0);
 | 
				
			||||||
    static constexpr bool value = count<Trait, Ts...>::size > 0;
 | 
					    static constexpr bool value = count_v<Trait, Ts...> > 0;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template <template <typename...> class Trait, typename... Ts>
 | 
					template <template <typename...> class Trait, typename... Ts>
 | 
				
			||||||
struct any_of<Trait, std::tuple<Ts...>> {
 | 
					struct any_of<Trait, std::tuple<Ts...>> {
 | 
				
			||||||
    static_assert(sizeof...(Ts) > 0);
 | 
					    static_assert(sizeof...(Ts) > 0);
 | 
				
			||||||
    static constexpr bool value = count<Trait, Ts...>::size > 0;
 | 
					    static constexpr bool value = count_v<Trait, Ts...> > 0;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template <template <typename...> class Trait, typename... Ts>
 | 
				
			||||||
 | 
					constexpr bool any_of_v = any_of<Trait, Ts...>::value;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
////////////////
 | 
					////////////////
 | 
				
			||||||
// none  of
 | 
					// none  of
 | 
				
			||||||
////////////////
 | 
					////////////////
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template <template <typename...> class Trait, typename... Ts>
 | 
					template <template <typename...> class Trait, typename... Ts>
 | 
				
			||||||
struct none_of {
 | 
					struct none_of {
 | 
				
			||||||
    static constexpr bool value = count<Trait, Ts...>::size == 0;
 | 
					    static constexpr bool value = count_v<Trait, Ts...> == 0;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template <template <typename...> class Trait, typename... Ts>
 | 
					template <template <typename...> class Trait, typename... Ts>
 | 
				
			||||||
struct none_of<Trait, std::tuple<Ts...>> {
 | 
					struct none_of<Trait, std::tuple<Ts...>> {
 | 
				
			||||||
    static constexpr bool value = count<Trait, Ts...>::size == 0;
 | 
					    static constexpr bool value = count_v<Trait, Ts...> == 0;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template <template <typename...> class Trait, typename... Ts>
 | 
				
			||||||
 | 
					constexpr bool none_of_v = none_of<Trait, Ts...>::value;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
////////////////
 | 
					////////////////
 | 
				
			||||||
// is instance of
 | 
					// is instance of
 | 
				
			||||||
////////////////
 | 
					////////////////
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template <typename T, template <typename...> class Template>
 | 
					template <template <typename...> class Template, typename T>
 | 
				
			||||||
struct is_instance_of {
 | 
					struct is_instance_of {
 | 
				
			||||||
    constexpr static bool value = false;
 | 
					    constexpr static bool value = false;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template <typename... Ts, template <typename...> class Template>
 | 
					template <template <typename...> class Template, typename... Ts>
 | 
				
			||||||
struct is_instance_of<Template<Ts...>, Template> {
 | 
					struct is_instance_of<Template, Template<Ts...>> {
 | 
				
			||||||
    constexpr static bool value = true;
 | 
					    constexpr static bool value = true;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template <template <typename...> class Template, typename... Ts>
 | 
				
			||||||
 | 
					constexpr bool is_instance_of_v = is_instance_of<Template, Ts...>::value;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
////////////////
 | 
					////////////////
 | 
				
			||||||
// ternary
 | 
					// ternary
 | 
				
			||||||
////////////////
 | 
					////////////////
 | 
				
			||||||
@ -354,17 +381,21 @@ using ternary_t = typename ternary<B, T, U>::type;
 | 
				
			|||||||
// tuple to struct
 | 
					// tuple to struct
 | 
				
			||||||
////////////////
 | 
					////////////////
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template <class S, std::size_t... Is, class Tup>
 | 
					template <class T, std::size_t... Is, class U>
 | 
				
			||||||
S to_object(std::index_sequence<Is...>, Tup&& tup) {
 | 
					T to_object_impl(std::index_sequence<Is...>, U&& data) {
 | 
				
			||||||
    return {std::get<Is>(std::forward<Tup>(tup))...};
 | 
					    return {std::get<Is>(std::forward<U>(data))...};
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// TODO Tup may not be a tuple ...
 | 
					template <class T, class U>
 | 
				
			||||||
template <class S, class Tup>
 | 
					T to_object(U&& data) {
 | 
				
			||||||
S to_object(Tup&& tup) {
 | 
					    using NoRefU = std::remove_reference_t<U>;
 | 
				
			||||||
    using T = std::remove_reference_t<Tup>;
 | 
					    if constexpr (is_instance_of_v<std::tuple, NoRefU>) {
 | 
				
			||||||
    return to_object<S>(std::make_index_sequence<std::tuple_size<T>{}>{},
 | 
					        return to_object_impl<
 | 
				
			||||||
                        std::forward<Tup>(tup));
 | 
					            T>(std::make_index_sequence<std::tuple_size<NoRefU>{}>{},
 | 
				
			||||||
 | 
					               std::forward<U>(data));
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        return T{std::forward<U>(data)};
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
} /* trait */
 | 
					} /* trait */
 | 
				
			||||||
 | 
				
			|||||||
@ -17,7 +17,7 @@ struct set_combinations_size {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
std::vector<std::string> words(const ss::split_input& input) {
 | 
					std::vector<std::string> words(const ss::split_data& input) {
 | 
				
			||||||
    std::vector<std::string> ret;
 | 
					    std::vector<std::string> ret;
 | 
				
			||||||
    for (const auto& [begin, end] : input) {
 | 
					    for (const auto& [begin, end] : input) {
 | 
				
			||||||
        ret.emplace_back(begin, end);
 | 
					        ret.emplace_back(begin, end);
 | 
				
			||||||
@ -88,6 +88,30 @@ auto spaced(const case_type& input, const std::string& s1,
 | 
				
			|||||||
    return ret;
 | 
					    return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					auto spaced_left(const case_type& input, const std::string& s) {
 | 
				
			||||||
 | 
					    case_type ret = input;
 | 
				
			||||||
 | 
					    for (const auto& i : input) {
 | 
				
			||||||
 | 
					        ret.push_back(concat(i));
 | 
				
			||||||
 | 
					        ret.push_back(concat(s, i));
 | 
				
			||||||
 | 
					        ret.push_back(concat(s, s, i));
 | 
				
			||||||
 | 
					        ret.push_back(concat(s, s, s, i));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					auto spaced_right(const case_type& input, const std::string& s) {
 | 
				
			||||||
 | 
					    case_type ret = input;
 | 
				
			||||||
 | 
					    for (const auto& i : input) {
 | 
				
			||||||
 | 
					        ret.push_back(concat(i));
 | 
				
			||||||
 | 
					        ret.push_back(concat(i, s));
 | 
				
			||||||
 | 
					        ret.push_back(concat(i, s, s));
 | 
				
			||||||
 | 
					        ret.push_back(concat(i, s, s, s));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
std::vector<std::string> combinations(const std::vector<std::string>& v,
 | 
					std::vector<std::string> combinations(const std::vector<std::string>& v,
 | 
				
			||||||
                                      const std::string& delim, size_t n) {
 | 
					                                      const std::string& delim, size_t n) {
 | 
				
			||||||
    if (n <= 1) {
 | 
					    if (n <= 1) {
 | 
				
			||||||
@ -709,3 +733,104 @@ TEST_CASE("splitter test invalid splits") {
 | 
				
			|||||||
    CHECK(!s.unterminated_quote());
 | 
					    CHECK(!s.unterminated_quote());
 | 
				
			||||||
    CHECK(!s.error_msg().empty());
 | 
					    CHECK(!s.error_msg().empty());
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					TEST_CASE("splitter test with trim_left") {
 | 
				
			||||||
 | 
					    auto guard = set_combinations_size(3);
 | 
				
			||||||
 | 
					    case_type case1 = spaced_left({R"(x )"}, " ");
 | 
				
			||||||
 | 
					    case_type case2 = spaced_left({R"(yy )"}, " ");
 | 
				
			||||||
 | 
					    case_type case3 = spaced_left({R"(y y )"}, " ");
 | 
				
			||||||
 | 
					    case_type case4 = spaced_left({R"()"}, " ");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    std::vector<std::string> delims = {",", "::", "\t", "\n"};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        matches_type p{{case1, "x "},
 | 
				
			||||||
 | 
					                       {case2, "yy "},
 | 
				
			||||||
 | 
					                       {case3, "y y "},
 | 
				
			||||||
 | 
					                       {case4, ""}};
 | 
				
			||||||
 | 
					        test_combinations<ss::trim_left<' '>>(p, delims);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    case_type case5 = spaced_left({"z "}, "\t");
 | 
				
			||||||
 | 
					    case_type case6 = spaced_left({"ab\t "}, " \t");
 | 
				
			||||||
 | 
					    case_type case7 = spaced_left({"a\tb "}, " \t");
 | 
				
			||||||
 | 
					    case_type case8 = spaced_left({"a \t b "}, " \t");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        matches_type p{{case1, "x "},    {case2, "yy "},    {case3, "y y "},
 | 
				
			||||||
 | 
					                       {case4, ""},      {case5, "z "},     {case6, "ab\t "},
 | 
				
			||||||
 | 
					                       {case7, "a\tb "}, {case8, "a \t b "}};
 | 
				
			||||||
 | 
					        test_combinations<ss::trim_left<' ', '\t'>>(p, {",", "::", "\n"});
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					TEST_CASE("splitter test with trim_right") {
 | 
				
			||||||
 | 
					    auto guard = set_combinations_size(3);
 | 
				
			||||||
 | 
					    case_type case1 = spaced_right({R"( x)"}, " ");
 | 
				
			||||||
 | 
					    case_type case2 = spaced_right({R"( yy)"}, " ");
 | 
				
			||||||
 | 
					    case_type case3 = spaced_right({R"( y y)"}, " ");
 | 
				
			||||||
 | 
					    case_type case4 = spaced_right({R"()"}, " ");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    std::vector<std::string> delims = {",", "::", "\t", "\n"};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        matches_type p{{case1, " x"},
 | 
				
			||||||
 | 
					                       {case2, " yy"},
 | 
				
			||||||
 | 
					                       {case3, " y y"},
 | 
				
			||||||
 | 
					                       {case4, ""}};
 | 
				
			||||||
 | 
					        test_combinations<ss::trim_right<' '>>(p, delims);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    case_type case5 = spaced_right({" z"}, "\t");
 | 
				
			||||||
 | 
					    case_type case6 = spaced_right({"\t ab"}, " \t");
 | 
				
			||||||
 | 
					    case_type case7 = spaced_right({"\ta\tb"}, " \t");
 | 
				
			||||||
 | 
					    case_type case8 = spaced_right({" \t a \t b"}, " \t");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        matches_type p{{case1, " x"},     {case2, " yy"},
 | 
				
			||||||
 | 
					                       {case3, " y y"},   {case4, ""},
 | 
				
			||||||
 | 
					                       {case5, " z"},     {case6, "\t ab"},
 | 
				
			||||||
 | 
					                       {case7, "\ta\tb"}, {case8, " \t a \t b"}};
 | 
				
			||||||
 | 
					        test_combinations<ss::trim_right<' ', '\t'>>(p, {",", "::", "\n"});
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					TEST_CASE("splitter test with trim_right and trim_left") {
 | 
				
			||||||
 | 
					    auto guard = set_combinations_size(3);
 | 
				
			||||||
 | 
					    case_type case1 = spaced_right({R"(-x)"}, "-");
 | 
				
			||||||
 | 
					    case_type case2 = spaced_left({R"(yy_)"}, "_");
 | 
				
			||||||
 | 
					    case_type case3 = spaced_right({R"(-y y)"}, "-");
 | 
				
			||||||
 | 
					    case_type case4 = spaced_left({R"()"}, "-");
 | 
				
			||||||
 | 
					    case_type case5 = spaced_left({R"()"}, "_");
 | 
				
			||||||
 | 
					    case_type case6 = {"___---", "_-", "______-"};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    std::vector<std::string> delims = {",", "::", "\t", "\n"};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        matches_type p{{case1, "-x"}, {case2, "yy_"}, {case3, "-y y"},
 | 
				
			||||||
 | 
					                       {case4, ""},   {case5, ""},    {case6, ""}};
 | 
				
			||||||
 | 
					        test_combinations<ss::trim_left<'_'>, ss::trim_right<'-'>>(p, delims);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					TEST_CASE("splitter test with quote and escape, trim_left and trim_right") {
 | 
				
			||||||
 | 
					    auto guard = set_combinations_size(3);
 | 
				
			||||||
 | 
					    case_type case1 = spaced_left({R"("\"")", R"(\")", R"("""")"}, "_");
 | 
				
			||||||
 | 
					    case_type case2 =
 | 
				
			||||||
 | 
					        spaced_left({R"("x\"x")", R"(x\"x)", R"(x"x)", R"("x""x")"}, "_");
 | 
				
			||||||
 | 
					    case_type case3 = spaced_left({R"("")", R"()"}, "_");
 | 
				
			||||||
 | 
					    case_type case4 = spaced_left({R"("x")", R"(x)"}, "_");
 | 
				
			||||||
 | 
					    case_type case5 =
 | 
				
			||||||
 | 
					        spaced_right({R"("\"\"")", R"("""""")", R"("\"""")", R"("""\"")"}, "-");
 | 
				
			||||||
 | 
					    case_type case6 = spaced_right({R"("\\")", R"(\\)"}, "-");
 | 
				
			||||||
 | 
					    case_type case7 = spaced_right({R"("xxxxxxxxxx")", R"(xxxxxxxxxx)"}, "-");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    std::vector<std::string> delims = {"::", "\n"};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        matches_type p{{case1, "\""},   {case2, "x\"x"}, {case3, ""},
 | 
				
			||||||
 | 
					                       {case5, "\"\""}, {case6, "\\"},   {case7, "xxxxxxxxxx"}};
 | 
				
			||||||
 | 
					        test_combinations<ss::quote<'"'>, ss::escape<'\\'>, ss::trim_left<'_'>,
 | 
				
			||||||
 | 
					                          ss::trim_right<'-'>>(p, delims);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user