From 5a39097b3a73052d09fe06d8fb5770605961e22e Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Mon, 12 Oct 2026 15:46:41 -1000 Subject: [PATCH] [light] Keep one copy of the color mode lookup table in flash (#20394) --- esphome/components/light/color_mode.h | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/esphome/components/light/color_mode.h b/esphome/components/light/color_mode.h index 0750ae250d..fbce5232ff 100644 --- a/esphome/components/light/color_mode.h +++ b/esphome/components/light/color_mode.h @@ -2,6 +2,7 @@ #include #include "esphome/core/finite_set_mask.h" +#include "esphome/core/hal.h" namespace esphome::light { @@ -108,8 +109,9 @@ constexpr ColorModeHelper operator|(ColorModeHelper lhs, ColorMode rhs) { using color_mode_bitmask_t = uint16_t; // Lookup table for ColorMode bit mapping -// This array defines the canonical order of color modes (bit 0-9) -constexpr ColorMode COLOR_MODE_LOOKUP[] = { +// This array defines the canonical order of color modes (bit 0-9). One shared copy in flash; read it at run time +// through color_mode_at(). +inline constexpr ColorMode COLOR_MODE_LOOKUP[] PROGMEM = { ColorMode::UNKNOWN, // bit 0 ColorMode::ON_OFF, // bit 1 ColorMode::BRIGHTNESS, // bit 2 @@ -122,6 +124,12 @@ constexpr ColorMode COLOR_MODE_LOOKUP[] = { ColorMode::RGB_COLD_WARM_WHITE, // bit 9 }; +constexpr ColorMode color_mode_at(unsigned bit) { + if (__builtin_is_constant_evaluated()) + return COLOR_MODE_LOOKUP[bit]; + return static_cast(progmem_read_byte(reinterpret_cast(&COLOR_MODE_LOOKUP[bit]))); +} + /// Bit mapping policy for ColorMode /// Uses lookup table for non-contiguous enum values struct ColorModeBitPolicy { @@ -129,17 +137,15 @@ struct ColorModeBitPolicy { static constexpr int MAX_BITS = sizeof(COLOR_MODE_LOOKUP) / sizeof(COLOR_MODE_LOOKUP[0]); static constexpr unsigned to_bit(ColorMode mode) { - // Linear search through lookup table - // Compiler optimizes this to efficient code since array is constexpr for (int i = 0; i < MAX_BITS; ++i) { - if (COLOR_MODE_LOOKUP[i] == mode) + if (color_mode_at(i) == mode) return i; } return 0; } static constexpr ColorMode from_bit(unsigned bit) { - return (bit < MAX_BITS) ? COLOR_MODE_LOOKUP[bit] : ColorMode::UNKNOWN; + return (bit < MAX_BITS) ? color_mode_at(bit) : ColorMode::UNKNOWN; } }; @@ -157,7 +163,7 @@ constexpr uint16_t compute_capability_bitmask(ColorCapability capability) { // Check each ColorMode to see if it has this capability constexpr int color_mode_count = sizeof(COLOR_MODE_LOOKUP) / sizeof(COLOR_MODE_LOOKUP[0]); for (int bit = 0; bit < color_mode_count; ++bit) { - uint8_t mode_val = static_cast(COLOR_MODE_LOOKUP[bit]); + uint8_t mode_val = static_cast(color_mode_at(bit)); if ((mode_val & cap_bit) != 0) { mask |= (1 << bit); }