1
0
mirror of https://github.com/esphome/esphome.git synced 2025-10-31 23:21:54 +00:00

[select] Optimize SelectTraits with FixedVector for compile-time options

This commit is contained in:
J. Nick Koston
2025-10-21 12:15:45 -10:00
parent 8e8a2bde95
commit a966ac7255
9 changed files with 46 additions and 21 deletions

View File

@@ -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"];

View File

@@ -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<std::string> *options{};
const FixedVector<std::string> *options{};
void encode(ProtoWriteBuffer buffer) const override;
void calculate_size(ProtoSize &size) const override;
#ifdef HAS_PROTO_MESSAGE_DUMP

View File

@@ -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);

View File

@@ -300,11 +300,11 @@ void LvSelectable::set_selected_text(const std::string &text, lv_anim_enable_t a
}
}
void LvSelectable::set_options(std::vector<std::string> options) {
void LvSelectable::set_options(std::initializer_list<std::string> 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);

View File

@@ -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<std::string> get_options() { return this->options_; }
void set_options(std::vector<std::string> options);
const FixedVector<std::string> &get_options() { return this->options_; }
void set_options(std::initializer_list<std::string> options);
protected:
virtual void set_option_string(const char *options) = 0;
std::vector<std::string> options_{};
FixedVector<std::string> options_{};
};
#ifdef USE_LVGL_DROPDOWN

View File

@@ -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_;

View File

@@ -3,9 +3,9 @@
namespace esphome {
namespace select {
void SelectTraits::set_options(std::vector<std::string> options) { this->options_ = std::move(options); }
void SelectTraits::set_options(std::initializer_list<std::string> options) { this->options_ = options; }
const std::vector<std::string> &SelectTraits::get_options() const { return this->options_; }
const FixedVector<std::string> &SelectTraits::get_options() const { return this->options_; }
} // namespace select
} // namespace esphome

View File

@@ -1,18 +1,19 @@
#pragma once
#include <vector>
#include <string>
#include <initializer_list>
#include "esphome/core/helpers.h"
namespace esphome {
namespace select {
class SelectTraits {
public:
void set_options(std::vector<std::string> options);
const std::vector<std::string> &get_options() const;
void set_options(std::initializer_list<std::string> options);
const FixedVector<std::string> &get_options() const;
protected:
std::vector<std::string> options_;
FixedVector<std::string> options_;
};
} // namespace select

View File

@@ -194,12 +194,8 @@ template<typename T> class FixedVector {
size_ = 0;
}
public:
FixedVector() = default;
/// Constructor from initializer list - allocates exact size needed
/// This enables brace initialization: FixedVector<int> v = {1, 2, 3};
FixedVector(std::initializer_list<T> init_list) {
// Helper to assign from initializer list (shared by constructor and assignment operator)
void assign_from_initializer_list_(std::initializer_list<T> init_list) {
init(init_list.size());
size_t idx = 0;
for (const auto &item : init_list) {
@@ -209,6 +205,13 @@ template<typename T> class FixedVector {
size_ = init_list.size();
}
public:
FixedVector() = default;
/// Constructor from initializer list - allocates exact size needed
/// This enables brace initialization: FixedVector<int> v = {1, 2, 3};
FixedVector(std::initializer_list<T> init_list) { assign_from_initializer_list_(init_list); }
~FixedVector() { cleanup_(); }
// Disable copy operations (avoid accidental expensive copies)
@@ -234,6 +237,15 @@ template<typename T> class FixedVector {
return *this;
}
/// Assignment from initializer list - avoids temporary and move overhead
/// This enables: FixedVector<int> v; v = {1, 2, 3};
FixedVector &operator=(std::initializer_list<T> 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_();