diff --git a/esphome/components/json/json_util.cpp b/esphome/components/json/json_util.cpp index 40a3496981..51c0fcf9cb 100644 --- a/esphome/components/json/json_util.cpp +++ b/esphome/components/json/json_util.cpp @@ -8,31 +8,6 @@ namespace json { static const char *const TAG = "json"; -#ifdef USE_PSRAM -// Build an allocator for the JSON Library using the RAMAllocator class -// This is only compiled when PSRAM is enabled -struct SpiRamAllocator : ArduinoJson::Allocator { - void *allocate(size_t size) override { return this->allocator_.allocate(size); } - - void deallocate(void *pointer) override { - // ArduinoJson's Allocator interface doesn't provide the size parameter in deallocate. - // RAMAllocator::deallocate() requires the size, which we don't have access to here. - // RAMAllocator::deallocate implementation just calls free() regardless of whether - // the memory was allocated with heap_caps_malloc or malloc. - // This is safe because ESP-IDF's heap implementation internally tracks the memory region - // and routes free() to the appropriate heap. - free(pointer); // NOLINT(cppcoreguidelines-owning-memory,cppcoreguidelines-no-malloc) - } - - void *reallocate(void *ptr, size_t new_size) override { - return this->allocator_.reallocate(static_cast(ptr), new_size); - } - - protected: - RAMAllocator allocator_{RAMAllocator(RAMAllocator::NONE)}; -}; -#endif - std::string build_json(const json_build_t &f) { // NOLINTBEGIN(clang-analyzer-cplusplus.NewDeleteLeaks) false positive with ArduinoJson JsonBuilder builder; @@ -69,27 +44,6 @@ bool parse_json(const std::string &data, const json_parse_t &f) { // NOLINTEND(clang-analyzer-cplusplus.NewDeleteLeaks) } -// JsonBuilder implementation -JsonBuilder::JsonBuilder() - : doc_( -#ifdef USE_PSRAM - [this]() { - auto *alloc = new SpiRamAllocator(); // NOLINT(cppcoreguidelines-owning-memory) - allocator_ = alloc; - return alloc; - }() -#else - nullptr -#endif - ) { -} - -JsonBuilder::~JsonBuilder() { -#ifdef USE_PSRAM - delete static_cast(allocator_); // NOLINT(cppcoreguidelines-owning-memory) -#endif -} - std::string JsonBuilder::serialize() { if (doc_.overflowed()) { ESP_LOGE(TAG, "JSON document overflow"); diff --git a/esphome/components/json/json_util.h b/esphome/components/json/json_util.h index 8eac87b10a..69b809ec49 100644 --- a/esphome/components/json/json_util.h +++ b/esphome/components/json/json_util.h @@ -13,6 +13,31 @@ namespace esphome { namespace json { +#ifdef USE_PSRAM +// Build an allocator for the JSON Library using the RAMAllocator class +// This is only compiled when PSRAM is enabled +struct SpiRamAllocator : ArduinoJson::Allocator { + void *allocate(size_t size) override { return allocator_.allocate(size); } + + void deallocate(void *ptr) override { + // ArduinoJson's Allocator interface doesn't provide the size parameter in deallocate. + // RAMAllocator::deallocate() requires the size, which we don't have access to here. + // RAMAllocator::deallocate implementation just calls free() regardless of whether + // the memory was allocated with heap_caps_malloc or malloc. + // This is safe because ESP-IDF's heap implementation internally tracks the memory region + // and routes free() to the appropriate heap. + free(ptr); // NOLINT(cppcoreguidelines-owning-memory,cppcoreguidelines-no-malloc) + } + + void *reallocate(void *ptr, size_t new_size) override { + return allocator_.reallocate(static_cast(ptr), new_size); + } + + protected: + RAMAllocator allocator_{RAMAllocator::NONE}; +}; +#endif + /// Callback function typedef for parsing JsonObjects. using json_parse_t = std::function; @@ -28,9 +53,6 @@ bool parse_json(const std::string &data, const json_parse_t &f); /// Builder class for creating JSON documents without lambdas class JsonBuilder { public: - JsonBuilder(); - ~JsonBuilder(); - JsonObject root() { if (!root_created_) { root_ = doc_.to(); @@ -42,13 +64,14 @@ class JsonBuilder { std::string serialize(); private: +#ifdef USE_PSRAM + SpiRamAllocator allocator_; + JsonDocument doc_{&allocator_}; +#else JsonDocument doc_; +#endif JsonObject root_; bool root_created_{false}; - // Allocator must be last member to ensure it's destroyed after doc_ -#ifdef USE_PSRAM - void *allocator_{nullptr}; // Will store SpiRamAllocator*, managed in cpp file -#endif }; } // namespace json