Program Listing for File MessageBuffer.h#
↰ Return to documentation for file (src/buffer/MessageBuffer.h)
#pragma once
/* internal */
#include "../result.h"
#include "CircularBuffer.h"
namespace Coral
{
template <std::size_t depth, std::size_t max_messages,
byte_size element_t = std::byte,
std::size_t alignment = sizeof(element_t)>
class MessageBuffer : public CircularBuffer<depth, element_t, alignment>
{
public:
class MessageContext
{
public:
MessageContext(MessageBuffer *_buf) : max(_buf->space()), buf(_buf)
{
/* Lock buffer, reset write count and determine maximum message
* size. */
buf->locked = true;
buf->write_count();
}
~MessageContext()
{
auto len = buf->write_count();
/* Track message if written length is within bounds, otherwise
* reset buffer due to overflow. */
if (len <= max)
{
buf->add_message(len);
}
else
{
buf->clear();
}
buf->locked = false;
}
template <std::endian endianness, std::integral T>
inline std::size_t custom(const element_t *elem, std::size_t length)
{
std::size_t result = 0;
result += buf->template write<endianness>(T());
result += buf->write_n(elem, length);
return result;
}
template <std::endian endianness, ifgen_struct T>
inline std::size_t point(const T *elem)
{
std::size_t result = 0;
result += buf->template write<endianness>(T::id);
result += buf->template write<endianness>(elem);
return result;
}
const std::size_t max;
protected:
MessageBuffer *buf;
};
MessageBuffer()
: CircularBuffer<depth, element_t, alignment>(), message_sizes(),
num_messages(0), data_size(0), locked(false)
{
}
MessageContext context(void)
{
return MessageContext(this);
}
inline std::size_t space(void)
{
return (data_size < depth) ? depth - data_size : 0;
}
inline bool full(std::size_t check = 0)
{
return num_messages >= max_messages or (data_size + check > depth);
}
Result put_message(const element_t *data, std::size_t len)
{
/* Need room for message size element and space in data buffer. */
auto result = len and not locked and not full(len);
if (result)
{
this->write_n(data, len);
add_message(len);
}
return ToResult(result);
}
Result get_message(element_t *data, std::size_t &len)
{
bool result = not locked and not empty();
if (result)
{
len = remove_message();
this->read_n(data, len);
}
return ToResult(result);
}
inline bool empty()
{
return num_messages == 0;
}
inline void clear(void)
{
this->reset();
message_sizes.reset();
/* Could track drops at some point. */
num_messages = 0;
data_size = 0;
}
protected:
CircularBuffer<max_messages, std::size_t> message_sizes;
std::size_t num_messages;
std::size_t data_size;
bool locked;
inline void add_message(std::size_t len)
{
message_sizes.write_single(len);
num_messages++;
data_size += len;
}
inline auto remove_message(void)
{
auto len = message_sizes.read_single();
num_messages--;
data_size -= len;
return len;
}
};
} // namespace Coral