From cb2fcaa9b1e076bce939700e8cc9e3d437c938a7 Mon Sep 17 00:00:00 2001 From: Fabian Date: Tue, 28 Mar 2023 08:38:56 +0200 Subject: [PATCH] `EntityBase` Name can stay in flash. (#4594) * `EntityBase`can stay in flash. * Trying to please the CI. --------- Co-authored-by: Your Name --- esphome/components/button/button.cpp | 3 - esphome/components/button/button.h | 3 - esphome/components/climate/climate.cpp | 5 - esphome/components/climate/climate.h | 5 - esphome/components/cover/cover.cpp | 3 +- esphome/components/cover/cover.h | 1 - .../components/esp32_camera/esp32_camera.cpp | 3 +- .../components/esp32_camera/esp32_camera.h | 1 - esphome/components/fan/fan.cpp | 3 - esphome/components/fan/fan.h | 4 - esphome/components/fan/fan_state.h | 1 - esphome/components/light/light_state.cpp | 1 - esphome/components/light/light_state.h | 3 - esphome/components/lock/lock.cpp | 3 +- esphome/components/lock/lock.h | 1 - esphome/components/partition/light.py | 2 +- esphome/components/sensor/sensor.cpp | 3 +- esphome/components/sensor/sensor.h | 1 - esphome/components/switch/switch.cpp | 3 +- esphome/components/switch/switch.h | 1 - .../components/text_sensor/text_sensor.cpp | 3 - esphome/components/text_sensor/text_sensor.h | 3 - esphome/core/entity_base.cpp | 12 +- esphome/core/entity_base.h | 10 +- esphome/core/string_ref.cpp | 12 ++ esphome/core/string_ref.h | 134 ++++++++++++++++++ 26 files changed, 161 insertions(+), 63 deletions(-) create mode 100644 esphome/core/string_ref.cpp create mode 100644 esphome/core/string_ref.h diff --git a/esphome/components/button/button.cpp b/esphome/components/button/button.cpp index 3d58780d6d..dfa417de7b 100644 --- a/esphome/components/button/button.cpp +++ b/esphome/components/button/button.cpp @@ -6,9 +6,6 @@ namespace button { static const char *const TAG = "button"; -Button::Button(const std::string &name) : EntityBase(name) {} -Button::Button() : Button("") {} - void Button::press() { ESP_LOGD(TAG, "'%s' Pressed.", this->get_name().c_str()); this->press_action(); diff --git a/esphome/components/button/button.h b/esphome/components/button/button.h index 3b5f338887..a4902810b2 100644 --- a/esphome/components/button/button.h +++ b/esphome/components/button/button.h @@ -28,9 +28,6 @@ namespace button { */ class Button : public EntityBase { public: - explicit Button(); - explicit Button(const std::string &name); - /** Press this button. This is called by the front-end. * * For implementing buttons, please override press_action. diff --git a/esphome/components/climate/climate.cpp b/esphome/components/climate/climate.cpp index 37572ae913..b4d5ee9685 100644 --- a/esphome/components/climate/climate.cpp +++ b/esphome/components/climate/climate.cpp @@ -453,12 +453,7 @@ void Climate::set_visual_temperature_step_override(float target, float current) this->visual_target_temperature_step_override_ = target; this->visual_current_temperature_step_override_ = current; } -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wdeprecated-declarations" -Climate::Climate(const std::string &name) : EntityBase(name) {} -#pragma GCC diagnostic pop -Climate::Climate() : Climate("") {} ClimateCall Climate::make_call() { return ClimateCall(this); } ClimateCall ClimateDeviceRestoreState::to_call(Climate *climate) { diff --git a/esphome/components/climate/climate.h b/esphome/components/climate/climate.h index 520036f718..43bd71657d 100644 --- a/esphome/components/climate/climate.h +++ b/esphome/components/climate/climate.h @@ -166,11 +166,6 @@ struct ClimateDeviceRestoreState { */ class Climate : public EntityBase { public: - /// Construct a climate device with empty name (will be set later). - Climate(); - /// Construct a climate device with a name. - Climate(const std::string &name); - /// The active mode of the climate device. ClimateMode mode{CLIMATE_MODE_OFF}; /// The active state of the climate device. diff --git a/esphome/components/cover/cover.cpp b/esphome/components/cover/cover.cpp index 902e9bca94..24dd88b698 100644 --- a/esphome/components/cover/cover.cpp +++ b/esphome/components/cover/cover.cpp @@ -31,7 +31,7 @@ const char *cover_operation_to_str(CoverOperation op) { } } -Cover::Cover(const std::string &name) : EntityBase(name), position{COVER_OPEN} {} +Cover::Cover() : position{COVER_OPEN} {} CoverCall::CoverCall(Cover *parent) : parent_(parent) {} CoverCall &CoverCall::set_command(const char *command) { @@ -204,7 +204,6 @@ optional Cover::restore_state_() { return {}; return recovered; } -Cover::Cover() : Cover("") {} std::string Cover::get_device_class() { if (this->device_class_override_.has_value()) return *this->device_class_override_; diff --git a/esphome/components/cover/cover.h b/esphome/components/cover/cover.h index 8ae9cfc8dd..c6a420fa97 100644 --- a/esphome/components/cover/cover.h +++ b/esphome/components/cover/cover.h @@ -111,7 +111,6 @@ const char *cover_operation_to_str(CoverOperation op); class Cover : public EntityBase { public: explicit Cover(); - explicit Cover(const std::string &name); /// The current operation of the cover (idle, opening, closing). CoverOperation current_operation{COVER_OPERATION_IDLE}; diff --git a/esphome/components/esp32_camera/esp32_camera.cpp b/esphome/components/esp32_camera/esp32_camera.cpp index 4a53748213..e4020a902e 100644 --- a/esphome/components/esp32_camera/esp32_camera.cpp +++ b/esphome/components/esp32_camera/esp32_camera.cpp @@ -202,7 +202,7 @@ void ESP32Camera::loop() { float ESP32Camera::get_setup_priority() const { return setup_priority::DATA; } /* ---------------- constructors ---------------- */ -ESP32Camera::ESP32Camera(const std::string &name) : EntityBase(name) { +ESP32Camera::ESP32Camera() { this->config_.pin_pwdn = -1; this->config_.pin_reset = -1; this->config_.pin_xclk = -1; @@ -215,7 +215,6 @@ ESP32Camera::ESP32Camera(const std::string &name) : EntityBase(name) { global_esp32_camera = this; } -ESP32Camera::ESP32Camera() : ESP32Camera("") {} /* ---------------- setters ---------------- */ /* set pin assignment */ diff --git a/esphome/components/esp32_camera/esp32_camera.h b/esphome/components/esp32_camera/esp32_camera.h index 62fdbabd06..5f88c6fda8 100644 --- a/esphome/components/esp32_camera/esp32_camera.h +++ b/esphome/components/esp32_camera/esp32_camera.h @@ -103,7 +103,6 @@ class CameraImageReader { /* ---------------- ESP32Camera class ---------------- */ class ESP32Camera : public Component, public EntityBase { public: - ESP32Camera(const std::string &name); ESP32Camera(); /* setters */ diff --git a/esphome/components/fan/fan.cpp b/esphome/components/fan/fan.cpp index c8a3064f6c..87566bad4a 100644 --- a/esphome/components/fan/fan.cpp +++ b/esphome/components/fan/fan.cpp @@ -80,9 +80,6 @@ void FanRestoreState::apply(Fan &fan) { fan.publish_state(); } -Fan::Fan() : EntityBase("") {} -Fan::Fan(const std::string &name) : EntityBase(name) {} - FanCall Fan::turn_on() { return this->make_call().set_state(true); } FanCall Fan::turn_off() { return this->make_call().set_state(false); } FanCall Fan::toggle() { return this->make_call().set_state(!this->state); } diff --git a/esphome/components/fan/fan.h b/esphome/components/fan/fan.h index 337bb3935a..f9d317e675 100644 --- a/esphome/components/fan/fan.h +++ b/esphome/components/fan/fan.h @@ -99,10 +99,6 @@ struct FanRestoreState { class Fan : public EntityBase { public: - Fan(); - /// Construct the fan with name. - explicit Fan(const std::string &name); - /// The current on/off state of the fan. bool state{false}; /// The current oscillation state of the fan. diff --git a/esphome/components/fan/fan_state.h b/esphome/components/fan/fan_state.h index 044ee59736..5926e700b0 100644 --- a/esphome/components/fan/fan_state.h +++ b/esphome/components/fan/fan_state.h @@ -15,7 +15,6 @@ enum ESPDEPRECATED("LegacyFanDirection members are deprecated, use FanDirection class ESPDEPRECATED("FanState is deprecated, use Fan instead.", "2022.2") FanState : public Fan, public Component { public: FanState() = default; - explicit FanState(const std::string &name) : Fan(name) {} /// Get the traits of this fan. FanTraits get_traits() override { return this->traits_; } diff --git a/esphome/components/light/light_state.cpp b/esphome/components/light/light_state.cpp index 64c29a346b..50ebd8882b 100644 --- a/esphome/components/light/light_state.cpp +++ b/esphome/components/light/light_state.cpp @@ -8,7 +8,6 @@ namespace light { static const char *const TAG = "light"; -LightState::LightState(const std::string &name, LightOutput *output) : EntityBase(name), output_(output) {} LightState::LightState(LightOutput *output) : output_(output) {} LightTraits LightState::get_traits() { return this->output_->get_traits(); } diff --git a/esphome/components/light/light_state.h b/esphome/components/light/light_state.h index 81f8be7207..ac4718ade5 100644 --- a/esphome/components/light/light_state.h +++ b/esphome/components/light/light_state.h @@ -33,9 +33,6 @@ enum LightRestoreMode { */ class LightState : public EntityBase, public Component { public: - /// Construct this LightState using the provided traits and name. - LightState(const std::string &name, LightOutput *output); - LightState(LightOutput *output); LightTraits get_traits(); diff --git a/esphome/components/lock/lock.cpp b/esphome/components/lock/lock.cpp index dbb8a941ad..ddc5445349 100644 --- a/esphome/components/lock/lock.cpp +++ b/esphome/components/lock/lock.cpp @@ -24,8 +24,7 @@ const char *lock_state_to_string(LockState state) { } } -Lock::Lock(const std::string &name) : EntityBase(name), state(LOCK_STATE_NONE) {} -Lock::Lock() : Lock("") {} +Lock::Lock() : state(LOCK_STATE_NONE) {} LockCall Lock::make_call() { return LockCall(this); } void Lock::lock() { diff --git a/esphome/components/lock/lock.h b/esphome/components/lock/lock.h index 52256691f6..7a98187a4f 100644 --- a/esphome/components/lock/lock.h +++ b/esphome/components/lock/lock.h @@ -103,7 +103,6 @@ class LockCall { class Lock : public EntityBase { public: explicit Lock(); - explicit Lock(const std::string &name); /** Make a lock device control call, this is used to control the lock device, see the LockCall description * for more info. diff --git a/esphome/components/partition/light.py b/esphome/components/partition/light.py index 73cda2c926..8e45915cf3 100644 --- a/esphome/components/partition/light.py +++ b/esphome/components/partition/light.py @@ -102,7 +102,7 @@ async def to_code(config): conf[CONF_ADDRESSABLE_LIGHT_ID], await cg.get_variable(conf[CONF_SINGLE_LIGHT_ID]), ) - light_state = cg.new_Pvariable(conf[CONF_LIGHT_ID], "", wrapper) + light_state = cg.new_Pvariable(conf[CONF_LIGHT_ID], wrapper) await cg.register_component(light_state, conf) segments.append(AddressableSegment(light_state, 0, 1, False)) diff --git a/esphome/components/sensor/sensor.cpp b/esphome/components/sensor/sensor.cpp index 0de452b784..fc66e03d6b 100644 --- a/esphome/components/sensor/sensor.cpp +++ b/esphome/components/sensor/sensor.cpp @@ -20,8 +20,7 @@ std::string state_class_to_string(StateClass state_class) { } } -Sensor::Sensor(const std::string &name) : EntityBase(name), state(NAN), raw_state(NAN) {} -Sensor::Sensor() : Sensor("") {} +Sensor::Sensor() : state(NAN), raw_state(NAN) {} std::string Sensor::get_unit_of_measurement() { if (this->unit_of_measurement_.has_value()) diff --git a/esphome/components/sensor/sensor.h b/esphome/components/sensor/sensor.h index e3651752cf..4308eafb12 100644 --- a/esphome/components/sensor/sensor.h +++ b/esphome/components/sensor/sensor.h @@ -57,7 +57,6 @@ std::string state_class_to_string(StateClass state_class); class Sensor : public EntityBase { public: explicit Sensor(); - explicit Sensor(const std::string &name); /// Get the unit of measurement, using the manual override if set. std::string get_unit_of_measurement(); diff --git a/esphome/components/switch/switch.cpp b/esphome/components/switch/switch.cpp index caa072b1ea..72e7add158 100644 --- a/esphome/components/switch/switch.cpp +++ b/esphome/components/switch/switch.cpp @@ -6,8 +6,7 @@ namespace switch_ { static const char *const TAG = "switch"; -Switch::Switch(const std::string &name) : EntityBase(name), state(false) {} -Switch::Switch() : Switch("") {} +Switch::Switch() : state(false) {} void Switch::turn_on() { ESP_LOGD(TAG, "'%s' Turning ON.", this->get_name().c_str()); diff --git a/esphome/components/switch/switch.h b/esphome/components/switch/switch.h index b89d8db6a5..8bea3b36db 100644 --- a/esphome/components/switch/switch.h +++ b/esphome/components/switch/switch.h @@ -32,7 +32,6 @@ enum SwitchRestoreMode { class Switch : public EntityBase { public: explicit Switch(); - explicit Switch(const std::string &name); /** Publish a state to the front-end from the back-end. * diff --git a/esphome/components/text_sensor/text_sensor.cpp b/esphome/components/text_sensor/text_sensor.cpp index d76ab7e27d..f10cd50267 100644 --- a/esphome/components/text_sensor/text_sensor.cpp +++ b/esphome/components/text_sensor/text_sensor.cpp @@ -6,9 +6,6 @@ namespace text_sensor { static const char *const TAG = "text_sensor"; -TextSensor::TextSensor() : TextSensor("") {} -TextSensor::TextSensor(const std::string &name) : EntityBase(name) {} - void TextSensor::publish_state(const std::string &state) { this->raw_state = state; this->raw_callback_.call(state); diff --git a/esphome/components/text_sensor/text_sensor.h b/esphome/components/text_sensor/text_sensor.h index cf7b6b86ef..996af02f7e 100644 --- a/esphome/components/text_sensor/text_sensor.h +++ b/esphome/components/text_sensor/text_sensor.h @@ -30,9 +30,6 @@ namespace text_sensor { class TextSensor : public EntityBase { public: - explicit TextSensor(); - explicit TextSensor(const std::string &name); - /// Getter-syntax for .state. std::string get_state() const; /// Getter-syntax for .raw_state diff --git a/esphome/core/entity_base.cpp b/esphome/core/entity_base.cpp index 49a73854a1..19ab57349d 100644 --- a/esphome/core/entity_base.cpp +++ b/esphome/core/entity_base.cpp @@ -6,16 +6,14 @@ namespace esphome { static const char *const TAG = "entity_base"; -EntityBase::EntityBase(std::string name) : name_(std::move(name)) { this->calc_object_id_(); } - // Entity Name -const std::string &EntityBase::get_name() const { return this->name_; } -void EntityBase::set_name(const std::string &name) { - if (name.empty()) { - this->name_ = App.get_friendly_name(); +const StringRef &EntityBase::get_name() const { return this->name_; } +void EntityBase::set_name(const char *name) { + this->name_ = StringRef(name); + if (this->name_.empty()) { + this->name_ = StringRef(App.get_friendly_name()); this->has_own_name_ = false; } else { - this->name_ = name; this->has_own_name_ = true; } this->calc_object_id_(); diff --git a/esphome/core/entity_base.h b/esphome/core/entity_base.h index 5ab1f7b424..e25aab21a9 100644 --- a/esphome/core/entity_base.h +++ b/esphome/core/entity_base.h @@ -2,6 +2,7 @@ #include #include +#include "string_ref.h" namespace esphome { @@ -14,12 +15,9 @@ enum EntityCategory : uint8_t { // The generic Entity base class that provides an interface common to all Entities. class EntityBase { public: - EntityBase() : EntityBase("") {} - explicit EntityBase(std::string name); - // Get/set the name of this Entity - const std::string &get_name() const; - void set_name(const std::string &name); + const StringRef &get_name() const; + void set_name(const char *name); // Get whether this Entity has its own name or it should use the device friendly_name. bool has_own_name() const { return this->has_own_name_; } @@ -54,7 +52,7 @@ class EntityBase { virtual uint32_t hash_base() { return 0L; } void calc_object_id_(); - std::string name_; + StringRef name_; bool has_own_name_{false}; std::string object_id_; const char *icon_c_str_{nullptr}; diff --git a/esphome/core/string_ref.cpp b/esphome/core/string_ref.cpp new file mode 100644 index 0000000000..ce1e33cbb7 --- /dev/null +++ b/esphome/core/string_ref.cpp @@ -0,0 +1,12 @@ +#include "string_ref.h" + +namespace esphome { + +#ifdef USE_JSON + +// NOLINTNEXTLINE(readability-identifier-naming) +void convertToJson(const StringRef &src, JsonVariant dst) { dst.set(src.c_str()); } + +#endif // USE_JSON + +} // namespace esphome diff --git a/esphome/core/string_ref.h b/esphome/core/string_ref.h new file mode 100644 index 0000000000..5940a7ee65 --- /dev/null +++ b/esphome/core/string_ref.h @@ -0,0 +1,134 @@ +#pragma once + +#include +#include +#include +#include "esphome/core/defines.h" + +#ifdef USE_JSON +#include "esphome/components/json/json_util.h" +#endif // USE_JSON + +namespace esphome { + +/** + * StringRef is a reference to a string owned by something else. So it behaves like simple string, but it does not own + * pointer. When it is default constructed, it has empty string. You can freely copy or move around this struct, but + * never free its pointer. str() function can be used to export the content as std::string. StringRef is adopted from + * + */ +class StringRef { + public: + using traits_type = std::char_traits; + using value_type = traits_type::char_type; + using allocator_type = std::allocator; + using size_type = std::allocator_traits::size_type; + using difference_type = std::allocator_traits::difference_type; + using const_reference = const value_type &; + using const_pointer = const value_type *; + using const_iterator = const_pointer; + using const_reverse_iterator = std::reverse_iterator; + + constexpr StringRef() : base_(""), len_(0) {} + explicit StringRef(const std::string &s) : base_(s.c_str()), len_(s.size()) {} + explicit StringRef(const char *s) : base_(s), len_(strlen(s)) {} + constexpr StringRef(const char *s, size_t n) : base_(s), len_(n) {} + template + constexpr StringRef(const CharT *s, size_t n) : base_(reinterpret_cast(s)), len_(n) {} + template + StringRef(InputIt first, InputIt last) + : base_(reinterpret_cast(&*first)), len_(std::distance(first, last)) {} + template + StringRef(InputIt *first, InputIt *last) + : base_(reinterpret_cast(first)), len_(std::distance(first, last)) {} + template constexpr static StringRef from_lit(const CharT (&s)[N]) { + return StringRef{s, N - 1}; + } + static StringRef from_maybe_nullptr(const char *s) { + if (s == nullptr) { + return StringRef(); + } + + return StringRef(s); + } + + constexpr const_iterator begin() const { return base_; }; + constexpr const_iterator cbegin() const { return base_; }; + + constexpr const_iterator end() const { return base_ + len_; }; + constexpr const_iterator cend() const { return base_ + len_; }; + + const_reverse_iterator rbegin() const { return const_reverse_iterator{base_ + len_}; } + const_reverse_iterator crbegin() const { return const_reverse_iterator{base_ + len_}; } + + const_reverse_iterator rend() const { return const_reverse_iterator{base_}; } + const_reverse_iterator crend() const { return const_reverse_iterator{base_}; } + + constexpr const char *c_str() const { return base_; } + constexpr size_type size() const { return len_; } + constexpr bool empty() const { return len_ == 0; } + constexpr const_reference operator[](size_type pos) const { return *(base_ + pos); } + + std::string str() const { return std::string(base_, len_); } + const uint8_t *byte() const { return reinterpret_cast(base_); } + + operator std::string() const { return str(); } + + private: + const char *base_; + size_type len_; +}; + +inline bool operator==(const StringRef &lhs, const StringRef &rhs) { + return lhs.size() == rhs.size() && std::equal(std::begin(lhs), std::end(lhs), std::begin(rhs)); +} + +inline bool operator==(const StringRef &lhs, const std::string &rhs) { + return lhs.size() == rhs.size() && std::equal(std::begin(lhs), std::end(lhs), std::begin(rhs)); +} + +inline bool operator==(const std::string &lhs, const StringRef &rhs) { return rhs == lhs; } + +inline bool operator==(const StringRef &lhs, const char *rhs) { + return lhs.size() == strlen(rhs) && std::equal(std::begin(lhs), std::end(lhs), rhs); +} + +inline bool operator==(const char *lhs, const StringRef &rhs) { return rhs == lhs; } + +inline bool operator!=(const StringRef &lhs, const StringRef &rhs) { return !(lhs == rhs); } + +inline bool operator!=(const StringRef &lhs, const std::string &rhs) { return !(lhs == rhs); } + +inline bool operator!=(const std::string &lhs, const StringRef &rhs) { return !(rhs == lhs); } + +inline bool operator!=(const StringRef &lhs, const char *rhs) { return !(lhs == rhs); } + +inline bool operator!=(const char *lhs, const StringRef &rhs) { return !(rhs == lhs); } + +inline bool operator<(const StringRef &lhs, const StringRef &rhs) { + return std::lexicographical_compare(std::begin(lhs), std::end(lhs), std::begin(rhs), std::end(rhs)); +} + +inline std::string &operator+=(std::string &lhs, const StringRef &rhs) { + lhs.append(rhs.c_str(), rhs.size()); + return lhs; +} + +inline std::string operator+(const char *lhs, const StringRef &rhs) { + auto str = std::string(lhs); + str.append(rhs.c_str(), rhs.size()); + return str; +} + +inline std::string operator+(const StringRef &lhs, const char *rhs) { + auto str = lhs.str(); + str.append(rhs); + return str; +} + +#ifdef USE_JSON +// NOLINTNEXTLINE(readability-identifier-naming) +void convertToJson(const StringRef &src, JsonVariant dst); +#endif // USE_JSON + +} // namespace esphome