NetBuffer - buffer specialized for socket read / write This class is for fast and small footprint buffering made specially for network I/O. It is similar to so-called circular buffers, but is not circular.

#ifndef _IO_BUFFER_H
#define _IO_BUFFER_H

#include &lt;cstdint&gt;
#include &lt;cstring&gt;
#include &lt;cstdio&gt;

namespace net{

template&lt;size_t CAPACITY&gt;
class IOBuffer{
public:
    using size_type = uint16_t;

private:
    size_type   head_   = 0;
    size_type   tail_   = 0;
    char        buffer_[CAPACITY];

public:
    void clear(){
        head_ = 0;
        tail_ = 0;
    }

    constexpr
    static size_t max_size(){
        return CAPACITY;
    }

    // ==================================

    const char *data() const{
        return &amp; buffer_[head_];
    }

    char *dataTail(){
        return &amp; buffer_[tail_];
    }

    size_t size() const{
        return tail_ - head_;
    }

    size_t capacity() const{
        return CAPACITY - tail_;
    }

    // ==================================

    bool push(const char *p){
        return p ? push(strlen(p), p) : false;
    }

    bool push(size_t const len, const void *ptr = nullptr){
        if (len == 0)
            return false;

        if (capacity() &lt; len)
            return false;

        if (ptr)
            memmove(&amp;buffer_[tail_], ptr, len);

        tail_ = (size_type) (tail_ + len);

        return true;
    }

    bool pop(size_t const len){
        if (len == 0)
            return false;

        auto const available = size();

        if (available &lt; len)
            return false;

        if (available == len){
            clear();
            return true;
        }

        head_ = (size_type) (head_ + len);

        return true;
    }

    // ==================================

    void print() const{
        printf("h: %3u | t: %3u | ad: %3zu | ac: %3zu | %.*s\n",
                head_, tail_,
                size(), capacity(),
                (int) size(), buffer_ );
    }
};

} // namespace

#endif


Usual usage include several socket read() until protocol data is collected, then several write() until response is sent back.

Reads and writes will not be mixed, but for the moment this is responsibility of the caller.

print is debug method, non intended to be called.

int main(){
    using Buffer = net::IOBuffer&lt;10&gt;;

    Buffer b;
    b.print();

    b.push("aaa");
    b.print();

    b.push("bbb");
    b.print();

    b.push("ccc");
    b.print();

    b.push("xxx");
    b.print();

    b.push("d");
    b.print();

    b.push("xxx");
    b.print();

    b.pop(3);
    b.print();

    b.pop(3);
    b.print();

    b.pop(b.size()); // same as b.clear()
    b.print();
}
One of the benefits of circular buffers is that they can be filled up to the entire size of the buffer, with completed fields being extracted from the head of the buffer immediately freeing up space.  This isn't the case for your buffer.  Space in the buffer is never freed until the entire buffer has been read, so if partial fields are consistently read there is a risk the buffer will get to a full state.

dataTail

You've declared your other access methods, including data as const.  Is it a mistake to not declare dataTail as const?  It's not entirely clear to me why a client would need to have a pointer to the bit of the buffer you haven't used.  Or are you expecting the client to actually write to the dataTail, without amending the tail_ afterwards?!?

push

Your extended push seems like it has a bug (or allows a very strange use case):

bool push(size_t const len, const void *ptr = nullptr){
    if (len == 0)
        return false;

    if (capacity() &lt; len)
        return false;

    if (ptr)
        memmove(&amp;buffer_[tail_], ptr, len);

    tail_ = (size_type) (tail_ + len);

    return true;
}


If ptr is null, then no bytes are added to the buffer, however the tail is still incremented as if data had been written.  So effectively, whatever is already in the buffer is added instead.  Having ptr default to null suggests this might be expected behaviour but it seems very odd.

print

print may be a debug method, however its output is confusing.  As you pop from the buffer, you're reducing the number of characters from the buffer that are displayed however you're still printing from the start of the buffer.  This gives the impression that pop is actually removing from the tail, rather than the head.  You should probably be printing from the head instead:

printf("h: %3u | t: %3u | ad: %3zu | ac: %3zu | %.*s\n",
        head_, tail_,
        size(), capacity(),
        (int) size(), data());