COROIO: NNet::TZeroCopyLineSplitter Class Reference
COROIO
 
Loading...
Searching...
No Matches
NNet::TZeroCopyLineSplitter Class Reference

Splits incoming data into lines using a fixed-size circular buffer, enabling zero-copy writes via Acquire() and Commit(). More...

#include <sockutils.hpp>

Public Member Functions

 TZeroCopyLineSplitter (int maxLen)
 Constructs a zero-copy line splitter with a fixed ring buffer capacity.
 
TLine Pop ()
 Extracts and removes the next complete line from the buffer, if available.
 
std::span< char > Acquire (size_t size)
 Reserves space in the circular buffer for writing data directly (e.g., from a socket read) without extra copying.
 
void Commit (size_t size)
 Finalizes the amount of data written into the span returned by Acquire().
 
void Push (const char *p, size_t len)
 (Optional) Copies data from an external buffer into the circular buffer.
 

Detailed Description

Splits incoming data into lines using a fixed-size circular buffer, enabling zero-copy writes via Acquire() and Commit().

This class maintains a ring buffer of maximum length (maxLen) where new data can be placed without extra copying. To add data, a typical workflow would be:

  1. Call Acquire() to get a std::span<char> in the internal buffer.
  2. Write directly into that span (e.g., using your socket's read or ReadSome).
  3. Call Commit() with the number of bytes actually written.

Lines can then be extracted using Pop(), which returns a TLine holding up to two string-view segments if the line crosses the buffer boundary.

Zero-Copy Example (Reading from a Socket)

// Example function that reads lines from a socket into TZeroCopyLineSplitter
void ReadLinesFromSocket(TSocket& socket) {
TZeroCopyLineSplitter splitter(1024); // ring buffer up to 1024 bytes
while (true) {
// Acquire a chunk of the buffer (say 256 bytes)
auto span = splitter.Acquire(256);
if (span.empty()) {
// Not enough space left - handle as needed (e.g., flush or error)
}
// Read directly into the splitter's internal buffer
ssize_t bytesRead = socket.ReadSome(span.data(), span.size());
if (bytesRead <= 0) {
// 0 => socket closed, negative => error
break;
}
// Commit the data we actually wrote
splitter.Commit(bytesRead);
// Now try popping lines
while (true) {
TLine line = splitter.Pop();
if (line.Part1.empty() && line.Part2.empty()) {
// No complete line available at the moment
break;
}
// Process the line (Part1 + Part2)...
}
}
}
auto ReadSome(void *buf, size_t size)
Asynchronously reads data from the socket into the provided buffer.
Definition socket.hpp:138
High-level asynchronous socket for network communication.
Definition socket.hpp:364
TZeroCopyLineSplitter(int maxLen)
Constructs a zero-copy line splitter with a fixed ring buffer capacity.

Constructor & Destructor Documentation

◆ TZeroCopyLineSplitter()

NNet::TZeroCopyLineSplitter::TZeroCopyLineSplitter ( int maxLen)

Constructs a zero-copy line splitter with a fixed ring buffer capacity.

Parameters
maxLenThe maximum number of bytes the buffer can hold.

Member Function Documentation

◆ Acquire()

std::span< char > NNet::TZeroCopyLineSplitter::Acquire ( size_t size)

Reserves space in the circular buffer for writing data directly (e.g., from a socket read) without extra copying.

This method returns a contiguous block of available space as a std::span<char>. If the ring buffer wraps around, you might only get the block up to the end; you can call Acquire() again for any remaining space, depending on your logic.

Parameters
sizeThe desired number of bytes to acquire.
Returns
A std::span<char> pointing to the ring buffer region where data can be written. Its size might be less than requested if there's less contiguous space available.
Note
You must call Commit() after writing into this span, specifying how many bytes were actually written. Otherwise, the new data won't be recognized by the splitter.

◆ Commit()

void NNet::TZeroCopyLineSplitter::Commit ( size_t size)

Finalizes the amount of data written into the span returned by Acquire().

Parameters
sizeThe number of bytes that were actually written into the acquired buffer.

After calling Commit(), this new data is considered part of the buffer and can be used to form lines via Pop().

◆ Pop()

TLine NNet::TZeroCopyLineSplitter::Pop ( )

Extracts and removes the next complete line from the buffer, if available.

A line is typically delimited by a newline character (implementation-specific). If the line crosses the circular boundary, the returned TLine will contain two segments (Part1 and Part2).

Returns
A TLine object with up to two std::string_view segments referencing the internal ring buffer. If there is no complete line available, behavior is implementation-defined (it may return an empty TLine or throw an exception).
Warning
The returned string views become invalid once additional data is acquired, committed, or popped. Keep this in mind if you need to store the line contents for later use.

◆ Push()

void NNet::TZeroCopyLineSplitter::Push ( const char * p,
size_t len )

(Optional) Copies data from an external buffer into the circular buffer.

While the main purpose of this class is zero-copy insertion via Acquire() and Commit(), this method offers a fallback for situations where you already have data in a separate buffer and wish to write it into the splitter in one call.

Parameters
pPointer to the data to copy from.
lenNumber of bytes to copy.

The documentation for this class was generated from the following file: