diff --git a/examples/str_exam.cpp b/examples/str_exam.cpp index 4aa1bca..8a29a16 100644 --- a/examples/str_exam.cpp +++ b/examples/str_exam.cpp @@ -1,12 +1,16 @@ +#include #include + // #include "../utils/snplib_string.h" // #include "../include/snipplib/snplib_string.h" +#include #include using namespace snplib; int main() { std::string si = " dewf wek e lwekjflkj "; + std::println("s = '{}'", si); auto s = snplib_trim_spaces(si); @@ -24,6 +28,15 @@ int main() std::println("sv(TrimType::TRIM_BOTH) = '{}'", sv); + const char cstr[] = " dwelkj 3827 dwjh 2398 "; + std::println("C-ish string: '{}'", cstr); + std::println("C-ish(TrimType::TRIM_BOTH) = '{}'", snplib_trim_spaces_as_view(cstr)); + + std::list ll{' ', ' ', '2', ' ', 'e', '4', 's', ' ', ' '}; + std::println("std::list: {}", ll); + std::println("std::ranges::subrange(TrimType::TRIM_BOTH) = '{}'", snplib_trim_spaces_as_view(ll)); + // std::println("std::ranges::subrange(TrimType::TRIM_BOTH) = '{}'", + // std::views::all(snplib_trim_spaces_as_view(ll))); si = "123; we; d34534; "; @@ -32,16 +45,45 @@ int main() std::println("\n\nstr = '{}'", si); - std::println("all elems: "); + std::print("all elems: "); for (auto& el : rv) { - std::println("el = '{}'", el); + std::print("'{}' ", el); } + std::println(""); rv = snplib_split_char_range(si, "; ", 1, 2); - std::println("2 elems starting from 1: "); + std::print("2 elems starting from 1: "); for (auto& el : rv) { - std::println("el = '{}'", el); + std::print("'{}' ", el); } + std::println(""); + + + si = " ATTR AAA 1.1 23 45 09 "; + std::vector v{std::from_range, si}; + ll = {std::from_range, si}; + + snplib_keyvalue_t kv{v}; + + std::println("\n\nKV = {}", v); + std::println("key = '{}'", kv.key()); + std::println("value = '{}'", kv.value()); + std::println("valueSeq = '{}'", kv.valueSeq()); + std::println("valueJoinSeq = '{}'", kv.valueJoinSeq(3, 3)); + std::println("valueJoinSeq = '{}'", kv.valueJoinSeq(3, 30)); + kv.setKeyValue("VAL", std::make_tuple(1, std::string{"RRR"}, 10.24)); + std::println("\n\nKV = {}", v); + + snplib_keyvalue_t kvl{ll}; + + std::println("\n\nKV = {}", ll); + std::println("key = '{}'", kvl.key()); + std::println("key = '{}'", kvl.key()); + std::println("value = '{}'", kvl.value()); + std::println("valueSeq = '{}'", kvl.valueSeq()); + std::println("valueSeq = '{}'", kvl.valueSeq>()); + + return 0; } \ No newline at end of file diff --git a/include/snipplib/concepts/snplib_concepts.h b/include/snipplib/concepts/snplib_concepts.h index 504672a..9bcca7a 100644 --- a/include/snipplib/concepts/snplib_concepts.h +++ b/include/snipplib/concepts/snplib_concepts.h @@ -127,7 +127,7 @@ template concept snplib_error_c = std::constructible_from && requires(T&& t) { static_cast(std::forward(t)); - { !std::forward(t) } -> std::convertible_to; + // { !std::forward(t) } -> std::convertible_to; }; // utility function to deduce error-type diff --git a/include/snipplib/serialization/snplib_serialization.h b/include/snipplib/serialization/snplib_serialization.h index e6535fb..23cfa9a 100644 --- a/include/snipplib/serialization/snplib_serialization.h +++ b/include/snipplib/serialization/snplib_serialization.h @@ -214,6 +214,16 @@ struct snplib_deserializer_error_category_t : public std::error_category { }; +inline std::error_code make_error_code(snplib_serializer_error_e ec) +{ + return std::error_code(static_cast(ec), snplib_serializer_error_category_t::get()); +} + +inline std::error_code make_error_code(snplib_deserializer_error_e ec) +{ + return std::error_code(static_cast(ec), snplib_deserializer_error_category_t::get()); +} + /* BASE SERIALIZER CLASS (FOR IMPLEMENTATIONS BELOW) */ @@ -370,7 +380,7 @@ struct snplib_serializer_t : snplib_serializer_base_t { return snplib_serializer_base_t::serializeRange(sr, value, output, params); } } else if constexpr (snplib_tuple_like_c) { - return [&output, ¶ms](this auto& self, VT& tp) -> error_t { + return [&output, ¶ms](this auto&& self, VT const& tp) -> error_t { if constexpr (I < (std::tuple_size_v - 1)) { auto err = snplib_serializer_t>{}(output, std::get(tp), params); if (err) { @@ -379,8 +389,9 @@ struct snplib_serializer_t : snplib_serializer_base_t { snplib_serializer_base_t::addElemDelimiter(output, params); - return self.template operator()(tp); - } else if constexpr (I < (std::tuple_size_v - 1)) { // the last element + return std::forward(self).template operator()(tp); + // } else if constexpr (I < (std::tuple_size_v - 1)) { // the last element + } else { // the last element auto err = snplib_serializer_t>{}(output, std::get(tp), params); if (err) { return snplib_deduced_error(err, snplib_serializer_error_e::ERROR_UNDERLYING_SERIALIZER); diff --git a/include/snipplib/utils/snplib_keyvalue.h b/include/snipplib/utils/snplib_keyvalue.h index 7295a76..6293e83 100644 --- a/include/snipplib/utils/snplib_keyvalue.h +++ b/include/snipplib/utils/snplib_keyvalue.h @@ -11,11 +11,12 @@ concept snplib_serializable_c = requires { [](std::type_identity) {}(std::type_identity>{}); }; template + requires(std::ranges::viewable_range && !std::ranges::borrowed_range) class snplib_keyvalue_t { public: static constexpr bool mutableContent = snplib_output_char_range_c; - static constexpr bool stringViewContent = + static constexpr bool contiguousContent = std::ranges::viewable_range && std::ranges::contiguous_range; typedef std::error_code error_t; @@ -28,79 +29,100 @@ public: std::string_view valseq_delim{DEFAULT_VALSEQ_DELIM_SEQ}; }; - constexpr snplib_keyvalue_t(ByteSeqT&& bytes, config_t cfg = config_t{}) {} + constexpr snplib_keyvalue_t(ByteSeqT& bytes, config_t cfg = config_t{}) : _byteSeq(bytes), _config(cfg) + { + fromByteSequence(bytes, cfg); + } virtual ~snplib_keyvalue_t() = default; - template - requires mutableContent - error_t fromByteSequence(R&& bytes) + error_t fromByteSequence(ByteSeqT& bytes, config_t cfg = config_t{}) { + _byteSeq = bytes; + _config = cfg; + // key and value - if constexpr (stringViewContent) { - auto bs = snplib_trim_spaces_as_view(bytes, TrimType::TRIM_LEFT); - auto found = std::ranges::search(bs, _config.keyval_delim); + auto bs = snplib_trim_spaces_as_view(bytes, TrimType::TRIM_LEFT); + auto found = std::ranges::search(bs, _config.keyval_delim); - if (found.empty()) { // no value - _key = snplib_trim_spaces_as_view(bs, TrimType::TRIM_RIGHT); + if (found.empty()) { // no value + _key = snplib_trim_spaces_as_view(bs, TrimType::TRIM_RIGHT); - _value = std::string_view(); - } else { - _key = snplib_trim_spaces_as_view(std::string_view(bs.begin(), found.begin()), TrimType::TRIM_RIGHT); + _value = decltype(_value)(); + } else { + _key = snplib_trim_spaces_as_view(decltype(_key)(bs.begin(), found.begin()), TrimType::TRIM_RIGHT); - // do not delete space at the end of value-string! - _value = std::string_view(found.end(), bs.end()); - } - - } else if constexpr (std::ranges::viewable_range) { - auto bs = bytes | std::views::drop_while(snplib_is_space); - auto found = std::ranges::search(bs, _config.keyval_delim); - - _value.clear(); - - if (found.empty()) { // no value - _key = snplib_trim_spaces(bs, TrimType::TRIM_RIGHT); - } else { - _key.clear(); - auto N = std::ranges::distance(bs.begin(), found.begin()); - std::ranges::copy(std::views::all(bs) | std::views::take(N) | std::views::reverse | - std::views::drop_while(snplib_is_space), - std::back_inserter(_key)); - - std::ranges::copy(found.end(), bs.end(), std::back_inserter(_value)); - } - } else { // always coping - auto bs = snplib_trim_spaces(bytes, TrimType::TRIM_LEFT); - auto found = std::ranges::search(bs, _config.keyval_delim); - - _value.clear(); - - if (found.empty()) { // no value - _key = snplib_trim_spaces(bs, TrimType::TRIM_RIGHT); - } else { - _key.clear; - auto N = std::ranges::distance(bs.begin(), found.begin()); - // std::ranges::copy_n(bs.begin(), N, std::back_inserter(_key)); - - size_t i = 0; - for (auto it = bs.begin(); it != found.begin(); ++it, ++i) { - if (i < N) { - if (!snplib_is_space(*it)) { - std::back_inserter(_key) = *it; - } - } - } - } - - std::ranges::copy(found.end(), bs.end(), std::back_inserter(_value)); + // do not delete space at the end of value-string! + _value = decltype(_value)(found.end(), bs.end()); } + + // if constexpr (contiguousContent) { + // auto bs = snplib_trim_spaces_as_view(bytes, TrimType::TRIM_LEFT); + // auto found = std::ranges::search(bs, _config.keyval_delim); + + // if (found.empty()) { // no value + // _key = snplib_trim_spaces_as_view(bs, TrimType::TRIM_RIGHT); + + // _value = std::string_view(); + // } else { + // _key = snplib_trim_spaces_as_view(std::string_view(bs.begin(), found.begin()), TrimType::TRIM_RIGHT); + + // // do not delete space at the end of value-string! + // _value = std::string_view(found.end(), bs.end()); + // } + + // } else if constexpr (std::ranges::viewable_range) { + // auto bs = bytes | std::views::drop_while(snplib_is_space); + // auto found = std::ranges::search(bs, _config.keyval_delim); + + // _value.clear(); + + // if (found.empty()) { // no value + // _key = snplib_trim_spaces(bs, TrimType::TRIM_RIGHT); + // } else { + // _key.clear(); + // auto N = std::ranges::distance(bs.begin(), found.begin()); + // std::ranges::copy(std::views::all(bs) | std::views::take(N) | std::views::reverse | + // std::views::drop_while(snplib_is_space), + // std::back_inserter(_key)); + + // std::ranges::copy(found.end(), bs.end(), std::back_inserter(_value)); + // } + // } else { // always coping + // auto bs = snplib_trim_spaces(bytes, TrimType::TRIM_LEFT); + // auto found = std::ranges::search(bs, _config.keyval_delim); + + // _value.clear(); + + // if (found.empty()) { // no value + // _key = snplib_trim_spaces(bs, TrimType::TRIM_RIGHT); + // } else { + // _key.clear; + // auto N = std::ranges::distance(bs.begin(), found.begin()); + // // std::ranges::copy_n(bs.begin(), N, std::back_inserter(_key)); + + // size_t i = 0; + // for (auto it = bs.begin(); it != found.begin(); ++it, ++i) { + // if (i < N) { + // if (!snplib_is_space(*it)) { + // std::back_inserter(_key) = *it; + // } + // } + // } + // } + + // std::ranges::copy(found.end(), bs.end(), std::back_inserter(_value)); + // } + // split value to elements - if (_value.size()) { + if (!_value.empty()) { _valueSeq = snplib_split_char_range(_value, _config.valseq_delim); } + + return {}; } template @@ -109,9 +131,9 @@ public: return snplib_transform_char_range(_key); } - constexpr std::string_view key() const + constexpr auto key() const { - return key(); + return _key; } template @@ -120,9 +142,9 @@ public: return snplib_transform_char_range(_value); } - constexpr std::string_view value() const + constexpr auto value() const { - return value(); + return _value; } @@ -147,9 +169,11 @@ public: std::ranges::for_each(elems, [&res](auto const& e) { if constexpr (std::constructible_from) { - std::back_inserter(el_t{e.cbegin(), e.cend()}, std::back_inserter(res)); + // std::back_inserter(el_t{e.cbegin(), e.cend()}, std::back_inserter(res)); + std::back_inserter(res) = el_t{e.cbegin(), e.cend()}; } else if constexpr (std::constructible_from) { - std::back_inserter(el_t{e}, std::back_inserter(res)); + // std::back_inserter(el_t{e}, std::back_inserter(res)); + std::back_inserter(res) = el_t{e}; } else { static_assert(false, "Incompatible types: cannot create output element!"); } @@ -159,9 +183,11 @@ public: return res; } - std::vector valueSeq(size_t start = 0, size_t N = std::numeric_limits::max()) const + auto valueSeq(size_t start = 0, size_t N = std::numeric_limits::max()) const + // std::vector valueSeq(size_t start = 0, size_t N = std::numeric_limits::max()) const { - return valueSeq>(start, N); + // return valueSeq>(start, N); + return _valueSeq; } @@ -172,7 +198,7 @@ public: return OR(); } - auto last_idx = start + N; + auto last_idx = start + N - 1; if (last_idx >= _valueSeq.size()) { last_idx = _valueSeq.size() - 1; } @@ -197,24 +223,30 @@ public: requires mutableContent error_t setKey(KeyT&& key, SParT const& sparams = snplib_serialization_params_t{}) { - auto err = snplib_serializer_t>(_key, std::forward(key), sparams); + _byteSeq.clear(); + auto err = snplib_serializer_t>{}(_byteSeq, std::forward(key), sparams); if (err) { - return snplib_deduced_error(err, std::errc::invalid_argument); + // return snplib_deduced_error(err, std::errc::invalid_argument); + // return snplib_deduced_error(err, std::make_error_code(std::errc::invalid_argument)); + return std::make_error_code(std::errc::invalid_argument); } return {}; + // return std::make_error_code(std::errc{}); } template requires mutableContent error_t setValue(ValueT&& value, SParT const& sparams = snplib_serialization_params_t{}) { - auto err = snplib_serializer_t>(_key, std::forward(value), sparams); + auto err = snplib_serializer_t>{}(_byteSeq, std::forward(value), sparams); if (err) { - return snplib_deduced_error(err, std::errc::invalid_argument); + // return snplib_deduced_error(err, std::make_error_code(std::errc::invalid_argument)); + return std::make_error_code(std::errc::invalid_argument); } return {}; + // return std::make_error_code(std::errc{}); } @@ -229,22 +261,25 @@ public: return err; } - return setValue(std::forward(value), sparams); + return setValue(std::forward(value), sparams); } protected: - std:: - conditional_t> - _key; - std:: - conditional_t> - _value; - std::vector _valueSeq; - // std::conditional_t, - // std::conditional_t, - // std::vector>> - // _valueSeq; + ByteSeqT& _byteSeq; + + // std:: + // conditional_t> + // _key; + // std:: + // conditional_t> + // _value; + std::conditional_t> _key; + std::conditional_t> _value; + // std::conditional_t> _key; + // std::conditional_t> _value; + std::vector _valueSeq; config_t _config; }; diff --git a/include/snipplib/utils/snplib_string.h b/include/snipplib/utils/snplib_string.h index 296bc90..189658d 100644 --- a/include/snipplib/utils/snplib_string.h +++ b/include/snipplib/utils/snplib_string.h @@ -15,7 +15,7 @@ constexpr static bool snplib_is_space(char in) noexcept }; -enum class TrimType { TRIM_LEFT, TRIM_RIGHT, TRIM_BOTH }; +enum class TrimType { TRIM_LEFT = 0b1, TRIM_RIGHT = 0b10, TRIM_BOTH = 0b11 }; template constexpr static OR snplib_trim_spaces(R&& r, @@ -45,38 +45,72 @@ constexpr static std::string snplib_trim_spaces(R&& r, return snplib_trim_spaces(std::forward(r), type, std::forward(is_space_func)); } -template -constexpr static std::string_view snplib_trim_spaces_as_view(R&& r, - TrimType type = TrimType::TRIM_BOTH, - IsSpaceFuncT&& is_space_func = snplib_is_space) - requires std::ranges::contiguous_range +// template +// constexpr static std::string_view snplib_trim_spaces_as_view(R&& r, +// TrimType type = TrimType::TRIM_BOTH, +// IsSpaceFuncT&& is_space_func = snplib_is_space) +// requires std::ranges::contiguous_range +// { +// auto end = std::forward(r).end(); + +// auto f1 = std::forward(r).begin(); + +// if (type != TrimType::TRIM_RIGHT) { +// // look for the first non-space symbol +// f1 = std::ranges::find_if_not(std::forward(r), std::forward(is_space_func)); +// if (f1 == end) { // all are spaces! +// return std::string_view(); +// } +// } + +// auto f2 = end; + +// if (type != TrimType::TRIM_LEFT) { +// auto f3 = f1; + +// do { +// f2 = std::ranges::find_if(++f3, end, std::forward(is_space_func)); +// if (f2 == end) +// break; +// f3 = std::ranges::find_if_not(f2 + 1, end, std::forward(is_space_func)); +// } while (f3 != end); +// } + +// return std::string_view(f1, f2); +// } + + +template + requires(snplib_char_range_c && std::ranges::borrowed_range) +constexpr static auto snplib_trim_spaces_as_view(R&& r, + TrimType type = TrimType::TRIM_BOTH, + IsSpaceFuncT&& is_space_func = snplib_is_space) { - auto end = std::forward(r).end(); + if constexpr (std::is_pointer_v>) { // char*, const char*, char[] ('\0' terminates C-ish string) + return snplib_trim_spaces_as_view(std::string_view(std::forward(r)), type, + std::forward(is_space_func)); + } else { + auto it_left = r.begin(); + auto it_right = r.end(); - auto f1 = std::forward(r).begin(); + if (std::to_underlying(type) & std::to_underlying(TrimType::TRIM_LEFT)) { + it_left = std::ranges::find_if_not(std::forward(r), std::forward(is_space_func)); + } - if (type != TrimType::TRIM_RIGHT) { - // look for the first non-space symbol - f1 = std::ranges::find_if_not(std::forward(r), std::forward(is_space_func)); - if (f1 == end) { // all are spaces! - return std::string_view(); + if (std::to_underlying(type) & std::to_underlying(TrimType::TRIM_RIGHT)) { + auto found = std::ranges::find_last_if_not(std::forward(r), std::forward(is_space_func)); + if (!found.empty()) { + it_right = std::next(found.begin()); + } + } + + if constexpr (std::ranges::contiguous_range>) { + return std::string_view{it_left, it_right}; + } else { + return std::ranges::subrange{it_left, it_right}; + // return std::views::all_t>(std::ranges::subrange{it_left, it_right}); } } - - auto f2 = end; - - if (type != TrimType::TRIM_LEFT) { - auto f3 = f1; - - do { - f2 = std::ranges::find_if(++f3, end, std::forward(is_space_func)); - if (f2 == end) - break; - f3 = std::ranges::find_if_not(f2 + 1, end, std::forward(is_space_func)); - } while (f3 != end); - } - - return std::string_view(f1, f2); } @@ -113,13 +147,21 @@ static constexpr OR snplib_transform_char_range(IR&& r, CTorTs&&... or_ctor_args { using val_t = std::remove_cvref_t; + static constexpr bool ret_view = snplib_char_view_c && std::ranges::viewable_range; + if constexpr (std::same_as) { // just a copy return r; - } else if constexpr (snplib_char_view_c && std::ranges::viewable_range) { + } else if constexpr (ret_view && + (std::constructible_from, std::ranges::iterator_t> || + std::constructible_from, + std::ranges::sentinel_t>)) { return OR{r.begin(), r.end()}; - } else if (snplib_output_char_range_c) { + } else if constexpr (std::constructible_from) { + return OR(std::forward(r)); + } else if constexpr (snplib_output_char_range_c) { OR res(std::forward(or_ctor_args)...); std::ranges::copy(std::forward(r), std::back_inserter(res)); + return res; } else { static_assert(false, "Incompatible types!"); } @@ -154,8 +196,10 @@ static constexpr OR snplib_split_char_range(IR&& input, using el_t = std::ranges::range_value_t; using it_t = std::ranges::iterator_t; - static_assert(std::constructible_from, + static_assert(std::constructible_from, "Incompatible input and output types: cannot create element!"); + // static_assert(std::constructible_from, + // "Incompatible input and output types: cannot create element!"); auto it = input.begin();