From 347501d895cb42d1a15633d4b2fd684ae6a2af6a Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sun, 12 Oct 2025 19:39:55 -1000 Subject: [PATCH] wifi fixed vector --- esphome/components/wifi/wifi_component.cpp | 2 +- esphome/components/wifi/wifi_component.h | 4 +- .../wifi/wifi_component_esp8266.cpp | 8 ++++ .../wifi/wifi_component_esp_idf.cpp | 5 +- .../wifi/wifi_component_libretiny.cpp | 2 +- esphome/core/helpers.h | 46 +++++++++++++++---- 6 files changed, 51 insertions(+), 16 deletions(-) diff --git a/esphome/components/wifi/wifi_component.cpp b/esphome/components/wifi/wifi_component.cpp index 2e083d4c68..1bb2674ad7 100644 --- a/esphome/components/wifi/wifi_component.cpp +++ b/esphome/components/wifi/wifi_component.cpp @@ -552,7 +552,7 @@ void WiFiComponent::start_scanning() { // Using insertion sort instead of std::stable_sort saves flash memory // by avoiding template instantiations (std::rotate, std::stable_sort, lambdas) // IMPORTANT: This sort is stable (preserves relative order of equal elements) -static void insertion_sort_scan_results(std::vector &results) { +static void insertion_sort_scan_results(FixedVector &results) { const size_t size = results.size(); for (size_t i = 1; i < size; i++) { // Make a copy to avoid issues with move semantics during comparison diff --git a/esphome/components/wifi/wifi_component.h b/esphome/components/wifi/wifi_component.h index ee62ec1a69..e1c3d6df88 100644 --- a/esphome/components/wifi/wifi_component.h +++ b/esphome/components/wifi/wifi_component.h @@ -278,7 +278,7 @@ class WiFiComponent : public Component { std::string get_use_address() const; void set_use_address(const std::string &use_address); - const std::vector &get_scan_result() const { return scan_result_; } + const FixedVector &get_scan_result() const { return scan_result_; } network::IPAddress wifi_soft_ap_ip(); @@ -385,7 +385,7 @@ class WiFiComponent : public Component { std::string use_address_; std::vector sta_; std::vector sta_priorities_; - std::vector scan_result_; + FixedVector scan_result_; WiFiAP selected_ap_; WiFiAP ap_; optional output_power_; diff --git a/esphome/components/wifi/wifi_component_esp8266.cpp b/esphome/components/wifi/wifi_component_esp8266.cpp index 3b3b4b139c..59909b2cb5 100644 --- a/esphome/components/wifi/wifi_component_esp8266.cpp +++ b/esphome/components/wifi/wifi_component_esp8266.cpp @@ -696,7 +696,15 @@ void WiFiComponent::wifi_scan_done_callback_(void *arg, STATUS status) { this->retry_connect(); return; } + + // Count the number of results first auto *head = reinterpret_cast(arg); + size_t count = 0; + for (bss_info *it = head; it != nullptr; it = STAILQ_NEXT(it, next)) { + count++; + } + + this->scan_result_.init(count); for (bss_info *it = head; it != nullptr; it = STAILQ_NEXT(it, next)) { WiFiScanResult res({it->bssid[0], it->bssid[1], it->bssid[2], it->bssid[3], it->bssid[4], it->bssid[5]}, std::string(reinterpret_cast(it->ssid), it->ssid_len), it->channel, it->rssi, diff --git a/esphome/components/wifi/wifi_component_esp_idf.cpp b/esphome/components/wifi/wifi_component_esp_idf.cpp index ccec800205..4c719ef4c3 100644 --- a/esphome/components/wifi/wifi_component_esp_idf.cpp +++ b/esphome/components/wifi/wifi_component_esp_idf.cpp @@ -763,8 +763,9 @@ void WiFiComponent::wifi_process_event_(IDFWiFiEvent *data) { const auto &it = data->data.sta_scan_done; ESP_LOGV(TAG, "Scan done: status=%" PRIu32 " number=%u scan_id=%u", it.status, it.number, it.scan_id); - scan_result_.clear(); this->scan_done_ = true; + scan_result_.clear(); + if (it.status != 0) { // scan error return; @@ -784,7 +785,7 @@ void WiFiComponent::wifi_process_event_(IDFWiFiEvent *data) { } records.resize(number); - scan_result_.reserve(number); + scan_result_.init(number); for (int i = 0; i < number; i++) { auto &record = records[i]; bssid_t bssid; diff --git a/esphome/components/wifi/wifi_component_libretiny.cpp b/esphome/components/wifi/wifi_component_libretiny.cpp index b15f710150..cb179d9022 100644 --- a/esphome/components/wifi/wifi_component_libretiny.cpp +++ b/esphome/components/wifi/wifi_component_libretiny.cpp @@ -411,7 +411,7 @@ void WiFiComponent::wifi_scan_done_callback_() { if (num < 0) return; - this->scan_result_.reserve(static_cast(num)); + this->scan_result_.init(static_cast(num)); for (int i = 0; i < num; i++) { String ssid = WiFi.SSID(i); wifi_auth_mode_t authmode = WiFi.encryptionType(i); diff --git a/esphome/core/helpers.h b/esphome/core/helpers.h index b5a0a1c8ac..12e921e3be 100644 --- a/esphome/core/helpers.h +++ b/esphome/core/helpers.h @@ -168,34 +168,54 @@ template class FixedVector { size_t size_{0}; size_t capacity_{0}; + // Helper to destroy elements and free memory + void cleanup_() { + if (data_ != nullptr) { + // Manually destroy all elements + for (size_t i = 0; i < size_; i++) { + data_[i].~T(); + } + // Free raw memory + ::operator delete(data_); + } + } + public: FixedVector() = default; - ~FixedVector() { - if (data_ != nullptr) { - delete[] data_; - } - } + ~FixedVector() { cleanup_(); } // Disable copy to avoid accidental copies FixedVector(const FixedVector &) = delete; FixedVector &operator=(const FixedVector &) = delete; - // Allocate capacity - can only be called once on empty vector + // Allocate capacity - can be called multiple times to reinit void init(size_t n) { - if (data_ == nullptr && n > 0) { - data_ = new T[n]; + cleanup_(); + data_ = nullptr; + capacity_ = 0; + size_ = 0; + if (n > 0) { + // Allocate raw memory without calling constructors + data_ = static_cast(::operator new(n * sizeof(T))); capacity_ = n; - size_ = 0; } } + // Clear the vector (reset size to 0, keep capacity) + void clear() { size_ = 0; } + + // Check if vector is empty + bool empty() const { return size_ == 0; } + /// Add element without bounds checking /// Caller must ensure sufficient capacity was allocated via init() /// Silently ignores pushes beyond capacity (no exception or assertion) void push_back(const T &value) { if (size_ < capacity_) { - data_[size_++] = value; + // Use placement new to construct the object in pre-allocated memory + new (&data_[size_]) T(value); + size_++; } } @@ -205,6 +225,12 @@ template class FixedVector { /// Caller must ensure index is valid (i < size()) T &operator[](size_t i) { return data_[i]; } const T &operator[](size_t i) const { return data_[i]; } + + // Iterator support for range-based for loops + T *begin() { return data_; } + T *end() { return data_ + size_; } + const T *begin() const { return data_; } + const T *end() const { return data_ + size_; } }; ///@}