This commit is contained in:
2026-07-23 11:17:03 +03:00
parent 4b3718f7af
commit d94c925765
4 changed files with 151 additions and 23 deletions

View File

@@ -1,3 +1,4 @@
#include <algorithm>
#include <list> #include <list>
#include <print> #include <print>
@@ -6,6 +7,8 @@
int main() int main()
{ {
std::println("{:*^80}\n", " STOP-SEQ PROTOCOL ");
snplib::snplib_netproto_stopseq_t<> proto; snplib::snplib_netproto_stopseq_t<> proto;
std::string bytes{"SET VAL1 10\n"}; 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 = "GET VAL2 1";
bytes_vec = {std::from_range, bytes}; bytes_vec = {std::from_range, bytes};
bytes_lst = {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); auto bs = proto.toBytes(bytes_vec);
std::println("BYTES (from std::vector): {}", bs); std::println("BYTES (from std::vector): {}", bs);
@@ -55,5 +58,37 @@ int main()
bytes_vec = proto.toBytes<decltype(bytes_vec)>(bytes_lst); bytes_vec = proto.toBytes<decltype(bytes_vec)>(bytes_lst);
std::println("BYTES: {}", bytes_vec); 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<std::vector<char>>(blob);
if (vmsg) {
std::println("BLOB (from std::vector): {}", vmsg.value());
} else {
std::println("VMSG ERR: {}", vmsg.error().message());
}
// std::array<char, 30> arr = bb_proto.toBytes<decltype(arr)>(bytes_lst);
return 0; return 0;
} }

View File

@@ -84,7 +84,7 @@ int main()
std::println("valueSeq = '{}'", kvl.valueSeq<std::list<std::string>>()); std::println("valueSeq = '{}'", kvl.valueSeq<std::list<std::string>>());
snplib_randoom_string_generator_t<> rstr_gen; snplib_random_string_generator_t<> rstr_gen;
std::println("\n\n"); std::println("\n\n");
std::println("RAND STR: {}", rstr_gen.generate()); std::println("RAND STR: {}", rstr_gen.generate());

View File

@@ -102,7 +102,7 @@ struct snplib_netproto_stopseq_t {
} else { } else {
auto Nelem = std::distance(bytes.begin(), found.begin()); auto Nelem = std::distance(bytes.begin(), found.begin());
if (Nelem > std::tuple_size_v<OR>) { if (Nelem > std::tuple_size_v<OR>) {
static_assert(false, "Invalid size of the output byte sequence type!"); return std::unexpected(std::make_error_code(std::errc::invalid_seek));
} }
OR res; OR res;
@@ -145,7 +145,9 @@ template <size_t SZ_FIELD_WIDTH = 8>
requires(SZ_FIELD_WIDTH > 0 && requires(SZ_FIELD_WIDTH > 0 &&
SZ_FIELD_WIDTH <= 16) // not greater than allowed for 64-bit unsigned integer representation SZ_FIELD_WIDTH <= 16) // not greater than allowed for 64-bit unsigned integer representation
struct snplib_netproto_binary_blob_t { struct snplib_netproto_binary_blob_t {
static constexpr std::array<char, 6> SZ_FIELD_FORMAT{'{', ':', '0', '0' + SZ_FIELD_WIDTH, 'X', '}'}; static constexpr size_t BLOB_SIZE_FIELD{SZ_FIELD_WIDTH};
static constexpr std::array<char, 6> BLOB_SIZE_FIELD_FORMAT{'{', ':', '0', '0' + BLOB_SIZE_FIELD, 'X', '}'};
template <snplib_input_char_range_c IR> template <snplib_input_char_range_c IR>
auto toBytes(IR&& message) auto toBytes(IR&& message)
@@ -154,7 +156,7 @@ struct snplib_netproto_binary_blob_t {
Nbytes.clear(); Nbytes.clear();
// std::format_to(std::back_inserter(Nbytes), "{:08X}", std::ranges::size(std::forward<IR>(message))); // std::format_to(std::back_inserter(Nbytes), "{:08X}", std::ranges::size(std::forward<IR>(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<IR>(message))); std::ranges::size(std::forward<IR>(message)));
if constexpr (std::ranges::contiguous_range<IR>) { if constexpr (std::ranges::contiguous_range<IR>) {
@@ -163,6 +165,82 @@ struct snplib_netproto_binary_blob_t {
return std::make_tuple(std::ranges::subrange(Nbytes), std::ranges::subrange(message)); return std::make_tuple(std::ranges::subrange(Nbytes), std::ranges::subrange(message));
} }
} }
template <snplib_char_range_c OR, snplib_input_char_range_c IR>
std::expected<OR, std::error_code> fromBytes(IR&& bytes)
{
using inp_t = std::remove_cvref_t<IR>;
// return a view
static constexpr bool ret_view =
std::ranges::view<OR> && std::ranges::viewable_range<inp_t> &&
(std::constructible_from<OR, std::ranges::iterator_t<inp_t>, std::ranges::iterator_t<inp_t>> ||
std::constructible_from<OR, std::ranges::iterator_t<inp_t>, std::ranges::sentinel_t<inp_t>>);
auto bytes_sz = std::ranges::size(std::forward<IR>(bytes));
if (bytes_sz < BLOB_SIZE_FIELD) { // not enough data
return std::unexpected(std::make_error_code(std::errc::invalid_seek));
}
std::optional<size_t> blob_sz;
if constexpr (std::ranges::contiguous_range<IR>) {
blob_sz = snplib_num_from_range<size_t>(std::span(bytes.begin(), BLOB_SIZE_FIELD), 16);
} else {
blob_sz = snplib_num_from_range<size_t>(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<IR>(bytes).begin();
std::advance(it_start, BLOB_SIZE_FIELD);
auto it_end = std::forward<IR>(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<OR>) {
if constexpr (!snplib_fixed_size_range_c<OR>) {
if constexpr (std::constructible_from<OR, std::ranges::iterator_t<inp_t>,
std::ranges::iterator_t<inp_t>>) {
return OR(it_start, it_end); // return without blob size field!!!
} else if constexpr (std::is_default_constructible_v<OR>) {
OR res;
std::ranges::copy(
std::forward<IR>(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<OR>) {
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 } // namespace snplib

View File

@@ -290,15 +290,30 @@ OR snplib_join_char_ranges(IR&& input, DR&& delim, size_t start = 0, size_t N =
} }
template <typename T, snplib_input_char_range_c R> template <typename T, snplib_input_char_range_c R>
static std::optional<T> snplib_num_from_range(R&& r) static std::optional<T> snplib_num_from_range(
requires((std::integral<T> || std::floating_point<T>) && std::ranges::contiguous_range<R>) R&& r,
std::conditional_t<std::integral<T>, int, std::chars_format> fmt =
[]() {
if constexpr (std::integral<T>)
return 10;
else
return std::chars_format::general;
}())
requires(std::integral<T> || std::floating_point<T>)
{ {
if constexpr (!std::ranges::contiguous_range<R>) {
std::string sval(std::from_range, std::forward<R>(r));
return snplib_num_from_range<T>(sval);
}
T val; T val;
const char* end_ptr = &*r.end(); const char* end_ptr = &*r.end();
if constexpr (std::integral<T>) { if constexpr (std::integral<T>) {
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()) { if (cvt_res.ec != std::errc()) {
return std::nullopt; return std::nullopt;
} else if (cvt_res.ptr != end_ptr) { } else if (cvt_res.ptr != end_ptr) {
@@ -325,7 +340,7 @@ static std::optional<T> snplib_num_from_range(R&& r)
return std::nullopt; return std::nullopt;
} }
#else #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()) { if (cvt_res.ec != std::errc()) {
return std::nullopt; return std::nullopt;
@@ -344,7 +359,7 @@ static std::optional<T> snplib_num_from_range(R&& r)
template <std::uniform_random_bit_generator RANDOM_GEN_T = std::mt19937_64> template <std::uniform_random_bit_generator RANDOM_GEN_T = std::mt19937_64>
class snplib_randoom_string_generator_t class snplib_random_string_generator_t
{ {
private: private:
std::random_device _randomDev{}; std::random_device _randomDev{};
@@ -363,30 +378,30 @@ public:
static constexpr size_t DEFAULT_RANDOM_STR_LEN = 32; static constexpr size_t DEFAULT_RANDOM_STR_LEN = 32;
snplib_randoom_string_generator_t() : _randomGen(_randomDev()) {} snplib_random_string_generator_t() : _randomGen(_randomDev()) {}
template <typename SEED_T> template <typename SEED_T>
snplib_randoom_string_generator_t(SEED_T seed) : _randomGen(seed) snplib_random_string_generator_t(SEED_T seed) : _randomGen(seed)
{ {
} }
template <snplib_output_char_range_c OR, template <snplib_output_char_range_c OR,
snplib_input_char_range_c IR = decltype(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_randoom_string_generator_t::DEFAULT_RANDOM_STR_LEN, OR generate(size_t len = snplib_random_string_generator_t::DEFAULT_RANDOM_STR_LEN,
IR char_range = snplib_randoom_string_generator_t::DEFAULT_RANDOM_CHAR_RANGE) IR char_range = snplib_random_string_generator_t::DEFAULT_RANDOM_CHAR_RANGE)
{ {
OR res; OR res;
size_t max_idx = std::ranges::size(char_range); size_t max_idx = std::ranges::size(char_range);
if (max_idx < 2) { if (max_idx < 2) {
char_range = snplib_randoom_string_generator_t::DEFAULT_RANDOM_CHAR_RANGE; char_range = snplib_random_string_generator_t::DEFAULT_RANDOM_CHAR_RANGE;
max_idx = snplib_randoom_string_generator_t::DEFAULT_RANDOM_CHAR_RANGE.size(); max_idx = snplib_random_string_generator_t::DEFAULT_RANDOM_CHAR_RANGE.size();
} }
std::uniform_int_distribution<size_t> rdist(0, --max_idx); std::uniform_int_distribution<size_t> rdist(0, --max_idx);
if (!len) { 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) { for (size_t i = 0; i < len; ++i) {
@@ -396,9 +411,9 @@ public:
return res; return res;
} }
template <snplib_input_char_range_c IR = decltype(snplib_randoom_string_generator_t::DEFAULT_RANDOM_CHAR_RANGE)> template <snplib_input_char_range_c IR = decltype(snplib_random_string_generator_t::DEFAULT_RANDOM_CHAR_RANGE)>
std::string generate(size_t len = snplib_randoom_string_generator_t::DEFAULT_RANDOM_STR_LEN, std::string generate(size_t len = snplib_random_string_generator_t::DEFAULT_RANDOM_STR_LEN,
IR char_range = snplib_randoom_string_generator_t::DEFAULT_RANDOM_CHAR_RANGE) IR char_range = snplib_random_string_generator_t::DEFAULT_RANDOM_CHAR_RANGE)
{ {
return generate<std::string>(len, char_range); return generate<std::string>(len, char_range);
} }
@@ -406,7 +421,7 @@ public:
template <snplib_output_char_range_c OR> template <snplib_output_char_range_c OR>
OR UUIDv4String() 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(); auto iter = res.begin();
size_t i = 0; size_t i = 0;
for (size_t idx : std::array<size_t, 4>{8, 13, 18, 23}) { for (size_t idx : std::array<size_t, 4>{8, 13, 18, 23}) {