From d94c925765b02ea542935e55efd0a3ac509fae27 Mon Sep 17 00:00:00 2001 From: "Timur A. Fatkhullin" Date: Thu, 23 Jul 2026 11:17:03 +0300 Subject: [PATCH] ... --- examples/net_exam.cpp | 39 +++++++++- examples/str_exam.cpp | 2 +- include/snipplib/network/snplib_netproto.h | 84 +++++++++++++++++++++- include/snipplib/utils/snplib_string.h | 49 ++++++++----- 4 files changed, 151 insertions(+), 23 deletions(-) diff --git a/examples/net_exam.cpp b/examples/net_exam.cpp index 7d6921b..8ca769a 100644 --- a/examples/net_exam.cpp +++ b/examples/net_exam.cpp @@ -1,3 +1,4 @@ +#include #include #include @@ -6,6 +7,8 @@ int main() { + std::println("{:*^80}\n", " STOP-SEQ PROTOCOL "); + snplib::snplib_netproto_stopseq_t<> proto; std::string bytes{"SET VAL1 10\n"}; @@ -38,13 +41,13 @@ int main() } - std::println("\n\n"); + std::println("\n"); bytes = "GET VAL2 1"; bytes_vec = {std::from_range, bytes}; bytes_lst = {std::from_range, bytes}; - std::println("MSG: ", bytes_vec); + std::println("MSG: {}", bytes_vec); auto bs = proto.toBytes(bytes_vec); std::println("BYTES (from std::vector): {}", bs); @@ -55,5 +58,37 @@ int main() bytes_vec = proto.toBytes(bytes_lst); std::println("BYTES: {}", bytes_vec); + + std::println("\n\n{:*^80}\n", " BINARY-BLOB PROTOCOL "); + + snplib::snplib_netproto_binary_blob_t<> bb_proto; + + snplib::snplib_random_string_generator_t<> rstr_gen; + + bytes = rstr_gen.generate(15); + bytes_vec = {std::from_range, bytes}; + bytes_lst = {std::from_range, bytes}; + + std::println("BLOB: {}", bytes); + + bs = bb_proto.toBytes(bytes_vec); + std::println("BYTES (from std::vector): {}", bs); + + auto bs2 = bb_proto.toBytes(bytes_lst); + std::println("BYTES (from std::list): {}", bs2); + + auto blob = std::vector(std::from_range, bs | std::views::join); + + std::println("\nBYTES: {}", blob); + + vmsg = bb_proto.fromBytes>(blob); + if (vmsg) { + std::println("BLOB (from std::vector): {}", vmsg.value()); + } else { + std::println("VMSG ERR: {}", vmsg.error().message()); + } + + // std::array arr = bb_proto.toBytes(bytes_lst); + return 0; } \ No newline at end of file diff --git a/examples/str_exam.cpp b/examples/str_exam.cpp index 1bfbce6..1ed05a7 100644 --- a/examples/str_exam.cpp +++ b/examples/str_exam.cpp @@ -84,7 +84,7 @@ int main() std::println("valueSeq = '{}'", kvl.valueSeq>()); - snplib_randoom_string_generator_t<> rstr_gen; + snplib_random_string_generator_t<> rstr_gen; std::println("\n\n"); std::println("RAND STR: {}", rstr_gen.generate()); diff --git a/include/snipplib/network/snplib_netproto.h b/include/snipplib/network/snplib_netproto.h index 575437b..f2140e6 100644 --- a/include/snipplib/network/snplib_netproto.h +++ b/include/snipplib/network/snplib_netproto.h @@ -102,7 +102,7 @@ struct snplib_netproto_stopseq_t { } else { auto Nelem = std::distance(bytes.begin(), found.begin()); if (Nelem > std::tuple_size_v) { - static_assert(false, "Invalid size of the output byte sequence type!"); + return std::unexpected(std::make_error_code(std::errc::invalid_seek)); } OR res; @@ -145,7 +145,9 @@ template requires(SZ_FIELD_WIDTH > 0 && SZ_FIELD_WIDTH <= 16) // not greater than allowed for 64-bit unsigned integer representation struct snplib_netproto_binary_blob_t { - static constexpr std::array SZ_FIELD_FORMAT{'{', ':', '0', '0' + SZ_FIELD_WIDTH, 'X', '}'}; + static constexpr size_t BLOB_SIZE_FIELD{SZ_FIELD_WIDTH}; + + static constexpr std::array BLOB_SIZE_FIELD_FORMAT{'{', ':', '0', '0' + BLOB_SIZE_FIELD, 'X', '}'}; template auto toBytes(IR&& message) @@ -154,7 +156,7 @@ struct snplib_netproto_binary_blob_t { Nbytes.clear(); // std::format_to(std::back_inserter(Nbytes), "{:08X}", std::ranges::size(std::forward(message))); - std::format_to(std::back_inserter(Nbytes), std::string_view(SZ_FIELD_FORMAT), + std::format_to(std::back_inserter(Nbytes), std::string_view(BLOB_SIZE_FIELD_FORMAT), std::ranges::size(std::forward(message))); if constexpr (std::ranges::contiguous_range) { @@ -163,6 +165,82 @@ struct snplib_netproto_binary_blob_t { return std::make_tuple(std::ranges::subrange(Nbytes), std::ranges::subrange(message)); } } + + + template + std::expected fromBytes(IR&& bytes) + { + using inp_t = std::remove_cvref_t; + + // return a view + static constexpr bool ret_view = + std::ranges::view && std::ranges::viewable_range && + (std::constructible_from, std::ranges::iterator_t> || + std::constructible_from, std::ranges::sentinel_t>); + + + auto bytes_sz = std::ranges::size(std::forward(bytes)); + + if (bytes_sz < BLOB_SIZE_FIELD) { // not enough data + return std::unexpected(std::make_error_code(std::errc::invalid_seek)); + } + + std::optional blob_sz; + if constexpr (std::ranges::contiguous_range) { + blob_sz = snplib_num_from_range(std::span(bytes.begin(), BLOB_SIZE_FIELD), 16); + } else { + blob_sz = snplib_num_from_range(bytes | std::views::take(BLOB_SIZE_FIELD), 16); + } + + if (!blob_sz) { + return std::unexpected(std::make_error_code(std::errc::invalid_argument)); + } + + bytes_sz -= BLOB_SIZE_FIELD; + + if (bytes_sz < blob_sz.value()) { + return std::unexpected(std::make_error_code(std::errc::invalid_seek)); + } + + auto it_start = std::forward(bytes).begin(); + std::advance(it_start, BLOB_SIZE_FIELD); + auto it_end = std::forward(bytes).begin(); + std::advance(it_end, BLOB_SIZE_FIELD + blob_sz.value()); + + if constexpr (ret_view) { + return OR(it_start, it_end); // return without blob size field + } else if constexpr (snplib_output_char_range_c) { + if constexpr (!snplib_fixed_size_range_c) { + if constexpr (std::constructible_from, + std::ranges::iterator_t>) { + return OR(it_start, it_end); // return without blob size field!!! + } else if constexpr (std::is_default_constructible_v) { + OR res; + std::ranges::copy( + std::forward(bytes) | std::views::drop(BLOB_SIZE_FIELD) | std::views::take(blob_sz.value()), + std::back_inserter(res)); + + return res; + } else { + static_assert(false, "Unsupported output byte sequence type!"); + } + } else { + if (blob_sz.value() > std::tuple_size_v) { + return std::unexpected(std::make_error_code(std::errc::invalid_seek)); + } + + OR res; + for (auto it = res.begin(); it != res.end(); std::advance(it, 1)) { + *it = *it_start; + std::advance(it_start, 1); + } + + return res; + } + } else { + static_assert(false, "Unsupported output byte sequence type!"); + } + } }; } // namespace snplib \ No newline at end of file diff --git a/include/snipplib/utils/snplib_string.h b/include/snipplib/utils/snplib_string.h index 75db433..ecd5dda 100644 --- a/include/snipplib/utils/snplib_string.h +++ b/include/snipplib/utils/snplib_string.h @@ -290,15 +290,30 @@ OR snplib_join_char_ranges(IR&& input, DR&& delim, size_t start = 0, size_t N = } + template -static std::optional snplib_num_from_range(R&& r) - requires((std::integral || std::floating_point) && std::ranges::contiguous_range) +static std::optional snplib_num_from_range( + R&& r, + std::conditional_t, int, std::chars_format> fmt = + []() { + if constexpr (std::integral) + return 10; + else + return std::chars_format::general; + }()) + requires(std::integral || std::floating_point) { + if constexpr (!std::ranges::contiguous_range) { + std::string sval(std::from_range, std::forward(r)); + + return snplib_num_from_range(sval); + } + T val; const char* end_ptr = &*r.end(); if constexpr (std::integral) { - auto cvt_res = std::from_chars(&*r.begin(), &*r.end(), val); + auto cvt_res = std::from_chars(&*r.begin(), &*r.end(), val, fmt); if (cvt_res.ec != std::errc()) { return std::nullopt; } else if (cvt_res.ptr != end_ptr) { @@ -325,7 +340,7 @@ static std::optional snplib_num_from_range(R&& r) return std::nullopt; } #else - auto cvt_res = std::from_chars(&*r.begin(), &*r.end(), val); + auto cvt_res = std::from_chars(&*r.begin(), &*r.end(), val, fmt); if (cvt_res.ec != std::errc()) { return std::nullopt; @@ -344,7 +359,7 @@ static std::optional snplib_num_from_range(R&& r) template -class snplib_randoom_string_generator_t +class snplib_random_string_generator_t { private: std::random_device _randomDev{}; @@ -363,30 +378,30 @@ public: static constexpr size_t DEFAULT_RANDOM_STR_LEN = 32; - snplib_randoom_string_generator_t() : _randomGen(_randomDev()) {} + snplib_random_string_generator_t() : _randomGen(_randomDev()) {} template - snplib_randoom_string_generator_t(SEED_T seed) : _randomGen(seed) + snplib_random_string_generator_t(SEED_T seed) : _randomGen(seed) { } template - OR generate(size_t len = snplib_randoom_string_generator_t::DEFAULT_RANDOM_STR_LEN, - IR char_range = snplib_randoom_string_generator_t::DEFAULT_RANDOM_CHAR_RANGE) + snplib_input_char_range_c IR = decltype(snplib_random_string_generator_t::DEFAULT_RANDOM_CHAR_RANGE)> + OR generate(size_t len = snplib_random_string_generator_t::DEFAULT_RANDOM_STR_LEN, + IR char_range = snplib_random_string_generator_t::DEFAULT_RANDOM_CHAR_RANGE) { OR res; size_t max_idx = std::ranges::size(char_range); if (max_idx < 2) { - char_range = snplib_randoom_string_generator_t::DEFAULT_RANDOM_CHAR_RANGE; - max_idx = snplib_randoom_string_generator_t::DEFAULT_RANDOM_CHAR_RANGE.size(); + char_range = snplib_random_string_generator_t::DEFAULT_RANDOM_CHAR_RANGE; + max_idx = snplib_random_string_generator_t::DEFAULT_RANDOM_CHAR_RANGE.size(); } std::uniform_int_distribution rdist(0, --max_idx); if (!len) { - len = snplib_randoom_string_generator_t::DEFAULT_RANDOM_STR_LEN; + len = snplib_random_string_generator_t::DEFAULT_RANDOM_STR_LEN; } for (size_t i = 0; i < len; ++i) { @@ -396,9 +411,9 @@ public: return res; } - template - std::string generate(size_t len = snplib_randoom_string_generator_t::DEFAULT_RANDOM_STR_LEN, - IR char_range = snplib_randoom_string_generator_t::DEFAULT_RANDOM_CHAR_RANGE) + template + std::string generate(size_t len = snplib_random_string_generator_t::DEFAULT_RANDOM_STR_LEN, + IR char_range = snplib_random_string_generator_t::DEFAULT_RANDOM_CHAR_RANGE) { return generate(len, char_range); } @@ -406,7 +421,7 @@ public: template OR UUIDv4String() { - OR res = generate(36, snplib_randoom_string_generator_t::UUID_STRING_RANGE); + OR res = generate(36, snplib_random_string_generator_t::UUID_STRING_RANGE); auto iter = res.begin(); size_t i = 0; for (size_t idx : std::array{8, 13, 18, 23}) {