diff --git a/esphome/components/api/api_frame_helper.cpp b/esphome/components/api/api_frame_helper.cpp index 3d6bc95163..e9751ac8dc 100644 --- a/esphome/components/api/api_frame_helper.cpp +++ b/esphome/components/api/api_frame_helper.cpp @@ -5,6 +5,7 @@ #include "esphome/core/helpers.h" #include "esphome/core/application.h" #include "proto.h" +#include "api_pb2_size.h" #include namespace esphome { @@ -574,6 +575,8 @@ APIError APINoiseFrameHelper::write_raw_(const struct iovec *iov, int iovcnt) { if (!tx_buf_.empty()) { // tx buf not empty, can't write now because then stream would be inconsistent + // Reserve space upfront to avoid multiple reallocations + tx_buf_.reserve(tx_buf_.size() + total_write_len); for (int i = 0; i < iovcnt; i++) { tx_buf_.insert(tx_buf_.end(), reinterpret_cast(iov[i].iov_base), reinterpret_cast(iov[i].iov_base) + iov[i].iov_len); @@ -584,6 +587,8 @@ APIError APINoiseFrameHelper::write_raw_(const struct iovec *iov, int iovcnt) { ssize_t sent = socket_->writev(iov, iovcnt); if (is_would_block(sent)) { // operation would block, add buffer to tx_buf + // Reserve space upfront to avoid multiple reallocations + tx_buf_.reserve(tx_buf_.size() + total_write_len); for (int i = 0; i < iovcnt; i++) { tx_buf_.insert(tx_buf_.end(), reinterpret_cast(iov[i].iov_base), reinterpret_cast(iov[i].iov_base) + iov[i].iov_len); @@ -596,6 +601,10 @@ APIError APINoiseFrameHelper::write_raw_(const struct iovec *iov, int iovcnt) { return APIError::SOCKET_WRITE_FAILED; } else if ((size_t) sent != total_write_len) { // partially sent, add end to tx_buf + size_t remaining = total_write_len - sent; + // Reserve space upfront to avoid multiple reallocations + tx_buf_.reserve(tx_buf_.size() + remaining); + size_t to_consume = sent; for (int i = 0; i < iovcnt; i++) { if (to_consume >= iov[i].iov_len) { @@ -933,6 +942,8 @@ APIError APIPlaintextFrameHelper::write_packet(uint16_t type, const uint8_t *pay } std::vector header; + header.reserve(1 + api::ProtoSize::varint(static_cast(payload_len)) + + api::ProtoSize::varint(static_cast(type))); header.push_back(0x00); ProtoVarInt(payload_len).encode(header); ProtoVarInt(type).encode(header); @@ -994,6 +1005,8 @@ APIError APIPlaintextFrameHelper::write_raw_(const struct iovec *iov, int iovcnt if (!tx_buf_.empty()) { // tx buf not empty, can't write now because then stream would be inconsistent + // Reserve space upfront to avoid multiple reallocations + tx_buf_.reserve(tx_buf_.size() + total_write_len); for (int i = 0; i < iovcnt; i++) { tx_buf_.insert(tx_buf_.end(), reinterpret_cast(iov[i].iov_base), reinterpret_cast(iov[i].iov_base) + iov[i].iov_len); @@ -1004,6 +1017,8 @@ APIError APIPlaintextFrameHelper::write_raw_(const struct iovec *iov, int iovcnt ssize_t sent = socket_->writev(iov, iovcnt); if (is_would_block(sent)) { // operation would block, add buffer to tx_buf + // Reserve space upfront to avoid multiple reallocations + tx_buf_.reserve(tx_buf_.size() + total_write_len); for (int i = 0; i < iovcnt; i++) { tx_buf_.insert(tx_buf_.end(), reinterpret_cast(iov[i].iov_base), reinterpret_cast(iov[i].iov_base) + iov[i].iov_len); @@ -1016,6 +1031,10 @@ APIError APIPlaintextFrameHelper::write_raw_(const struct iovec *iov, int iovcnt return APIError::SOCKET_WRITE_FAILED; } else if ((size_t) sent != total_write_len) { // partially sent, add end to tx_buf + size_t remaining = total_write_len - sent; + // Reserve space upfront to avoid multiple reallocations + tx_buf_.reserve(tx_buf_.size() + remaining); + size_t to_consume = sent; for (int i = 0; i < iovcnt; i++) { if (to_consume >= iov[i].iov_len) {