[light] Replace std::lerp with lightweight fast_lerp in LightColorValues::lerp

std::lerp includes NaN/infinity edge-case handling per C++20 spec, which
generates ~200 bytes of overhead per call. With 10 fields interpolated,
this bloated the symbol to 2,038 bytes. Since all light color values are
pre-clamped finite floats, a simple a + t * (b - a) is sufficient.

Reduces LightColorValues::lerp from 2,038 B to 286 B (86% reduction).
This commit is contained in:
J. Nick Koston
2026-02-23 17:22:21 -06:00
parent 869678953d
commit 8db3f67be4
+15 -13
View File
@@ -1,27 +1,29 @@
#include "light_color_values.h"
#include <cmath>
namespace esphome::light {
// Lightweight lerp without std::lerp's NaN/infinity handling overhead.
// Safe here because all color values are pre-clamped finite floats.
static inline float fast_lerp(float a, float b, float t) { return a + t * (b - a); }
LightColorValues LightColorValues::lerp(const LightColorValues &start, const LightColorValues &end, float completion) {
// Directly interpolate the raw values to avoid getter/setter overhead.
// This is safe because:
// - All LightColorValues have their values clamped when set via the setters
// - std::lerp guarantees output is in the same range as inputs
// - fast_lerp output stays in range when inputs are in range and 0 <= completion <= 1
// - Therefore the output doesn't need clamping, so we can skip the setters
LightColorValues v;
v.color_mode_ = end.color_mode_;
v.state_ = std::lerp(start.state_, end.state_, completion);
v.brightness_ = std::lerp(start.brightness_, end.brightness_, completion);
v.color_brightness_ = std::lerp(start.color_brightness_, end.color_brightness_, completion);
v.red_ = std::lerp(start.red_, end.red_, completion);
v.green_ = std::lerp(start.green_, end.green_, completion);
v.blue_ = std::lerp(start.blue_, end.blue_, completion);
v.white_ = std::lerp(start.white_, end.white_, completion);
v.color_temperature_ = std::lerp(start.color_temperature_, end.color_temperature_, completion);
v.cold_white_ = std::lerp(start.cold_white_, end.cold_white_, completion);
v.warm_white_ = std::lerp(start.warm_white_, end.warm_white_, completion);
v.state_ = fast_lerp(start.state_, end.state_, completion);
v.brightness_ = fast_lerp(start.brightness_, end.brightness_, completion);
v.color_brightness_ = fast_lerp(start.color_brightness_, end.color_brightness_, completion);
v.red_ = fast_lerp(start.red_, end.red_, completion);
v.green_ = fast_lerp(start.green_, end.green_, completion);
v.blue_ = fast_lerp(start.blue_, end.blue_, completion);
v.white_ = fast_lerp(start.white_, end.white_, completion);
v.color_temperature_ = fast_lerp(start.color_temperature_, end.color_temperature_, completion);
v.cold_white_ = fast_lerp(start.cold_white_, end.cold_white_, completion);
v.warm_white_ = fast_lerp(start.warm_white_, end.warm_white_, completion);
return v;
}