mirror of
				https://github.com/esphome/esphome.git
				synced 2025-11-03 16:41:50 +00:00 
			
		
		
		
	Compare commits
	
		
			4 Commits
		
	
	
		
			more_flexi
			...
			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
 | 
			
		||||
// 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<WiFiScanResult> &results) {
 | 
			
		||||
static void insertion_sort_scan_results(FixedVector<WiFiScanResult> &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
 | 
			
		||||
 
 | 
			
		||||
@@ -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<WiFiScanResult> &get_scan_result() const { return scan_result_; }
 | 
			
		||||
  const FixedVector<WiFiScanResult> &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<WiFiAP> sta_;
 | 
			
		||||
  std::vector<WiFiSTAPriority> sta_priorities_;
 | 
			
		||||
  std::vector<WiFiScanResult> scan_result_;
 | 
			
		||||
  FixedVector<WiFiScanResult> scan_result_;
 | 
			
		||||
  WiFiAP selected_ap_;
 | 
			
		||||
  WiFiAP ap_;
 | 
			
		||||
  optional<float> output_power_;
 | 
			
		||||
 
 | 
			
		||||
@@ -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<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)) {
 | 
			
		||||
    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,
 | 
			
		||||
 
 | 
			
		||||
@@ -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;
 | 
			
		||||
 
 | 
			
		||||
@@ -411,7 +411,7 @@ void WiFiComponent::wifi_scan_done_callback_() {
 | 
			
		||||
  if (num < 0)
 | 
			
		||||
    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++) {
 | 
			
		||||
    String ssid = WiFi.SSID(i);
 | 
			
		||||
    wifi_auth_mode_t authmode = WiFi.encryptionType(i);
 | 
			
		||||
 
 | 
			
		||||
@@ -340,8 +340,8 @@ void Application::calculate_looping_components_() {
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Pre-reserve vector to avoid reallocations
 | 
			
		||||
  this->looping_components_.reserve(total_looping);
 | 
			
		||||
  // Initialize FixedVector with exact size - no reallocation possible
 | 
			
		||||
  this->looping_components_.init(total_looping);
 | 
			
		||||
 | 
			
		||||
  // Add all components with loop override that aren't already LOOP_DONE
 | 
			
		||||
  // 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
 | 
			
		||||
  //   and active_end_ is incremented
 | 
			
		||||
  // - 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
 | 
			
		||||
  std::vector<int> socket_fds_;  // Vector of all monitored socket file descriptors
 | 
			
		||||
#endif
 | 
			
		||||
 
 | 
			
		||||
@@ -159,6 +159,80 @@ template<typename T, size_t N> class StaticVector {
 | 
			
		||||
  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
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user