From 2496d7bff8ad2e89d176dc114fafd2afe61fc2d8 Mon Sep 17 00:00:00 2001 From: Li-Xiang-Ideal <54926635+Li-Xiang-Ideal@users.noreply.github.com> Date: Fri, 30 Jan 2026 11:49:57 +0800 Subject: [PATCH 1/2] Add in-place data construction for Encoder Add functions to append new data directly to the end of the buffer, improving efficiency by avoiding intermediate copies. CHANGES - Add `generate_back_ustr()` for constructing data directly at the end of buffer using indices - Add `transform_back_ustr()` for transforming source data and inserting at buffer end - Add common buffer management functions: `size()`, `reserve()`, `resize()` --- wxf_parser.h | 38 +++++++++++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/wxf_parser.h b/wxf_parser.h index fc3a544..9b4b1ee 100644 --- a/wxf_parser.h +++ b/wxf_parser.h @@ -49,6 +49,7 @@ #include #include #include +#include #include namespace WXF_PARSER { @@ -179,6 +180,11 @@ namespace WXF_PARSER { // move from existing buffer Encoder(std::vector&& buf) : buffer(std::move(buf)) {} + const size_t size() const { return buffer.size(); } + void reserve(const size_t new_size) { buffer.reserve(new_size); } + void resize(const size_t new_size) { buffer.resize(new_size); } + void resize(const size_t new_size, const uint8_t val) { buffer.resize(new_size, val); } + // push ustr directly Encoder& push_ustr(const std::vector& str) { buffer.insert(buffer.end(), str.begin(), str.end()); return *this; } Encoder& push_ustr(const std::string_view str) { @@ -193,6 +199,36 @@ namespace WXF_PARSER { buffer.insert(buffer.end(), (uint8_t*)start, (uint8_t*)end); return *this; } + // generate data as ustr in the back + template + Encoder& generate_back_ustr(const size_t len, F&& func) { + static_assert(std::is_trivially_copyable_v, "T should be trivially copyable"); + static_assert(std::is_invocable_r_v, "func should be callable with size_t and return T"); + size_t old_size = buffer.size(); + buffer.resize(old_size + len * sizeof(T)); + uint8_t* data_ptr = buffer.data() + old_size; + for (size_t i = 0; i < len; i++) { + T value = func(i); + std::memcpy(data_ptr + i * sizeof(T), &value, sizeof(T)); + } + return *this; + } + + // generate transformed data as ustr in the back + template + Encoder& transform_back_ustr(const T2* src_ptr, const size_t len, F&& func) { + static_assert(std::is_trivially_copyable_v, "T1 should be trivially copyable"); + static_assert(std::is_invocable_r_v, "func should be callable with T2 and return T1"); + size_t old_size = buffer.size(); + buffer.resize(old_size + len * sizeof(T1)); + uint8_t* data_ptr = buffer.data() + old_size; + for (size_t i = 0; i < len; i++) { + T1 value = func(src_ptr[i]); + std::memcpy(data_ptr + i * sizeof(T1), &value, sizeof(T1)); + } + return *this; + } + Encoder& push_integer(const int64_t val) { auto num_type = minimal_signed_bits(val); switch (num_type) { @@ -1314,4 +1350,4 @@ namespace WXF_PARSER { fullform_to_wxf(encoder, FullForm::parse_FullForm(ff_template), map); return encoder; } -} // namespace WXF_PARSER \ No newline at end of file +} // namespace WXF_PARSER From e6d6a3d86ec60bc6ff800c6121823bf141fdef60 Mon Sep 17 00:00:00 2001 From: Li-Xiang-Ideal <54926635+Li-Xiang-Ideal@users.noreply.github.com> Date: Sun, 5 Jul 2026 13:47:59 +0800 Subject: [PATCH 2/2] Add typed and transformed array writes Update Encoder array writes so integer payloads use the requested WXF element width, and add helpers for transforming or generating array data directly into the output buffer. CHANGES - Make `push_array()` write integer payloads according to `num_type` - Add `push_array_data()` for in-place transformed span payloads - Add generated-array helpers for index-based payload construction --- wxf_parser.h | 125 +++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 122 insertions(+), 3 deletions(-) diff --git a/wxf_parser.h b/wxf_parser.h index 9b4b1ee..7bb3393 100644 --- a/wxf_parser.h +++ b/wxf_parser.h @@ -51,6 +51,7 @@ #include #include #include +#include namespace WXF_PARSER { @@ -301,8 +302,59 @@ namespace WXF_PARSER { return all_len; } - template - Encoder& push_array(const std::vector& dimension_array, const std::span data, WXF_HEAD type, uint8_t num_type) { + template + requires std::is_invocable_v + Encoder& push_array_data(const std::span data, uint8_t num_type, F&& func = std::identity{}) { + // backup current size + size_t old_size = buffer.size(); + using value_t = std::remove_cvref_t>; + + if constexpr (std::is_integral_v) { + const bool consistent_sign = (num_type >> 2) == (std::is_unsigned_v ? (16 >> 2) : 0); + if (size_of_arr_num_type(num_type) == sizeof(value_t) && consistent_sign) { + if constexpr (std::is_same_v, std::identity>) { + return push_ustr(data.data(), data.size()); + } + else { + return transform_back_ustr(data.data(), data.size(), func); + } + } + +#define APPEND_CASTED_ARRAY_DATA(TYPE) do { \ + transform_back_ustr(data.data(), data.size(), \ + [&](const T& value) { return static_cast(func(value)); }); \ + } while (0) + + switch (num_type) { + case 0: APPEND_CASTED_ARRAY_DATA(int8_t); break; + case 1: APPEND_CASTED_ARRAY_DATA(int16_t); break; + case 2: APPEND_CASTED_ARRAY_DATA(int32_t); break; + case 3: APPEND_CASTED_ARRAY_DATA(int64_t); break; + case 16: APPEND_CASTED_ARRAY_DATA(uint8_t); break; + case 17: APPEND_CASTED_ARRAY_DATA(uint16_t); break; + case 18: APPEND_CASTED_ARRAY_DATA(uint32_t); break; + case 19: APPEND_CASTED_ARRAY_DATA(uint64_t); break; + default: std::cerr << "Encoder::push_array_data: unsupported integer array num_type " + << static_cast(num_type) << "." << std::endl; + buffer.resize(old_size); + break; + } + return *this; +#undef APPEND_CASTED_ARRAY_DATA + } + else { + if constexpr (std::is_same_v, std::identity>) { + return push_ustr(data.data(), data.size()); + } + else { + return transform_back_ustr(data.data(), data.size(), func); + } + } + } + + template + requires std::is_invocable_v + Encoder& push_array(const std::vector& dimension_array, const std::span data, WXF_HEAD type, uint8_t num_type, F&& func = std::identity{}) { // backup current size size_t old_size = buffer.size(); @@ -317,7 +369,74 @@ namespace WXF_PARSER { } // push data - return push_ustr(data.data(), data.size()); + if constexpr (std::is_integral_v) { + const bool supported_num_type = num_type <= 3 || (num_type >= 16 && num_type <= 19); + if (!supported_num_type) { + std::cerr << "Encoder::push_array: unsupported integer array num_type " + << static_cast(num_type) << "." << std::endl; + buffer.resize(old_size); + return *this; + } + } + return push_array_data(data, num_type, std::forward(func)); + } + + template + requires std::is_invocable_v + Encoder& push_generated_array_data(const size_t len, uint8_t num_type, F&& func) { + // backup current size + size_t old_size = buffer.size(); + using value_t = std::remove_cvref_t>; + + if constexpr (std::is_integral_v) { +#define GENERATE_ARRAY_DATA(TYPE) do { \ + generate_back_ustr(len, [&](size_t i) { \ + return static_cast(func(i)); \ + });} while (0) + + switch (num_type) { + case 0: GENERATE_ARRAY_DATA(int8_t); break; + case 1: GENERATE_ARRAY_DATA(int16_t); break; + case 2: GENERATE_ARRAY_DATA(int32_t); break; + case 3: GENERATE_ARRAY_DATA(int64_t); break; + case 16: GENERATE_ARRAY_DATA(uint8_t); break; + case 17: GENERATE_ARRAY_DATA(uint16_t); break; + case 18: GENERATE_ARRAY_DATA(uint32_t); break; + case 19: GENERATE_ARRAY_DATA(uint64_t); break; + default: std::cerr << "Encoder::push_generated_array_data: unsupported integer array num_type " + << static_cast(num_type) << "." << std::endl; + buffer.resize(old_size); + break; + } + return *this; +#undef GENERATE_ARRAY_DATA + } + else { + return generate_back_ustr(len, func); + } + } + + template + requires std::is_invocable_v + Encoder& push_generated_array(const std::vector& dimension_array, WXF_HEAD type, uint8_t num_type, F&& func) { + // backup current size + size_t old_size = buffer.size(); + using value_t = std::remove_cvref_t>; + + // [array_type, num_type, rank, dimensions..., data...] + auto all_len = push_array_info(dimension_array, type, num_type); + + // push data + if constexpr (std::is_integral_v) { + const bool supported_num_type = num_type <= 3 || (num_type >= 16 && num_type <= 19); + if (!supported_num_type) { + std::cerr << "Encoder::push_generated_array: unsupported integer array num_type " + << static_cast(num_type) << "." << std::endl; + buffer.resize(old_size); + return *this; + } + } + return push_generated_array_data(all_len, num_type, std::forward(func)); } template