mirror of
https://github.com/esphome/esphome.git
synced 2026-10-14 10:12:52 +00:00
[core] Add cg.shared_progmem_array for deduplicated PROGMEM tables
Emits one PROGMEM array per distinct type and contents and returns the same variable to later callers. The array name is made unique against every config id and registered variable, so a generated table can never collide with a user id.
This commit is contained in:
@@ -40,6 +40,7 @@ from esphome.cpp_generator import ( # noqa: F401
|
||||
progmem_array,
|
||||
safe_exp,
|
||||
set_cpp_standard,
|
||||
shared_progmem_array,
|
||||
statement,
|
||||
static_const_array,
|
||||
static_function,
|
||||
|
||||
@@ -19,7 +19,12 @@ from esphome.core import (
|
||||
TimePeriodNanoseconds,
|
||||
TimePeriodSeconds,
|
||||
)
|
||||
from esphome.helpers import cpp_string_escape, indent, indent_all_but_first_and_last
|
||||
from esphome.helpers import (
|
||||
cpp_string_escape,
|
||||
ensure_unique_string,
|
||||
indent,
|
||||
indent_all_but_first_and_last,
|
||||
)
|
||||
from esphome.types import Expression, SafeExpType, TemplateArgsType
|
||||
from esphome.util import OrderedDict
|
||||
from esphome.yaml_util import ESPHomeDataBase
|
||||
@@ -463,6 +468,31 @@ def progmem_array(id_, rhs) -> "MockObj":
|
||||
return obj
|
||||
|
||||
|
||||
def shared_progmem_array(
|
||||
name: str, type_: "MockObjClass", rhs: SafeExpType
|
||||
) -> "MockObj":
|
||||
"""Emit a PROGMEM array once per distinct type and contents; later calls reuse it.
|
||||
|
||||
The name is made unique against every config id and registered variable. Call it at
|
||||
setup() top level: the array is a static local that later reuses must be able to see.
|
||||
"""
|
||||
from esphome.config import iter_ids
|
||||
from esphome.config_validation import RESERVED_IDS
|
||||
|
||||
arrays: dict[str, MockObj] = CORE.data.setdefault("shared_progmem_array", {})
|
||||
rhs = safe_exp(rhs)
|
||||
key = f"{type_} {rhs}"
|
||||
if (array := arrays.get(key)) is None:
|
||||
used = {str(i) for i, _ in iter_ids(CORE.config)}
|
||||
used |= {str(i) for i in CORE.variables}
|
||||
used |= set(RESERVED_IDS) | CORE.loaded_integrations
|
||||
unique = ensure_unique_string(name, used)
|
||||
array = arrays[key] = progmem_array(
|
||||
ID(unique, is_declaration=True, type=type_), rhs
|
||||
)
|
||||
return array
|
||||
|
||||
|
||||
def static_const_array(id_, rhs) -> "MockObj":
|
||||
rhs = safe_exp(rhs)
|
||||
obj = MockObj(id_, ".")
|
||||
|
||||
@@ -4,6 +4,7 @@ import math
|
||||
import pytest
|
||||
|
||||
from esphome import cpp_generator as cg, cpp_types as ct
|
||||
from esphome.core import CORE, ID
|
||||
|
||||
|
||||
class TestExpressions:
|
||||
@@ -808,3 +809,31 @@ async def test_templatable__lambda_with_std_string() -> None:
|
||||
result = await cg.templatable(lambda_obj, [], ct.std_string)
|
||||
|
||||
assert isinstance(result, cg.LambdaExpression)
|
||||
|
||||
|
||||
class TestSharedProgmemArray:
|
||||
def test_identical_contents_share_one_array(self) -> None:
|
||||
CORE.config = {}
|
||||
a = cg.shared_progmem_array("table", ct.uint8, [1, 2, 3])
|
||||
b = cg.shared_progmem_array("table", ct.uint8, [1, 2, 3])
|
||||
c = cg.shared_progmem_array("table", ct.uint8, [4])
|
||||
assert a is b
|
||||
assert str(a) != str(c)
|
||||
assert sum("PROGMEM" in str(st) for st in CORE.main_statements) == 2
|
||||
|
||||
def test_same_contents_different_type_are_separate(self) -> None:
|
||||
CORE.config = {}
|
||||
a = cg.shared_progmem_array("table", ct.uint8, [1])
|
||||
b = cg.shared_progmem_array("table", ct.uint16, [1])
|
||||
assert str(a) != str(b)
|
||||
|
||||
def test_name_avoids_config_ids(self) -> None:
|
||||
CORE.config = {"sensor": [{"id": ID("table", is_declaration=True)}]}
|
||||
array = cg.shared_progmem_array("table", ct.uint8, [1])
|
||||
assert str(array) == "table_2"
|
||||
|
||||
def test_name_avoids_registered_variables(self) -> None:
|
||||
CORE.config = {}
|
||||
CORE.register_variable(ID("table", is_declaration=True), cg.MockObj("table"))
|
||||
array = cg.shared_progmem_array("table", ct.uint8, [1])
|
||||
assert str(array) == "table_2"
|
||||
|
||||
Reference in New Issue
Block a user