Merge branch 'kamilcuk/use-placement-new' into integration

This commit is contained in:
J. Nick Koston
2026-03-22 13:58:24 -10:00
7 changed files with 21 additions and 37 deletions
-23
View File
@@ -11,11 +11,9 @@
#include <iterator>
#include <limits>
#include <memory>
#include <new>
#include <span>
#include <string>
#include <type_traits>
#include <utility>
#include <vector>
#include <concepts>
#include <strings.h>
@@ -2232,27 +2230,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
///@{
+6 -4
View File
@@ -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.