mirror of
https://github.com/esphome/esphome.git
synced 2026-05-26 11:17:00 +08:00
avoid template overhead
This commit is contained in:
@@ -2222,27 +2222,6 @@ template<std::totally_ordered T, comparable_with<T> U> T clamp_at_most(T value,
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Provides properly aligned, uninitialized static storage for a given type T.
|
||||
*
|
||||
* This struct is designed to replace dynamic heap allocations (`new T(...)`) for
|
||||
* global or static singletons within ESPHome, preventing memory fragmentation.
|
||||
* The underlying object must be explicitly constructed using placement new
|
||||
* before access. No destructor is called — this is intentional since ESPHome
|
||||
* singletons live for the entire device lifetime.
|
||||
*/
|
||||
template<class T> struct PlacementStorage {
|
||||
/// @brief Raw byte storage, strictly aligned for type T.
|
||||
alignas(T) unsigned char data[sizeof(T)];
|
||||
|
||||
/// @brief Retrieves a pointer to the storage as the target type.
|
||||
/// The caller must ensure the object has been constructed via placement new before dereferencing.
|
||||
T *get() { return reinterpret_cast<T *>(data); }
|
||||
|
||||
/// @brief Retrieves a const pointer to the storage as the target type.
|
||||
const T *get() const { return reinterpret_cast<const T *>(data); }
|
||||
};
|
||||
|
||||
/// @name Internal functions
|
||||
///@{
|
||||
|
||||
|
||||
@@ -584,18 +584,20 @@ def Pvariable(id_: ID, rhs: SafeExpType, type_: "MockObj" = None) -> "MockObj":
|
||||
# For 'new' allocations, use placement new into static storage
|
||||
# to avoid heap fragmentation on embedded devices.
|
||||
the_type = id_.type
|
||||
storage_type = MockObj(f"esphome::PlacementStorage<{the_type}>")
|
||||
storage_id = ID(f"{id_.id}_storage_", type=storage_type)
|
||||
storage_name = f"{id_.id}_storage_"
|
||||
|
||||
# Declare aligned byte array for the object storage
|
||||
CORE.add_global(
|
||||
VariableDeclarationExpression(storage_type, "", storage_id, static=True)
|
||||
RawStatement(
|
||||
f"alignas({the_type}) static unsigned char {storage_name}[sizeof({the_type})];"
|
||||
)
|
||||
)
|
||||
CORE.add_global(
|
||||
AssignmentExpression(
|
||||
f"static {the_type}",
|
||||
"*const ",
|
||||
id_,
|
||||
MockObj(f"{storage_id.id}.get()"),
|
||||
MockObj(f"reinterpret_cast<{the_type} *>({storage_name})"),
|
||||
)
|
||||
)
|
||||
# Extract args from the CallExpression and rebuild as placement new.
|
||||
|
||||
@@ -8,7 +8,7 @@ def test_deep_sleep_setup(generate_main):
|
||||
main_cpp = generate_main("tests/component_tests/deep_sleep/test_deep_sleep1.yaml")
|
||||
|
||||
assert (
|
||||
"static deep_sleep::DeepSleepComponent *const deepsleep = deepsleep_storage_.get();"
|
||||
"static deep_sleep::DeepSleepComponent *const deepsleep = reinterpret_cast<deep_sleep::DeepSleepComponent *>(deepsleep_storage_);"
|
||||
in main_cpp
|
||||
)
|
||||
assert "new(deepsleep) deep_sleep::DeepSleepComponent();" in main_cpp
|
||||
|
||||
@@ -16,12 +16,12 @@ def test_globals_placement_new_with_template_args(
|
||||
# Globals uses Pvariable with Type.new(template_args, initial_value)
|
||||
# which exercises the template_args preservation in placement new.
|
||||
assert "static globals::GlobalsComponent<int> *const my_global_int" in main_cpp
|
||||
assert "PlacementStorage<globals::GlobalsComponent<int>>" in main_cpp
|
||||
assert "sizeof(globals::GlobalsComponent<int>)" in main_cpp
|
||||
assert "new(my_global_int) globals::GlobalsComponent<int>" in main_cpp
|
||||
|
||||
# Verify initial value is passed as constructor arg
|
||||
assert "42" in main_cpp
|
||||
|
||||
# Check other globals are also generated
|
||||
assert "PlacementStorage<globals::GlobalsComponent<float>>" in main_cpp
|
||||
assert "PlacementStorage<globals::GlobalsComponent<bool>>" in main_cpp
|
||||
assert "sizeof(globals::GlobalsComponent<float>)" in main_cpp
|
||||
assert "sizeof(globals::GlobalsComponent<bool>)" in main_cpp
|
||||
|
||||
@@ -242,9 +242,13 @@ def test_image_generation(
|
||||
main_cpp = generate_main(component_config_path("image_test.yaml"))
|
||||
assert "uint8_t_id[] PROGMEM = {0x24, 0x21, 0x24, 0x21" in main_cpp
|
||||
assert (
|
||||
"static esphome::PlacementStorage<image::Image> cat_img_storage_;" in main_cpp
|
||||
"alignas(image::Image) static unsigned char cat_img_storage_[sizeof(image::Image)];"
|
||||
in main_cpp
|
||||
)
|
||||
assert (
|
||||
"static image::Image *const cat_img = reinterpret_cast<image::Image *>(cat_img_storage_);"
|
||||
in main_cpp
|
||||
)
|
||||
assert "static image::Image *const cat_img = cat_img_storage_.get();" in main_cpp
|
||||
assert (
|
||||
"new(cat_img) image::Image(uint8_t_id, 32, 24, image::IMAGE_TYPE_RGB565, image::TRANSPARENCY_OPAQUE);"
|
||||
in main_cpp
|
||||
|
||||
@@ -119,11 +119,12 @@ def test_code_generation(
|
||||
|
||||
main_cpp = generate_main(component_fixture_path("mipi_dsi.yaml"))
|
||||
assert (
|
||||
"static esphome::PlacementStorage<mipi_dsi::MIPI_DSI> p4_nano_storage_;"
|
||||
"alignas(mipi_dsi::MIPI_DSI) static unsigned char p4_nano_storage_[sizeof(mipi_dsi::MIPI_DSI)];"
|
||||
in main_cpp
|
||||
)
|
||||
assert (
|
||||
"static mipi_dsi::MIPI_DSI *const p4_nano = p4_nano_storage_.get();" in main_cpp
|
||||
"static mipi_dsi::MIPI_DSI *const p4_nano = reinterpret_cast<mipi_dsi::MIPI_DSI *>(p4_nano_storage_);"
|
||||
in main_cpp
|
||||
)
|
||||
assert (
|
||||
"new(p4_nano) mipi_dsi::MIPI_DSI(800, 1280, display::COLOR_BITNESS_565, 16);"
|
||||
|
||||
@@ -13,11 +13,11 @@ def test_status_led_generation(
|
||||
"""Test status_led generation."""
|
||||
main_cpp = generate_main(component_config_path("status_led_test.yaml"))
|
||||
assert (
|
||||
"static esphome::PlacementStorage<status_led::StatusLED> status_led_statusled_id_storage_;"
|
||||
"alignas(status_led::StatusLED) static unsigned char status_led_statusled_id_storage_[sizeof(status_led::StatusLED)];"
|
||||
in main_cpp
|
||||
)
|
||||
assert (
|
||||
"static status_led::StatusLED *const status_led_statusled_id = status_led_statusled_id_storage_.get();"
|
||||
"static status_led::StatusLED *const status_led_statusled_id = reinterpret_cast<status_led::StatusLED *>(status_led_statusled_id_storage_);"
|
||||
in main_cpp
|
||||
)
|
||||
assert "new(status_led_statusled_id) status_led::StatusLED(" in main_cpp
|
||||
|
||||
Reference in New Issue
Block a user