diff --git a/src/core/emsfactory.h b/src/core/emsfactory.h index 44e78b607..771aad4af 100644 --- a/src/core/emsfactory.h +++ b/src/core/emsfactory.h @@ -39,23 +39,22 @@ class EMSFactory { public: virtual ~EMSFactory() = default; - // Register factory object of derived class using the device_type as the unique identifier - static auto registerFactory(const uint8_t device_type, EMSFactory * factory) -> void { - auto & reg = EMSFactory::getRegister(); - reg[device_type] = factory; - } - using FactoryMap = std::map; + // Register factory object of derived class using the device_type as the unique identifier + static inline auto registerFactory(const uint8_t device_type, EMSFactory * factory) -> void { + getRegister()[device_type] = factory; + } + // returns all registered classes (really only for debugging) - static auto device_handlers() -> const FactoryMap & { - return EMSFactory::getRegister(); + static inline auto device_handlers() -> const FactoryMap & { + return getRegister(); } // Construct derived class returning an unique ptr static auto add(const uint8_t device_type, uint8_t device_id, uint8_t product_id, const char * version, const char * default_name, uint8_t flags, uint8_t brand) -> std::unique_ptr { - if (auto * ptr = EMSFactory::makeRaw(device_type, device_id, product_id, version, default_name, flags, brand)) { + if (auto * ptr = makeRaw(device_type, device_id, product_id, version, default_name, flags, brand)) { return std::unique_ptr(ptr); } return nullptr; @@ -66,7 +65,7 @@ class EMSFactory { private: // Force global variable to be initialized, thus it avoids the "initialization order fiasco" - static auto getRegister() -> FactoryMap & { + static inline auto getRegister() -> FactoryMap & { static FactoryMap classRegister{}; return classRegister; } @@ -75,12 +74,9 @@ class EMSFactory { // find which EMS device it is and use that class static auto makeRaw(const uint8_t device_type, uint8_t device_id, uint8_t product_id, const char * version, const char * name, uint8_t flags, uint8_t brand) -> EMSdevice * { - auto & reg = EMSFactory::getRegister(); - auto it = reg.find(device_type); - if (it != reg.end()) { - return it->second->construct(device_type, device_id, product_id, version, name, flags, brand); - } - return nullptr; + const auto & reg = getRegister(); + const auto it = reg.find(device_type); + return (it != reg.end()) ? it->second->construct(device_type, device_id, product_id, version, name, flags, brand) : nullptr; } }; @@ -88,7 +84,7 @@ template class ConcreteEMSFactory : EMSFactory { public: // Register this global object on the EMSFactory register - ConcreteEMSFactory(const uint8_t device_type) { + explicit ConcreteEMSFactory(const uint8_t device_type) { EMSFactory::registerFactory(device_type, this); } diff --git a/src/core/shuntingYard.cpp b/src/core/shuntingYard.cpp index 62e738bfb..d90b0a9c7 100644 --- a/src/core/shuntingYard.cpp +++ b/src/core/shuntingYard.cpp @@ -344,8 +344,12 @@ bool isnum(const std::string & s) { std::string commands(std::string & expr, bool quotes) { auto expr_new = Helpers::toLower(expr); for (uint8_t device = 0; device < EMSdevice::DeviceType::UNKNOWN; device++) { - std::string d = (std::string)EMSdevice::device_type_2_device_name(device) + "/"; - auto f = expr_new.find(d); + // Optimized: build string with reserve to avoid temporary allocations + std::string d; + d.reserve(32); // typical device name length + "/" + d = EMSdevice::device_type_2_device_name(device); + d += "/"; + auto f = expr_new.find(d); while (f != std::string::npos) { // entity names are alphanumeric or _ auto e = expr_new.find_first_not_of("/._abcdefghijklmnopqrstuvwxyz0123456789", f); @@ -367,9 +371,11 @@ std::string commands(std::string & expr, bool quotes) { JsonDocument doc_in; JsonObject output = doc_out.to(); JsonObject input = doc_in.to(); - std::string cmd_s = "api/" + std::string(cmd); + // Optimized: use stack buffer for small strings to avoid heap allocation + char cmd_s[COMMAND_MAX_LENGTH + 5]; // "api/" prefix + cmd + snprintf(cmd_s, sizeof(cmd_s), "api/%s", cmd); - auto return_code = Command::process(cmd_s.c_str(), true, input, output); + auto return_code = Command::process(cmd_s, true, input, output); // check for no value (entity is valid but has no value set) if (return_code != CommandRet::OK && return_code != CommandRet::NO_VALUE) { return expr = ""; @@ -725,7 +731,7 @@ std::string compute(const std::string & expr) { // if there is data, force a POST if (value.length() || Helpers::toLower(method) == "post") { if (value.find_first_of('{') != std::string::npos) { - http.addHeader("Content-Type", "application/json"); // auto-set to JSON + http.addHeader(asyncsrv::T_Content_Type, asyncsrv::T_application_json, false); // auto-set to JSON } httpResult = http.POST(value.c_str()); } else { diff --git a/src/web/WebSchedulerService.cpp b/src/web/WebSchedulerService.cpp index 943d30b21..70da3063f 100644 --- a/src/web/WebSchedulerService.cpp +++ b/src/web/WebSchedulerService.cpp @@ -248,18 +248,24 @@ void WebSchedulerService::publish(const bool force) { snprintf(val_obj, sizeof(val_obj), "value_json['%s']", scheduleItem.name); snprintf(val_cond, sizeof(val_cond), "%s is defined", val_obj); + // Optimized: use stack buffer instead of string concatenation to avoid heap allocations + char val_tpl[150]; if (Mqtt::discovery_type() == Mqtt::discoveryType::HOMEASSISTANT) { - config["val_tpl"] = (std::string) "{{" + val_obj + " if " + val_cond + "}}"; + snprintf(val_tpl, sizeof(val_tpl), "{{%s if %s}}", val_obj, val_cond); } else { - config["val_tpl"] = (std::string) "{{" + val_obj + "}}"; // omit value conditional Jinja2 template code + snprintf(val_tpl, sizeof(val_tpl), "{{%s}}", val_obj); // omit value conditional Jinja2 template code } + config["val_tpl"] = val_tpl; char uniq_s[70]; snprintf(uniq_s, sizeof(uniq_s), "%s_%s", F_(scheduler), scheduleItem.name); config["uniq_id"] = uniq_s; config["name"] = (const char *)scheduleItem.name; - config["def_ent_id"] = std::string("switch.") + uniq_s; + // Optimized: use stack buffer instead of string concatenation + char def_ent_id[80]; + snprintf(def_ent_id, sizeof(def_ent_id), "switch.%s", uniq_s); + config["def_ent_id"] = def_ent_id; char topic[Mqtt::MQTT_TOPIC_MAX_SIZE]; char command_topic[Mqtt::MQTT_TOPIC_MAX_SIZE]; @@ -331,7 +337,7 @@ bool WebSchedulerService::command(const char * name, const std::string & command int httpResult = 0; if (value.length() || method == "post") { // we have all lowercase if (value.find_first_of('{') != std::string::npos) { - http.addHeader("Content-Type", "application/json"); // auto-set to JSON + http.addHeader(asyncsrv::T_Content_Type, asyncsrv::T_application_json, false); // auto-set to JSON } httpResult = http.POST(value.c_str()); } else {