22 #include <string_view>
28 : delimiter_(delimiter), include_delimiter_(include_delimiter), max_length_(max_length) {
29 if (delimiter_.empty()) {
35 if (data.
empty())
return;
42 const size_t chunk_limit = std::max(max_length_,
size_t(4096));
45 while (offset < data.
size()) {
46 size_t len = std::min(data.
size() - offset, chunk_limit);
47 push_bytes_internal(data.
subspan(offset, len));
53 if (data.
empty())
return;
56 if (buffer_.empty()) {
57 size_t processed_count = scan_and_process(data, 0);
60 if (processed_count < data.
size()) {
61 buffer_.insert(buffer_.end(), data.
begin() + processed_count, data.
end());
62 scanned_idx_ = buffer_.size();
65 if (buffer_.size() > max_length_) {
77 buffer_.insert(buffer_.end(), data.
begin(), data.
end());
81 size_t search_start_idx = scanned_idx_;
82 if (search_start_idx >= delimiter_.length()) {
83 search_start_idx -= (delimiter_.length() - 1);
91 if (processed_count > 0) {
92 buffer_.erase(buffer_.begin(), buffer_.begin() +
static_cast<std::ptrdiff_t
>(processed_count));
97 scanned_idx_ = buffer_.size();
101 if (buffer_.size() > max_length_) {
109 if (search_start_offset > data.size()) {
110 search_start_offset = data.size();
115 size_t processed_count = 0;
118 size_t search_cursor = search_start_offset;
122 if (search_cursor > data.size())
break;
125 auto search_begin = data.begin() +
static_cast<std::ptrdiff_t
>(search_cursor);
126 decltype(data.begin()) it;
128 if (delimiter_.size() == 1) {
130 const void* found = std::memchr(search_begin,
static_cast<uint8_t
>(delimiter_[0]),
131 static_cast<size_t>(std::distance(search_begin, data.end())));
133 it =
static_cast<const uint8_t*
>(found);
138 it = std::search(search_begin, data.end(), delimiter_.begin(), delimiter_.end());
141 if (it == data.end()) {
146 size_t match_start_idx =
static_cast<size_t>(std::distance(data.begin(), it));
147 size_t match_end_idx = match_start_idx + delimiter_.length();
150 size_t current_msg_total_len = match_end_idx - processed_count;
153 if (current_msg_total_len > max_length_) {
158 size_t payload_len = include_delimiter_ ? current_msg_total_len : (current_msg_total_len - delimiter_.length());
164 processed_count = match_end_idx;
167 search_cursor = processed_count;
170 return processed_count;
std::function< void(memory::ConstByteSpan)> MessageCallback
Register a callback to be invoked when a complete message is extracted.
void reset() override
Reset internal state/buffer.
void set_on_message(MessageCallback cb) override
void push_bytes(memory::ConstByteSpan data) override
Push raw bytes into the framer's internal buffer.
LineFramer(std::string_view delimiter="\n", bool include_delimiter=false, size_t max_length=65536)
Construct a new Line Framer.
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
SafeSpan< const uint8_t > ConstByteSpan