28 : start_pattern_(start_pattern), end_pattern_(end_pattern), max_length_(max_length), state_(State::Sync) {
29 if (start_pattern_.empty() && end_pattern_.empty()) {
30 throw std::invalid_argument(
"PacketFramer: start_pattern and end_pattern cannot both be empty.");
35 if (data.
empty())
return;
38 if (buffer_.empty()) {
39 size_t processed_count = 0;
40 while (processed_count < data.
size()) {
42 auto search_start = data.
begin() +
static_cast<std::ptrdiff_t
>(processed_count);
43 auto it_start = std::search(search_start, data.
end(), start_pattern_.begin(), start_pattern_.end());
45 if (it_start == data.
end()) {
48 size_t remaining = data.
size() - processed_count;
49 size_t keep_len = (start_pattern_.size() > 1) ? (start_pattern_.size() - 1) : 0;
50 if (remaining > keep_len) {
51 processed_count = data.
size() - keep_len;
57 size_t start_idx =
static_cast<size_t>(std::distance(data.
begin(), it_start));
58 size_t search_end_start_idx = start_idx + start_pattern_.size();
60 if (end_pattern_.empty()) {
62 size_t packet_len = start_pattern_.size();
64 on_message_(data.
subspan(start_idx, packet_len));
66 processed_count = start_idx + packet_len;
71 auto search_end_start = data.
begin() +
static_cast<std::ptrdiff_t
>(search_end_start_idx);
72 auto it_end = std::search(search_end_start, data.
end(), end_pattern_.begin(), end_pattern_.end());
74 if (it_end == data.
end()) {
77 processed_count = start_idx;
84 size_t packet_len =
static_cast<size_t>(std::distance(data.
begin(), it_end)) + end_pattern_.size() - start_idx;
86 if (packet_len <= max_length_) {
88 on_message_(data.
subspan(start_idx, packet_len));
93 processed_count = start_idx + packet_len;
96 if (processed_count < data.
size()) {
97 buffer_.insert(buffer_.end(), data.
begin() +
static_cast<std::ptrdiff_t
>(processed_count), data.
end());
100 if (state_ == State::Sync && !buffer_.empty()) {
101 if (buffer_.size() >= start_pattern_.size()) {
102 if (std::equal(start_pattern_.begin(), start_pattern_.end(), buffer_.begin())) {
103 state_ = State::Collect;
104 scanned_idx_ = start_pattern_.size();
112 buffer_.insert(buffer_.end(), data.
begin(), data.
end());
115 if (state_ == State::Sync) {
116 if (start_pattern_.empty()) {
117 state_ = State::Collect;
121 auto it = std::search(buffer_.begin(), buffer_.end(), start_pattern_.begin(), start_pattern_.end());
122 if (it != buffer_.end()) {
125 if (it != buffer_.begin()) {
126 buffer_.erase(buffer_.begin(), it);
128 state_ = State::Collect;
130 scanned_idx_ = start_pattern_.size();
135 if (start_pattern_.size() > 1) {
136 size_t keep_len = start_pattern_.size() - 1;
137 if (buffer_.size() > keep_len) {
138 buffer_.erase(buffer_.begin(), buffer_.end() -
static_cast<std::ptrdiff_t
>(keep_len));
145 }
else if (state_ == State::Collect) {
146 if (end_pattern_.empty()) {
149 size_t packet_len = start_pattern_.size();
153 if (buffer_.empty())
return;
155 buffer_.erase(buffer_.begin(), buffer_.begin() +
static_cast<std::ptrdiff_t
>(packet_len));
156 state_ = State::Sync;
162 size_t search_offset = std::max(start_pattern_.size(), scanned_idx_);
165 if (search_offset > start_pattern_.size()) {
166 size_t overlap = (end_pattern_.size() > 1) ? (end_pattern_.size() - 1) : 0;
167 if (search_offset >= overlap) {
168 search_offset -= overlap;
175 if (search_offset < start_pattern_.size()) {
176 search_offset = start_pattern_.size();
179 if (buffer_.size() < search_offset) {
184 auto search_start = buffer_.begin() +
static_cast<std::ptrdiff_t
>(search_offset);
185 auto it = std::search(search_start, buffer_.end(), end_pattern_.begin(), end_pattern_.end());
187 if (it != buffer_.end()) {
189 size_t packet_len =
static_cast<size_t>(std::distance(buffer_.begin(), it)) + end_pattern_.size();
191 if (packet_len <= max_length_) {
195 if (buffer_.empty())
return;
197 buffer_.erase(buffer_.begin(), buffer_.begin() +
static_cast<std::ptrdiff_t
>(packet_len));
198 state_ = State::Sync;
202 buffer_.erase(buffer_.begin(), buffer_.begin() +
static_cast<std::ptrdiff_t
>(packet_len));
203 state_ = State::Sync;
208 scanned_idx_ = buffer_.size();
209 if (buffer_.size() > max_length_) {
212 state_ = State::Sync;
225 state_ = State::Sync;
std::function< void(memory::ConstByteSpan)> MessageCallback
Register a callback to be invoked when a complete message is extracted.
void set_on_message(MessageCallback cb) override
void push_bytes(memory::ConstByteSpan data) override
Push raw bytes into the framer's internal buffer.
PacketFramer(const std::vector< uint8_t > &start_pattern, const std::vector< uint8_t > &end_pattern, size_t max_length)
Construct a new Packet Framer.
void reset() override
Reset internal state/buffer.
A C++17 compatible span-like class for safe array access.
constexpr size_type size() const noexcept
constexpr iterator begin() const noexcept
constexpr iterator end() const noexcept
constexpr SafeSpan< T > subspan(size_type offset, size_type count=SIZE_MAX) const
constexpr bool empty() const noexcept