mirror of
https://github.com/red0124/ssp.git
synced 2025-12-14 21:59:55 +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:
@@ -1,4 +1,5 @@
|
||||
#pragma once
|
||||
#include "common.hpp"
|
||||
#include "setup.hpp"
|
||||
#include "type_traits.hpp"
|
||||
#include <algorithm>
|
||||
@@ -10,16 +11,12 @@
|
||||
|
||||
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>
|
||||
class splitter {
|
||||
private:
|
||||
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;
|
||||
|
||||
constexpr static auto string_error = setup<Ts...>::string_error;
|
||||
@@ -39,8 +36,7 @@ public:
|
||||
}
|
||||
|
||||
const std::string& error_msg() const {
|
||||
static_assert(string_error,
|
||||
"'string_error' needs to be enabled to use 'error_msg'");
|
||||
assert_string_error_defined<string_error>();
|
||||
return error_;
|
||||
}
|
||||
|
||||
@@ -48,9 +44,9 @@ public:
|
||||
return unterminated_quote_;
|
||||
}
|
||||
|
||||
const split_input& split(line_ptr_type new_line,
|
||||
const std::string& delimiter = default_delimiter) {
|
||||
split_input_.clear();
|
||||
const split_data& split(line_ptr_type new_line,
|
||||
const std::string& delimiter = default_delimiter) {
|
||||
split_data_.clear();
|
||||
return resplit(new_line, -1, delimiter);
|
||||
}
|
||||
|
||||
@@ -60,32 +56,34 @@ private:
|
||||
////////////////
|
||||
|
||||
void adjust_ranges(const char* old_line) {
|
||||
for (auto& [begin, end] : split_input_) {
|
||||
for (auto& [begin, end] : split_data_) {
|
||||
begin = begin - 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,
|
||||
const std::string& delimiter = default_delimiter) {
|
||||
line_ = new_line;
|
||||
|
||||
// resplitting, continue from last slice
|
||||
if (!split_input_.empty() && unterminated_quote()) {
|
||||
const auto& last = std::prev(split_input_.end());
|
||||
const auto [old_line, old_begin] = *last;
|
||||
size_t begin = old_begin - old_line - 1;
|
||||
split_input_.pop_back();
|
||||
adjust_ranges(old_line);
|
||||
if constexpr (quote::enabled) {
|
||||
if (!split_data_.empty() && unterminated_quote()) {
|
||||
const auto& last = std::prev(split_data_.end());
|
||||
const auto [old_line, old_begin] = *last;
|
||||
size_t begin = old_begin - old_line - 1;
|
||||
split_data_.pop_back();
|
||||
adjust_ranges(old_line);
|
||||
|
||||
// safety measure
|
||||
if (new_size != -1 && static_cast<size_t>(new_size) < begin) {
|
||||
set_error_invalid_resplit();
|
||||
return split_input_;
|
||||
// safety measure
|
||||
if (new_size != -1 && static_cast<size_t>(new_size) < begin) {
|
||||
set_error_invalid_resplit();
|
||||
return split_data_;
|
||||
}
|
||||
|
||||
begin_ = line_ + begin;
|
||||
}
|
||||
|
||||
begin_ = line_ + begin;
|
||||
}
|
||||
|
||||
return split_impl_select_delim(delimiter);
|
||||
@@ -163,9 +161,17 @@ private:
|
||||
return delim.size();
|
||||
}
|
||||
|
||||
void trim_if_enabled(line_ptr_type& curr) {
|
||||
if constexpr (trim::enabled) {
|
||||
while (trim::match(*curr)) {
|
||||
void trim_left_if_enabled(line_ptr_type& curr) {
|
||||
if constexpr (trim_left::enabled) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -176,7 +182,7 @@ private:
|
||||
const Delim& delim) {
|
||||
line_ptr_type end = begin;
|
||||
|
||||
trim_if_enabled(end);
|
||||
trim_right_if_enabled(end);
|
||||
|
||||
// just spacing
|
||||
if (*end == '\0') {
|
||||
@@ -190,7 +196,7 @@ private:
|
||||
}
|
||||
|
||||
end += delimiter_size(delim);
|
||||
trim_if_enabled(end);
|
||||
trim_left_if_enabled(end);
|
||||
|
||||
// delimiter
|
||||
return {end - begin, true};
|
||||
@@ -213,7 +219,7 @@ private:
|
||||
|
||||
void shift_and_push() {
|
||||
shift_and_set_current();
|
||||
split_input_.emplace_back(begin_, curr_);
|
||||
split_data_.emplace_back(begin_, curr_);
|
||||
}
|
||||
|
||||
void shift_if_escaped(line_ptr_type& curr) {
|
||||
@@ -241,13 +247,13 @@ private:
|
||||
// split impl
|
||||
////////////////
|
||||
|
||||
const split_input& split_impl_select_delim(
|
||||
const split_data& split_impl_select_delim(
|
||||
const std::string& delimiter = default_delimiter) {
|
||||
clear_error();
|
||||
switch (delimiter.size()) {
|
||||
case 0:
|
||||
set_error_empty_delimiter();
|
||||
return split_input_;
|
||||
return split_data_;
|
||||
case 1:
|
||||
return split_impl(delimiter[0]);
|
||||
default:
|
||||
@@ -256,18 +262,18 @@ private:
|
||||
}
|
||||
|
||||
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_;
|
||||
}
|
||||
|
||||
trim_if_enabled(begin_);
|
||||
trim_left_if_enabled(begin_);
|
||||
|
||||
for (done_ = false; !done_; read(delim))
|
||||
;
|
||||
|
||||
return split_input_;
|
||||
return split_data_;
|
||||
}
|
||||
|
||||
////////////////
|
||||
@@ -329,7 +335,7 @@ private:
|
||||
// eg: ..."hell\0 -> quote not terminated
|
||||
if (*end_ == '\0') {
|
||||
set_error_unterminated_quote();
|
||||
split_input_.emplace_back(line_, begin_);
|
||||
split_data_.emplace_back(line_, begin_);
|
||||
done_ = true;
|
||||
break;
|
||||
}
|
||||
@@ -363,7 +369,7 @@ private:
|
||||
// mismatched quote
|
||||
// eg: ...,"hel"lo,... -> error
|
||||
set_error_mismatched_quote(end_ - line_);
|
||||
split_input_.emplace_back(line_, begin_);
|
||||
split_data_.emplace_back(line_, begin_);
|
||||
}
|
||||
done_ = true;
|
||||
break;
|
||||
@@ -375,17 +381,16 @@ private:
|
||||
// members
|
||||
////////////////
|
||||
|
||||
static_assert(std::is_same_v<error_type, bool> ||
|
||||
std::is_same_v<error_type, std::string>);
|
||||
error_type error_;
|
||||
error_type error_{};
|
||||
bool unterminated_quote_{false};
|
||||
bool done_;
|
||||
size_t escaped_{0};
|
||||
split_data split_data_;
|
||||
|
||||
line_ptr_type begin_;
|
||||
line_ptr_type curr_;
|
||||
line_ptr_type end_;
|
||||
line_ptr_type line_;
|
||||
bool done_;
|
||||
size_t escaped_{0};
|
||||
split_input split_input_;
|
||||
|
||||
template <typename...>
|
||||
friend class converter;
|
||||
|
||||
Reference in New Issue
Block a user