From 1da86dd657853b3dedcc023fa7eb932962ea7c2d Mon Sep 17 00:00:00 2001 From: crosstyan Date: Wed, 15 Jul 2026 22:32:04 +0800 Subject: [PATCH] refactor(utils): trim unused helpers, make deferrer allocation-free MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove app::utils helpers with zero fleet call sites after the app_common merge (as_u8s, hexdump, add_overflow/overflow_error, try_get/try_get_ref, constrain_value_in_range_static — a template-bounds reimplementation of std::clamp) and the unused app_clock milliseconds alias. This drops several heavy includes from a header every consumer compiles. Rewrite deferrer as a stdlib scope guard that owns the callable directly (template, non-copyable/non-movable) instead of type-erasing through std::move_only_function/std::function, so it never heap-allocates. The 3 call sites (band max32664d) are unchanged via CTAD. --- README.md | 7 +- inc/app_clock.hpp | 1 - inc/app_utils.hpp | 177 +++------------------------------------------- 3 files changed, 12 insertions(+), 173 deletions(-) diff --git a/README.md b/README.md index e91a6a2..056bc2c 100644 --- a/README.md +++ b/README.md @@ -6,10 +6,9 @@ hand-copied (and had drifted) between the three repos. ## Contents -- `inc/app_utils.hpp` — byte/span casts (`as_bytes`, `as_u8s`), `overloads`, - `try_get`/`try_get_ref`, `deferrer`, `hexdump`, `add_overflow`, - `constrain_value_in_range_static`, `to_mac_string` (only when the toolchain - has ``; guarded by `__cpp_lib_format`). +- `inc/app_utils.hpp` — byte/span casts (`as_bytes`), `overloads`, `deferrer`, + `to_mac_string` (only when the toolchain has ``; guarded by + `__cpp_lib_format`). - `inc/app_clock.hpp` — monotonic microsecond `TrivialClock`. The only OS-specific code in this repo: `now()` is `k_uptime_ticks()` on Zephyr and `esp_timer_get_time()` on ESP-IDF, selected by `__ZEPHYR__` / `ESP_PLATFORM`. diff --git a/inc/app_clock.hpp b/inc/app_clock.hpp index 42ce0b0..53235c3 100644 --- a/inc/app_clock.hpp +++ b/inc/app_clock.hpp @@ -34,5 +34,4 @@ struct clock_t { #endif } }; -using milliseconds = std::chrono::duration; } diff --git a/inc/app_utils.hpp b/inc/app_utils.hpp index 0cdc524..844f6b1 100644 --- a/inc/app_utils.hpp +++ b/inc/app_utils.hpp @@ -1,15 +1,8 @@ #pragma once #include -#include -#include -#include -#include -#include -#include #include -#include -#include +#include #include #ifdef __cpp_lib_format #include @@ -61,182 +54,30 @@ inline std::span as_bytes(const std::uint8_t *data, std::size_t return {reinterpret_cast(data), size}; } - -/// @brief reinterpret_cast a trivially copyable value to a span of uint8_t -template - requires std::is_trivially_copyable_v -inline std::span as_u8s(const T &value) { - return {reinterpret_cast(&value), sizeof(value)}; -} - -/// @brief reinterpret_cast a trivially copyable value to a span of uint8_t span -template - requires std::is_trivially_copyable_v -inline std::span as_u8s(T &value) { - return {reinterpret_cast(&value), sizeof(value)}; -} - -/// @brief convert a std::byte span to a uint8_t span -inline std::span as_u8s(std::span span) { - return {reinterpret_cast(span.data()), span.size()}; -} - -/// @brief convert a std::byte span to a uint8_t span (mutable) -inline std::span as_u8s(std::span span) { - return {reinterpret_cast(span.data()), span.size()}; -} - /// @brief helper type for the visitor template struct overloads : Ts... { using Ts::operator()...; }; -inline void hexdump(std::span data) { - const auto enumerate = [](const auto &data) { - return data | std::views::transform([i = 0](const auto &value) mutable { - return std::make_tuple(i++, value); - }); - }; - for (const auto [i, byte] : enumerate(data)) { - bool is_end = i == data.size() - 1; - if (is_end) { - printf("%02x\n", static_cast(byte)); - } else { - if (i % 16 == 15) { - printf("%02x\n", static_cast(byte)); - } else { - printf("%02x ", static_cast(byte)); - } - } - } -} - -/** - * @brief try to get an element from a span - * @tparam T, should be trivially copyable - * @param s span - * @param idx index, can be negative, will be shifted into [0, s.size()) - * @return std::optional element, or std::nullopt if index is out of range - */ -template -std::optional try_get(std::span s, int idx) { - const int n = static_cast(s.size()); - // 1) if negative, shift into [−n, 0) → [0, n) - if (idx < 0) { - idx += n; - } - // 2) now both negative-too-big and positive-too-big land outside [0,n) - if (idx < 0 || idx >= n) { - return std::nullopt; - } - return s[idx]; -} - -/** - * @brief try to get an element from a const span - * @tparam T - * @param s const span - * @param idx index, can be negative, will be shifted into [0, s.size()) - * @return std::optional> element reference, or std::nullopt if index is out of range - * @see try_get - */ -template -std::optional> -try_get_ref(std::span s, int idx) { - const int n = static_cast(s.size()); - if (idx < 0) { - idx += n; - } - if (idx < 0 || idx >= n) { - return std::nullopt; - } - return std::cref(s[idx]); -} - /** * @brief a simple RAII helper for `defer` like behavior */ -struct deferrer { -#ifdef __cpp_lib_move_only_function - using func_t = std::move_only_function; -#else - using func_t = std::function; -#endif +template +class deferrer { + F f_; - deferrer(func_t &&f) : _f(std::move(f)) {} +public: + explicit constexpr deferrer(F f) : f_(std::move(f)) {} ~deferrer() { - if (_f) { - _f(); - } + f_(); } deferrer(const deferrer &) = delete; deferrer &operator=(const deferrer &) = delete; - deferrer(deferrer &&other) noexcept : _f(std::move(other._f)) { - other._f = {}; - } - deferrer &operator=(deferrer &&other) noexcept { - if (this != &other) { - // call current function before overwriting - if (_f) { - _f(); - } - _f = std::move(other._f); - other._f = {}; - } - return *this; - } - -private: - func_t _f; + deferrer(deferrer &&) = delete; + deferrer &operator=(deferrer &&) = delete; }; -using overflow_error = std::monostate; -/** - * @brief a safe addition that returns an overflow error if the result is out of range - */ -template - requires std::is_integral_v -std::expected add_overflow(T a, T b) { - using ue = std::unexpected; - - if constexpr (std::is_unsigned_v) { - // For unsigned: check if a > max - b (rearranged to avoid overflow in the check itself) - if (a > std::numeric_limits::max() - b) { - return ue{overflow_error{}}; - } - } else { - // For signed integers: need to check both positive and negative overflow - if (b > 0) { - if (a > std::numeric_limits::max() - b) { - return ue{overflow_error{}}; - } - } else { - if (a < std::numeric_limits::min() - b) { - return ue{overflow_error{}}; - } - } - } - - return a + b; -} - - -/** - * @see `std::clamp` - */ -template -T constrain_value_in_range_static(T value) { - static_assert(min < max, "min must be less than max"); - if (value < min) { - return min; - } - if (value > max) { - return max; - } - return value; -} - #ifdef __cpp_lib_format inline std::string to_mac_string(std::span mac) { return std::format("{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}",