mirror of
https://github.com/esphome/esphome.git
synced 2026-01-19 09:36:24 -07:00
Compare commits
4 Commits
cache_gith
...
wifi_fixed
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
347501d895 | ||
|
|
4c00861760 | ||
|
|
2ff3e7fb2b | ||
|
|
b0c20d7adb |
@@ -552,7 +552,7 @@ void WiFiComponent::start_scanning() {
|
|||||||
// Using insertion sort instead of std::stable_sort saves flash memory
|
// Using insertion sort instead of std::stable_sort saves flash memory
|
||||||
// by avoiding template instantiations (std::rotate, std::stable_sort, lambdas)
|
// by avoiding template instantiations (std::rotate, std::stable_sort, lambdas)
|
||||||
// IMPORTANT: This sort is stable (preserves relative order of equal elements)
|
// IMPORTANT: This sort is stable (preserves relative order of equal elements)
|
||||||
static void insertion_sort_scan_results(std::vector<WiFiScanResult> &results) {
|
static void insertion_sort_scan_results(FixedVector<WiFiScanResult> &results) {
|
||||||
const size_t size = results.size();
|
const size_t size = results.size();
|
||||||
for (size_t i = 1; i < size; i++) {
|
for (size_t i = 1; i < size; i++) {
|
||||||
// Make a copy to avoid issues with move semantics during comparison
|
// Make a copy to avoid issues with move semantics during comparison
|
||||||
|
|||||||
@@ -278,7 +278,7 @@ class WiFiComponent : public Component {
|
|||||||
std::string get_use_address() const;
|
std::string get_use_address() const;
|
||||||
void set_use_address(const std::string &use_address);
|
void set_use_address(const std::string &use_address);
|
||||||
|
|
||||||
const std::vector<WiFiScanResult> &get_scan_result() const { return scan_result_; }
|
const FixedVector<WiFiScanResult> &get_scan_result() const { return scan_result_; }
|
||||||
|
|
||||||
network::IPAddress wifi_soft_ap_ip();
|
network::IPAddress wifi_soft_ap_ip();
|
||||||
|
|
||||||
@@ -385,7 +385,7 @@ class WiFiComponent : public Component {
|
|||||||
std::string use_address_;
|
std::string use_address_;
|
||||||
std::vector<WiFiAP> sta_;
|
std::vector<WiFiAP> sta_;
|
||||||
std::vector<WiFiSTAPriority> sta_priorities_;
|
std::vector<WiFiSTAPriority> sta_priorities_;
|
||||||
std::vector<WiFiScanResult> scan_result_;
|
FixedVector<WiFiScanResult> scan_result_;
|
||||||
WiFiAP selected_ap_;
|
WiFiAP selected_ap_;
|
||||||
WiFiAP ap_;
|
WiFiAP ap_;
|
||||||
optional<float> output_power_;
|
optional<float> output_power_;
|
||||||
|
|||||||
@@ -696,7 +696,15 @@ void WiFiComponent::wifi_scan_done_callback_(void *arg, STATUS status) {
|
|||||||
this->retry_connect();
|
this->retry_connect();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Count the number of results first
|
||||||
auto *head = reinterpret_cast<bss_info *>(arg);
|
auto *head = reinterpret_cast<bss_info *>(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)) {
|
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]},
|
WiFiScanResult res({it->bssid[0], it->bssid[1], it->bssid[2], it->bssid[3], it->bssid[4], it->bssid[5]},
|
||||||
std::string(reinterpret_cast<char *>(it->ssid), it->ssid_len), it->channel, it->rssi,
|
std::string(reinterpret_cast<char *>(it->ssid), it->ssid_len), it->channel, it->rssi,
|
||||||
|
|||||||
@@ -763,8 +763,9 @@ void WiFiComponent::wifi_process_event_(IDFWiFiEvent *data) {
|
|||||||
const auto &it = data->data.sta_scan_done;
|
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);
|
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;
|
this->scan_done_ = true;
|
||||||
|
scan_result_.clear();
|
||||||
|
|
||||||
if (it.status != 0) {
|
if (it.status != 0) {
|
||||||
// scan error
|
// scan error
|
||||||
return;
|
return;
|
||||||
@@ -784,7 +785,7 @@ void WiFiComponent::wifi_process_event_(IDFWiFiEvent *data) {
|
|||||||
}
|
}
|
||||||
records.resize(number);
|
records.resize(number);
|
||||||
|
|
||||||
scan_result_.reserve(number);
|
scan_result_.init(number);
|
||||||
for (int i = 0; i < number; i++) {
|
for (int i = 0; i < number; i++) {
|
||||||
auto &record = records[i];
|
auto &record = records[i];
|
||||||
bssid_t bssid;
|
bssid_t bssid;
|
||||||
|
|||||||
@@ -411,7 +411,7 @@ void WiFiComponent::wifi_scan_done_callback_() {
|
|||||||
if (num < 0)
|
if (num < 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
this->scan_result_.reserve(static_cast<unsigned int>(num));
|
this->scan_result_.init(static_cast<unsigned int>(num));
|
||||||
for (int i = 0; i < num; i++) {
|
for (int i = 0; i < num; i++) {
|
||||||
String ssid = WiFi.SSID(i);
|
String ssid = WiFi.SSID(i);
|
||||||
wifi_auth_mode_t authmode = WiFi.encryptionType(i);
|
wifi_auth_mode_t authmode = WiFi.encryptionType(i);
|
||||||
|
|||||||
@@ -340,8 +340,8 @@ void Application::calculate_looping_components_() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pre-reserve vector to avoid reallocations
|
// Initialize FixedVector with exact size - no reallocation possible
|
||||||
this->looping_components_.reserve(total_looping);
|
this->looping_components_.init(total_looping);
|
||||||
|
|
||||||
// Add all components with loop override that aren't already LOOP_DONE
|
// Add all components with loop override that aren't already LOOP_DONE
|
||||||
// Some components (like logger) may call disable_loop() during initialization
|
// Some components (like logger) may call disable_loop() during initialization
|
||||||
|
|||||||
@@ -472,7 +472,7 @@ class Application {
|
|||||||
// - When a component is enabled, it's swapped with the first inactive component
|
// - When a component is enabled, it's swapped with the first inactive component
|
||||||
// and active_end_ is incremented
|
// and active_end_ is incremented
|
||||||
// - This eliminates branch mispredictions from flag checking in the hot loop
|
// - This eliminates branch mispredictions from flag checking in the hot loop
|
||||||
std::vector<Component *> looping_components_{};
|
FixedVector<Component *> looping_components_{};
|
||||||
#ifdef USE_SOCKET_SELECT_SUPPORT
|
#ifdef USE_SOCKET_SELECT_SUPPORT
|
||||||
std::vector<int> socket_fds_; // Vector of all monitored socket file descriptors
|
std::vector<int> socket_fds_; // Vector of all monitored socket file descriptors
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -159,6 +159,80 @@ template<typename T, size_t N> class StaticVector {
|
|||||||
const_reverse_iterator rend() const { return const_reverse_iterator(begin()); }
|
const_reverse_iterator rend() const { return const_reverse_iterator(begin()); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Fixed-capacity vector - allocates once at runtime, never reallocates
|
||||||
|
/// This avoids std::vector template overhead (_M_realloc_insert, _M_default_append)
|
||||||
|
/// when size is known at initialization but not at compile time
|
||||||
|
template<typename T> class FixedVector {
|
||||||
|
private:
|
||||||
|
T *data_{nullptr};
|
||||||
|
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() { cleanup_(); }
|
||||||
|
|
||||||
|
// Disable copy to avoid accidental copies
|
||||||
|
FixedVector(const FixedVector &) = delete;
|
||||||
|
FixedVector &operator=(const FixedVector &) = delete;
|
||||||
|
|
||||||
|
// Allocate capacity - can be called multiple times to reinit
|
||||||
|
void init(size_t n) {
|
||||||
|
cleanup_();
|
||||||
|
data_ = nullptr;
|
||||||
|
capacity_ = 0;
|
||||||
|
size_ = 0;
|
||||||
|
if (n > 0) {
|
||||||
|
// Allocate raw memory without calling constructors
|
||||||
|
data_ = static_cast<T *>(::operator new(n * sizeof(T)));
|
||||||
|
capacity_ = n;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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_) {
|
||||||
|
// Use placement new to construct the object in pre-allocated memory
|
||||||
|
new (&data_[size_]) T(value);
|
||||||
|
size_++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t size() const { return size_; }
|
||||||
|
|
||||||
|
/// Access element without bounds checking (matches std::vector behavior)
|
||||||
|
/// 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_; }
|
||||||
|
};
|
||||||
|
|
||||||
///@}
|
///@}
|
||||||
|
|
||||||
/// @name Mathematics
|
/// @name Mathematics
|
||||||
|
|||||||
Reference in New Issue
Block a user