ESPHome 2026.10.2
Loading...
Searching...
No Matches
progmem.h
Go to the documentation of this file.
1#pragma once
2
3#include <array>
4#include <cstddef>
5#include <cstdint>
6#include <new>
7#include <string>
8
9#include "esphome/core/hal.h" // For PROGMEM definition
10
11// Platform-agnostic macros for PROGMEM string handling
12// On ESP8266/Arduino: Use Arduino's F() macro for PROGMEM strings
13// On other platforms: Use plain strings (no PROGMEM)
14
15#ifdef USE_ESP8266
16// ESP8266 uses Arduino macros
17#define ESPHOME_F(string_literal) F(string_literal)
18#define ESPHOME_PGM_P PGM_P
19#define ESPHOME_PSTR(s) PSTR(s)
20#define ESPHOME_strncpy_P strncpy_P
21#define ESPHOME_strncat_P strncat_P
22#define ESPHOME_snprintf_P snprintf_P
23#define ESPHOME_strcmp_P strcmp_P
24#define ESPHOME_strcasecmp_P strcasecmp_P
25#define ESPHOME_strncmp_P strncmp_P
26#define ESPHOME_strncasecmp_P strncasecmp_P
27#define ESPHOME_strlen_P strlen_P
28// Type for pointers to PROGMEM strings (for use with ESPHOME_F return values)
29using ProgmemStr = const __FlashStringHelper *;
30// Storage class for PROGMEM_STRING_TABLE data; LOG_STR_ARG treats a LogString as PGM_P
31// on ESP8266, so the table data must be in flash to match.
32#define ESPHOME_PROGMEM_STRING_TABLE_STORAGE PROGMEM
33#else
34#define ESPHOME_F(string_literal) (string_literal)
35#define ESPHOME_PGM_P const char *
36#define ESPHOME_PSTR(s) (s)
37#define ESPHOME_strncpy_P strncpy
38#define ESPHOME_strncat_P strncat
39#define ESPHOME_snprintf_P snprintf
40#define ESPHOME_strcmp_P strcmp
41#define ESPHOME_strcasecmp_P strcasecmp
42#define ESPHOME_strncmp_P strncmp
43#define ESPHOME_strncasecmp_P strncasecmp
44#define ESPHOME_strlen_P strlen
45// Type for pointers to strings (no PROGMEM on non-ESP8266 platforms)
46using ProgmemStr = const char *;
47// No-op on non-ESP8266 platforms where PROGMEM itself is a no-op.
48#define ESPHOME_PROGMEM_STRING_TABLE_STORAGE
49#endif
50
51namespace esphome {
52
54#ifdef USE_ESP8266
55std::string progmem_string(ProgmemStr str);
56#else
57inline std::string progmem_string(ProgmemStr str) { return std::string(str); }
58#endif
59
61template<size_t N> struct FixedString {
62 char data[N]{};
63 constexpr FixedString(const char (&str)[N]) {
64 for (size_t i = 0; i < N; ++i)
65 data[i] = str[i];
66 }
67 constexpr size_t size() const { return N - 1; } // exclude null terminator
68};
69
78template<FixedString... Strs> struct ProgmemStringTable {
79 static constexpr size_t COUNT = sizeof...(Strs);
80 static constexpr size_t BLOB_SIZE = (0 + ... + (Strs.size() + 1));
81
83 static constexpr auto make_blob() {
84 std::array<char, BLOB_SIZE> result{};
85 size_t pos = 0;
86 auto copy = [&](const auto &str) {
87 for (size_t i = 0; i <= str.size(); ++i)
88 result[pos++] = str.data[i];
89 };
90 (copy(Strs), ...);
91 return result;
92 }
93
95 static constexpr auto make_offsets() {
96 static_assert(COUNT > 0, "PROGMEM_STRING_TABLE must contain at least one string");
97 static_assert(COUNT <= 255, "PROGMEM_STRING_TABLE supports at most 255 strings with uint8_t indices");
98 static_assert(BLOB_SIZE <= 255, "PROGMEM_STRING_TABLE blob exceeds 255 bytes; use fewer/shorter strings");
99 std::array<uint8_t, COUNT> result{};
100 size_t pos = 0, idx = 0;
101 ((result[idx++] = static_cast<uint8_t>(pos), pos += Strs.size() + 1), ...);
102 return result;
103 }
104};
105
106// Forward declaration for LogString (defined in log.h)
107struct LogString;
108
112#define PROGMEM_STRING_TABLE(Name, ...) \
113 struct Name { \
114 using Table = ::esphome::ProgmemStringTable<__VA_ARGS__>; \
115 static constexpr size_t COUNT = Table::COUNT; \
116 static constexpr uint8_t LAST_INDEX = COUNT - 1; \
117 static constexpr size_t BLOB_SIZE = Table::BLOB_SIZE; \
118 static constexpr auto BLOB ESPHOME_PROGMEM_STRING_TABLE_STORAGE = Table::make_blob(); \
119 static constexpr auto OFFSETS ESPHOME_PROGMEM_STRING_TABLE_STORAGE = Table::make_offsets(); \
120 static const char *get_(uint8_t idx, uint8_t fallback) { \
121 if (idx >= COUNT) \
122 idx = fallback; \
123 /* std::launder is used here to prevent the inter-procedural analysis that */ \
124 /* causes the false positive that the string is not null terminated */ \
125 return std::launder(&BLOB[::esphome::progmem_read_byte(&OFFSETS[idx])]); \
126 } \
127 static ::ProgmemStr get_progmem_str(uint8_t idx, uint8_t fallback) { \
128 return reinterpret_cast<::ProgmemStr>(get_(idx, fallback)); \
129 } \
130 static const ::esphome::LogString *get_log_str(uint8_t idx, uint8_t fallback) { \
131 return reinterpret_cast<const ::esphome::LogString *>(get_(idx, fallback)); \
132 } \
133 }
134
135} // namespace esphome
std::string progmem_string(ProgmemStr str)
Copies a string stored with ESPHOME_F into a std::string.
Definition helpers.cpp:23
size_t size_t pos
Definition helpers.h:1186
const __FlashStringHelper * ProgmemStr
Definition progmem.h:29
Helper for C++20 string literal template arguments.
Definition progmem.h:61
constexpr size_t size() const
Definition progmem.h:67
constexpr FixedString(const char(&str)[N])
Definition progmem.h:63
Compile-time string table that packs strings into a single blob with offset lookup.
Definition progmem.h:78
static constexpr size_t COUNT
Definition progmem.h:79
static constexpr size_t BLOB_SIZE
Definition progmem.h:80
static constexpr auto make_blob()
Generate packed string blob at compile time.
Definition progmem.h:83
static constexpr auto make_offsets()
Generate offset table at compile time (uint8_t limits blob to 255 bytes)
Definition progmem.h:95