mirror of
https://github.com/esphome/esphome.git
synced 2026-06-24 16:20:42 +00:00
74 lines
2.4 KiB
C++
74 lines
2.4 KiB
C++
#pragma once
|
|
|
|
#include <cstdint>
|
|
#include <cstring>
|
|
#include <memory>
|
|
|
|
#include "esphome/core/defines.h"
|
|
#include "esphome/core/helpers.h"
|
|
|
|
namespace esphome::api {
|
|
|
|
/// Helper to use make_unique_for_overwrite where available (skips zero-fill),
|
|
/// falling back to make_unique on older GCC (ESP8266, LibreTiny).
|
|
inline std::unique_ptr<uint8_t[]> make_buffer(size_t n) {
|
|
#if defined(USE_ESP8266) || defined(USE_LIBRETINY)
|
|
return std::make_unique<uint8_t[]>(n);
|
|
#else
|
|
return std::make_unique_for_overwrite<uint8_t[]>(n);
|
|
#endif
|
|
}
|
|
|
|
/// Byte buffer that skips zero-initialization on resize().
|
|
///
|
|
/// std::vector<uint8_t>::resize() zero-fills new bytes via memset. For the
|
|
/// shared protobuf write buffer, every byte is overwritten by the encoder,
|
|
/// making the zero-fill pure waste. For the receive buffer, bytes are
|
|
/// overwritten by socket reads.
|
|
///
|
|
/// Designed for bulk clear/resize/overwrite patterns. grow_() allocates
|
|
/// exactly the requested size (no growth factor) since callers resize to
|
|
/// known sizes rather than appending incrementally.
|
|
///
|
|
/// Safe because: callers always write exactly the number of bytes they
|
|
/// resize for. In the protobuf write path, debug_check_bounds_ validates
|
|
/// writes in debug builds.
|
|
class APIBuffer {
|
|
public:
|
|
void clear() { this->size_ = 0; }
|
|
inline void reserve(size_t n) ESPHOME_ALWAYS_INLINE {
|
|
if (n > this->capacity_)
|
|
this->grow_(n);
|
|
}
|
|
inline void resize(size_t n) ESPHOME_ALWAYS_INLINE {
|
|
this->reserve(n);
|
|
this->size_ = n; // no zero-fill
|
|
}
|
|
/// Reserve capacity for max(reserve_size, new_size) bytes, then set size to new_size.
|
|
/// Single grow_ check regardless of argument order.
|
|
inline void reserve_and_resize(size_t reserve_size, size_t new_size) ESPHOME_ALWAYS_INLINE {
|
|
this->reserve(std::max(reserve_size, new_size));
|
|
this->size_ = new_size;
|
|
}
|
|
uint8_t *data() { return this->data_.get(); }
|
|
const uint8_t *data() const { return this->data_.get(); }
|
|
size_t size() const { return this->size_; }
|
|
bool empty() const { return this->size_ == 0; }
|
|
uint8_t &operator[](size_t i) { return this->data_[i]; }
|
|
const uint8_t &operator[](size_t i) const { return this->data_[i]; }
|
|
/// Release all memory (equivalent to std::vector swap trick).
|
|
void release() {
|
|
this->data_.reset();
|
|
this->size_ = 0;
|
|
this->capacity_ = 0;
|
|
}
|
|
|
|
protected:
|
|
void grow_(size_t n);
|
|
std::unique_ptr<uint8_t[]> data_;
|
|
size_t size_{0};
|
|
size_t capacity_{0};
|
|
};
|
|
|
|
} // namespace esphome::api
|