diff --git a/esphome/components/api/api.proto b/esphome/components/api/api.proto index d202486cfa..104da3037d 100644 --- a/esphome/components/api/api.proto +++ b/esphome/components/api/api.proto @@ -1143,7 +1143,7 @@ message ListEntitiesSelectResponse { reserved 4; // Deprecated: was string unique_id string icon = 5 [(field_ifdef) = "USE_ENTITY_ICON"]; - repeated string options = 6 [(container_pointer) = "std::vector"]; + repeated string options = 6 [(container_pointer) = "FixedVector"]; bool disabled_by_default = 7; EntityCategory entity_category = 8; uint32 device_id = 9 [(field_ifdef) = "USE_DEVICES"]; diff --git a/esphome/components/api/api_pb2.h b/esphome/components/api/api_pb2.h index ed49498176..7213a56a09 100644 --- a/esphome/components/api/api_pb2.h +++ b/esphome/components/api/api_pb2.h @@ -1534,7 +1534,7 @@ class ListEntitiesSelectResponse final : public InfoResponseProtoMessage { #ifdef HAS_PROTO_MESSAGE_DUMP const char *message_name() const override { return "list_entities_select_response"; } #endif - const std::vector *options{}; + const FixedVector *options{}; void encode(ProtoWriteBuffer buffer) const override; void calculate_size(ProtoSize &size) const override; #ifdef HAS_PROTO_MESSAGE_DUMP diff --git a/esphome/components/copy/select/copy_select.cpp b/esphome/components/copy/select/copy_select.cpp index bdcbd0b42c..e412aa9d90 100644 --- a/esphome/components/copy/select/copy_select.cpp +++ b/esphome/components/copy/select/copy_select.cpp @@ -9,7 +9,12 @@ static const char *const TAG = "copy.select"; void CopySelect::setup() { source_->add_on_state_callback([this](const std::string &value, size_t index) { this->publish_state(value); }); - traits.set_options(source_->traits.get_options()); + // Copy options from source select + const auto &source_options = source_->traits.get_options(); + this->traits.options_.init(source_options.size()); + for (const auto &option : source_options) { + this->traits.options_.push_back(option); + } if (source_->has_state()) this->publish_state(source_->state); diff --git a/esphome/components/lvgl/lvgl_esphome.cpp b/esphome/components/lvgl/lvgl_esphome.cpp index 7a32691b53..94766691b8 100644 --- a/esphome/components/lvgl/lvgl_esphome.cpp +++ b/esphome/components/lvgl/lvgl_esphome.cpp @@ -300,11 +300,11 @@ void LvSelectable::set_selected_text(const std::string &text, lv_anim_enable_t a } } -void LvSelectable::set_options(std::vector options) { +void LvSelectable::set_options(std::initializer_list options) { auto index = this->get_selected_index(); if (index >= options.size()) index = options.size() - 1; - this->options_ = std::move(options); + this->options_ = options; this->set_option_string(join_string(this->options_).c_str()); lv_event_send(this->obj, LV_EVENT_REFRESH, nullptr); this->set_selected_index(index, LV_ANIM_OFF); diff --git a/esphome/components/lvgl/lvgl_esphome.h b/esphome/components/lvgl/lvgl_esphome.h index 3ae67e8a0b..d18d954400 100644 --- a/esphome/components/lvgl/lvgl_esphome.h +++ b/esphome/components/lvgl/lvgl_esphome.h @@ -358,12 +358,12 @@ class LvSelectable : public LvCompound { virtual void set_selected_index(size_t index, lv_anim_enable_t anim) = 0; void set_selected_text(const std::string &text, lv_anim_enable_t anim); std::string get_selected_text(); - std::vector get_options() { return this->options_; } - void set_options(std::vector options); + const FixedVector &get_options() { return this->options_; } + void set_options(std::initializer_list options); protected: virtual void set_option_string(const char *options) = 0; - std::vector options_{}; + FixedVector options_{}; }; #ifdef USE_LVGL_DROPDOWN diff --git a/esphome/components/lvgl/select/lvgl_select.h b/esphome/components/lvgl/select/lvgl_select.h index a0e60295a6..e5dfc68436 100644 --- a/esphome/components/lvgl/select/lvgl_select.h +++ b/esphome/components/lvgl/select/lvgl_select.h @@ -53,7 +53,14 @@ class LVGLSelect : public select::Select, public Component { this->widget_->set_selected_text(value, this->anim_); this->publish(); } - void set_options_() { this->traits.set_options(this->widget_->get_options()); } + void set_options_() { + // Copy options from lvgl widget to select traits + const auto &widget_options = this->widget_->get_options(); + this->traits.options_.init(widget_options.size()); + for (const auto &option : widget_options) { + this->traits.options_.push_back(option); + } + } LvSelectable *widget_; lv_anim_enable_t anim_; diff --git a/esphome/components/select/select_traits.cpp b/esphome/components/select/select_traits.cpp index a8cd4290c8..497bffbe01 100644 --- a/esphome/components/select/select_traits.cpp +++ b/esphome/components/select/select_traits.cpp @@ -3,9 +3,9 @@ namespace esphome { namespace select { -void SelectTraits::set_options(std::vector options) { this->options_ = std::move(options); } +void SelectTraits::set_options(std::initializer_list options) { this->options_ = options; } -const std::vector &SelectTraits::get_options() const { return this->options_; } +const FixedVector &SelectTraits::get_options() const { return this->options_; } } // namespace select } // namespace esphome diff --git a/esphome/components/select/select_traits.h b/esphome/components/select/select_traits.h index 128066dd6b..e37ce8f77f 100644 --- a/esphome/components/select/select_traits.h +++ b/esphome/components/select/select_traits.h @@ -1,18 +1,19 @@ #pragma once -#include #include +#include +#include "esphome/core/helpers.h" namespace esphome { namespace select { class SelectTraits { public: - void set_options(std::vector options); - const std::vector &get_options() const; + void set_options(std::initializer_list options); + const FixedVector &get_options() const; protected: - std::vector options_; + FixedVector options_; }; } // namespace select diff --git a/esphome/core/helpers.h b/esphome/core/helpers.h index 234d2a7d7d..9b0591c9c5 100644 --- a/esphome/core/helpers.h +++ b/esphome/core/helpers.h @@ -194,12 +194,8 @@ template class FixedVector { size_ = 0; } - public: - FixedVector() = default; - - /// Constructor from initializer list - allocates exact size needed - /// This enables brace initialization: FixedVector v = {1, 2, 3}; - FixedVector(std::initializer_list init_list) { + // Helper to assign from initializer list (shared by constructor and assignment operator) + void assign_from_initializer_list_(std::initializer_list init_list) { init(init_list.size()); size_t idx = 0; for (const auto &item : init_list) { @@ -209,6 +205,13 @@ template class FixedVector { size_ = init_list.size(); } + public: + FixedVector() = default; + + /// Constructor from initializer list - allocates exact size needed + /// This enables brace initialization: FixedVector v = {1, 2, 3}; + FixedVector(std::initializer_list init_list) { assign_from_initializer_list_(init_list); } + ~FixedVector() { cleanup_(); } // Disable copy operations (avoid accidental expensive copies) @@ -234,6 +237,15 @@ template class FixedVector { return *this; } + /// Assignment from initializer list - avoids temporary and move overhead + /// This enables: FixedVector v; v = {1, 2, 3}; + FixedVector &operator=(std::initializer_list init_list) { + cleanup_(); + reset_(); + assign_from_initializer_list_(init_list); + return *this; + } + // Allocate capacity - can be called multiple times to reinit void init(size_t n) { cleanup_();