refactor(utils): trim unused helpers, make deferrer allocation-free
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<F>, 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.
This commit is contained in:
@@ -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 `<format>`; guarded by `__cpp_lib_format`).
|
||||
- `inc/app_utils.hpp` — byte/span casts (`as_bytes`), `overloads`, `deferrer`,
|
||||
`to_mac_string` (only when the toolchain has `<format>`; 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`.
|
||||
|
||||
@@ -34,5 +34,4 @@ struct clock_t {
|
||||
#endif
|
||||
}
|
||||
};
|
||||
using milliseconds = std::chrono::duration<int32_t, std::milli>;
|
||||
}
|
||||
|
||||
+9
-168
@@ -1,15 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
#include <expected>
|
||||
#include <functional>
|
||||
#include <limits>
|
||||
#include <optional>
|
||||
#include <ranges>
|
||||
#include <span>
|
||||
#include <tuple>
|
||||
#include <variant>
|
||||
#include <utility>
|
||||
#include <version>
|
||||
#ifdef __cpp_lib_format
|
||||
#include <format>
|
||||
@@ -61,182 +54,30 @@ inline std::span<const std::byte> as_bytes(const std::uint8_t *data, std::size_t
|
||||
return {reinterpret_cast<const std::byte *>(data), size};
|
||||
}
|
||||
|
||||
|
||||
/// @brief reinterpret_cast a trivially copyable value to a span of uint8_t
|
||||
template <typename T>
|
||||
requires std::is_trivially_copyable_v<T>
|
||||
inline std::span<const std::uint8_t> as_u8s(const T &value) {
|
||||
return {reinterpret_cast<const std::uint8_t *>(&value), sizeof(value)};
|
||||
}
|
||||
|
||||
/// @brief reinterpret_cast a trivially copyable value to a span of uint8_t span
|
||||
template <typename T>
|
||||
requires std::is_trivially_copyable_v<T>
|
||||
inline std::span<std::uint8_t> as_u8s(T &value) {
|
||||
return {reinterpret_cast<std::uint8_t *>(&value), sizeof(value)};
|
||||
}
|
||||
|
||||
/// @brief convert a std::byte span to a uint8_t span
|
||||
inline std::span<const std::uint8_t> as_u8s(std::span<const std::byte> span) {
|
||||
return {reinterpret_cast<const std::uint8_t *>(span.data()), span.size()};
|
||||
}
|
||||
|
||||
/// @brief convert a std::byte span to a uint8_t span (mutable)
|
||||
inline std::span<std::uint8_t> as_u8s(std::span<std::byte> span) {
|
||||
return {reinterpret_cast<std::uint8_t *>(span.data()), span.size()};
|
||||
}
|
||||
|
||||
/// @brief helper type for the visitor
|
||||
template <class... Ts>
|
||||
struct overloads : Ts... {
|
||||
using Ts::operator()...;
|
||||
};
|
||||
|
||||
inline void hexdump(std::span<const std::byte> 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<uint8_t>(byte));
|
||||
} else {
|
||||
if (i % 16 == 15) {
|
||||
printf("%02x\n", static_cast<uint8_t>(byte));
|
||||
} else {
|
||||
printf("%02x ", static_cast<uint8_t>(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<T> element, or std::nullopt if index is out of range
|
||||
*/
|
||||
template <typename T>
|
||||
std::optional<T> try_get(std::span<T> s, int idx) {
|
||||
const int n = static_cast<int>(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<std::reference_wrapper<const T>> element reference, or std::nullopt if index is out of range
|
||||
* @see try_get
|
||||
*/
|
||||
template <typename T>
|
||||
std::optional<std::reference_wrapper<const T>>
|
||||
try_get_ref(std::span<const T> s, int idx) {
|
||||
const int n = static_cast<int>(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<void()>;
|
||||
#else
|
||||
using func_t = std::function<void()>;
|
||||
#endif
|
||||
template <typename F>
|
||||
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 <typename T>
|
||||
requires std::is_integral_v<T>
|
||||
std::expected<T, overflow_error> add_overflow(T a, T b) {
|
||||
using ue = std::unexpected<overflow_error>;
|
||||
|
||||
if constexpr (std::is_unsigned_v<T>) {
|
||||
// For unsigned: check if a > max - b (rearranged to avoid overflow in the check itself)
|
||||
if (a > std::numeric_limits<T>::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<T>::max() - b) {
|
||||
return ue{overflow_error{}};
|
||||
}
|
||||
} else {
|
||||
if (a < std::numeric_limits<T>::min() - b) {
|
||||
return ue{overflow_error{}};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return a + b;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @see `std::clamp`
|
||||
*/
|
||||
template <typename T, T min, T max>
|
||||
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<const std::byte, 6> mac) {
|
||||
return std::format("{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}",
|
||||
|
||||
Reference in New Issue
Block a user