diff --git a/flash.hpp b/flash.hpp index 3e49f77..626de7b 100644 --- a/flash.hpp +++ b/flash.hpp @@ -1,9 +1,14 @@ #pragma once +#include + +#include #include #include +#include "../util/util.hpp" + #define F(str) (reinterpret_cast(PSTR(str))) #define GF(name, str) \ const char __##name[] PROGMEM = str; \ @@ -19,14 +24,96 @@ struct FlashString; namespace flash { template -static T load(const T &object) +static inline T load(const T &object) { - auto buffer = T{}; - auto rawBuffer = reinterpret_cast(&buffer); + T buffer; + auto byteBuffer = reinterpret_cast(&buffer); for (auto i = std::size_t{0}; i < sizeof(T); ++i) { - rawBuffer[i] = static_cast(pgm_read_byte(&reinterpret_cast(&object)[i])); + byteBuffer[i] = static_cast(pgm_read_byte(&reinterpret_cast(&object)[i])); } return buffer; } +template +struct [[gnu::progmem]] Wrapper +{ + using value_type = T; + + inline T operator*() const + { + return load(value); + } + + inline std::byte operator[](const std::size_t idx) const + { + const auto bytePtr = reinterpret_cast(&value); + return load(bytePtr[idx]); + } + + const T value; +}; + +template +struct RamWrapper { + using value_type = T; + + inline constexpr T &operator*() + { + return value; + } + + inline constexpr const T &operator*() const + { + return value; + } + + inline std::byte &operator[](const std::size_t idx) + { + const auto bytePtr = reinterpret_cast(&value); + return bytePtr[idx]; + } + + inline const std::byte &operator[](const std::size_t idx) const + { + const auto bytePtr = reinterpret_cast(&value); + return bytePtr[idx]; + } + + T value; +}; + +template +struct is_flash_wrapper : std::false_type { +}; + +template +struct is_flash_wrapper> : std::true_type { +}; + +template +static inline constexpr auto is_flash_wrapper_v = is_flash_wrapper::value; + +template +struct is_ram_wrapper : std::false_type { +}; + +template +struct is_ram_wrapper> : std::true_type { +}; + +template +static inline constexpr auto is_ram_wrapper_v = is_ram_wrapper::value; + +template +static inline decltype(auto) loadLike(const T &object) +{ + if constexpr (is_ram_wrapper_v>) { + return object; + } else if constexpr (is_flash_wrapper_v>) { + return load(object); + } else { + static_assert(util::always_false_v, "Invalid wrapper type"); + } +} + } // namespace flash