mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-29 22:24:26 +00:00 
			
		
		
		
	fixed_vector, bluetooth services
This commit is contained in:
		| @@ -1519,7 +1519,7 @@ message BluetoothGATTCharacteristic { | ||||
|   repeated uint64 uuid = 1 [(fixed_array_size) = 2, (fixed_array_skip_zero) = true]; | ||||
|   uint32 handle = 2; | ||||
|   uint32 properties = 3; | ||||
|   repeated BluetoothGATTDescriptor descriptors = 4; | ||||
|   repeated BluetoothGATTDescriptor descriptors = 4 [(fixed_vector) = true]; | ||||
|  | ||||
|   // New field for efficient UUID (v1.12+) | ||||
|   // Only one of uuid or short_uuid will be set. | ||||
| @@ -1531,7 +1531,7 @@ message BluetoothGATTCharacteristic { | ||||
| message BluetoothGATTService { | ||||
|   repeated uint64 uuid = 1 [(fixed_array_size) = 2, (fixed_array_skip_zero) = true]; | ||||
|   uint32 handle = 2; | ||||
|   repeated BluetoothGATTCharacteristic characteristics = 3; | ||||
|   repeated BluetoothGATTCharacteristic characteristics = 3 [(fixed_vector) = true]; | ||||
|  | ||||
|   // New field for efficient UUID (v1.12+) | ||||
|   // Only one of uuid or short_uuid will be set. | ||||
|   | ||||
| @@ -64,4 +64,10 @@ extend google.protobuf.FieldOptions { | ||||
|     // This is typically done through methods returning const T& or special accessor | ||||
|     // methods like get_options() or supported_modes_for_api_(). | ||||
|     optional string container_pointer = 50001; | ||||
|  | ||||
|     // fixed_vector: Use FixedVector instead of std::vector for repeated fields | ||||
|     // When set, the repeated field will use FixedVector<T> which requires calling | ||||
|     // init(size) before adding elements. This eliminates std::vector template overhead | ||||
|     // and is ideal when the exact size is known before populating the array. | ||||
|     optional bool fixed_vector = 50013 [default=false]; | ||||
| } | ||||
|   | ||||
| @@ -1923,7 +1923,7 @@ class BluetoothGATTCharacteristic final : public ProtoMessage { | ||||
|   std::array<uint64_t, 2> uuid{}; | ||||
|   uint32_t handle{0}; | ||||
|   uint32_t properties{0}; | ||||
|   std::vector<BluetoothGATTDescriptor> descriptors{}; | ||||
|   FixedVector<BluetoothGATTDescriptor> descriptors{}; | ||||
|   uint32_t short_uuid{0}; | ||||
|   void encode(ProtoWriteBuffer buffer) const override; | ||||
|   void calculate_size(ProtoSize &size) const override; | ||||
| @@ -1937,7 +1937,7 @@ class BluetoothGATTService final : public ProtoMessage { | ||||
|  public: | ||||
|   std::array<uint64_t, 2> uuid{}; | ||||
|   uint32_t handle{0}; | ||||
|   std::vector<BluetoothGATTCharacteristic> characteristics{}; | ||||
|   FixedVector<BluetoothGATTCharacteristic> characteristics{}; | ||||
|   uint32_t short_uuid{0}; | ||||
|   void encode(ProtoWriteBuffer buffer) const override; | ||||
|   void calculate_size(ProtoSize &size) const override; | ||||
|   | ||||
| @@ -749,13 +749,29 @@ class ProtoSize { | ||||
|   template<typename MessageType> | ||||
|   inline void add_repeated_message(uint32_t field_id_size, const std::vector<MessageType> &messages) { | ||||
|     // Skip if the vector is empty | ||||
|     if (messages.empty()) { | ||||
|       return; | ||||
|     if (!messages.empty()) { | ||||
|       // Use the force version for all messages in the repeated field | ||||
|       for (const auto &message : messages) { | ||||
|         add_message_object_force(field_id_size, message); | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|  | ||||
|     // Use the force version for all messages in the repeated field | ||||
|     for (const auto &message : messages) { | ||||
|       add_message_object_force(field_id_size, message); | ||||
|   /** | ||||
|    * @brief Calculates and adds the sizes of all messages in a repeated field to the total message size (FixedVector | ||||
|    * version) | ||||
|    * | ||||
|    * @tparam MessageType The type of the nested messages in the FixedVector | ||||
|    * @param messages FixedVector of message objects | ||||
|    */ | ||||
|   template<typename MessageType> | ||||
|   inline void add_repeated_message(uint32_t field_id_size, const FixedVector<MessageType> &messages) { | ||||
|     // Skip if the fixed vector is empty | ||||
|     if (!messages.empty()) { | ||||
|       // Use the force version for all messages in the repeated field | ||||
|       for (const auto &message : messages) { | ||||
|         add_message_object_force(field_id_size, message); | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| }; | ||||
|   | ||||
| @@ -230,8 +230,8 @@ void BluetoothConnection::send_service_for_discovery_() { | ||||
|     service_resp.handle = service_result.start_handle; | ||||
|  | ||||
|     if (total_char_count > 0) { | ||||
|       // Reserve space and process characteristics | ||||
|       service_resp.characteristics.reserve(total_char_count); | ||||
|       // Initialize FixedVector with exact count and process characteristics | ||||
|       service_resp.characteristics.init(total_char_count); | ||||
|       uint16_t char_offset = 0; | ||||
|       esp_gattc_char_elem_t char_result; | ||||
|       while (true) {  // characteristics | ||||
| @@ -275,8 +275,8 @@ void BluetoothConnection::send_service_for_discovery_() { | ||||
|           continue; | ||||
|         } | ||||
|  | ||||
|         // Reserve space and process descriptors | ||||
|         characteristic_resp.descriptors.reserve(total_desc_count); | ||||
|         // Initialize FixedVector with exact count and process descriptors | ||||
|         characteristic_resp.descriptors.init(total_desc_count); | ||||
|         uint16_t desc_offset = 0; | ||||
|         esp_gattc_descr_elem_t desc_result; | ||||
|         while (true) {  // descriptors | ||||
|   | ||||
| @@ -181,6 +181,31 @@ template<typename T> class FixedVector { | ||||
|   FixedVector(const FixedVector &) = delete; | ||||
|   FixedVector &operator=(const FixedVector &) = delete; | ||||
|  | ||||
|   // Enable move semantics for use in containers | ||||
|   FixedVector(FixedVector &&other) noexcept : data_(other.data_), size_(other.size_), capacity_(other.capacity_) { | ||||
|     other.data_ = nullptr; | ||||
|     other.size_ = 0; | ||||
|     other.capacity_ = 0; | ||||
|   } | ||||
|  | ||||
|   FixedVector &operator=(FixedVector &&other) noexcept { | ||||
|     if (this != &other) { | ||||
|       // Delete our current data | ||||
|       if (data_ != nullptr) { | ||||
|         delete[] data_; | ||||
|       } | ||||
|       // Take ownership of other's data | ||||
|       data_ = other.data_; | ||||
|       size_ = other.size_; | ||||
|       capacity_ = other.capacity_; | ||||
|       // Leave other in valid empty state | ||||
|       other.data_ = nullptr; | ||||
|       other.size_ = 0; | ||||
|       other.capacity_ = 0; | ||||
|     } | ||||
|     return *this; | ||||
|   } | ||||
|  | ||||
|   // Allocate capacity - can only be called once on empty vector | ||||
|   void init(size_t n) { | ||||
|     if (data_ == nullptr && n > 0) { | ||||
| @@ -199,12 +224,33 @@ template<typename T> class FixedVector { | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   /// Construct element in place and return reference | ||||
|   /// Caller must ensure sufficient capacity was allocated via init() | ||||
|   T &emplace_back() { | ||||
|     if (size_ < capacity_) { | ||||
|       return data_[size_++]; | ||||
|     } | ||||
|     // Should never happen with proper init() - return last element to avoid crash | ||||
|     return data_[capacity_ - 1]; | ||||
|   } | ||||
|  | ||||
|   /// Access last element | ||||
|   T &back() { return data_[size_ - 1]; } | ||||
|   const T &back() const { return data_[size_ - 1]; } | ||||
|  | ||||
|   size_t size() const { return size_; } | ||||
|   bool empty() const { return size_ == 0; } | ||||
|  | ||||
|   /// 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]; } | ||||
|  | ||||
|   /// Iterators 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_; } | ||||
| }; | ||||
|  | ||||
| ///@} | ||||
|   | ||||
		Reference in New Issue
	
	Block a user