Files CCore/inc/NanoPacket.h CCore/src/NanoPacket.cpp
NanoPacket is a simple packet technology. It has three components: NanoPacket, NanoPacketList and NanoPacketPool.
NanoPacket consists of a header, followed by a body. The body is a range of some POD values. The initial part of the body carries data.
The NanoPacket class is a wrapper over a pointer to the header. This class is copyable, so you must use it with the same caution as a raw pointer. The pointer may be null.
template <class POD>
class NanoPacket
{
using NanoPacketFunction = Function<void (NanoPacket<POD> packet)> ;
private:
Header *ptr;
public:
// constructors
static constexpr ulen AllocLen(ulen max_data_len);
NanoPacket() noexcept : ptr(0) {}
NanoPacket(NothingType) : ptr(0) {}
NanoPacket(Place<void> place,ulen max_data_len,NanoPacketFunction free_function);
// methods
bool operator + () const { return ptr!=0; }
bool operator ! () const { return ptr==0; }
void free();
// data
POD * getData() const;
ulen getDataLen() const;
ulen getMaxDataLen() const;
PtrLen<POD> getRange() const;
PtrLen<POD> getMaxRange() const;
PtrLen<POD> setDataLen(ulen len);
};
AllocLen() calculates the required memory size to store a NanoPacket with the given capacity. There is no overflow check in this function, so the argument must not be "huge".
The default constructor and the Nothing-constructor create a null packet.
The third constructor creates a non-null packet. You must provide as arguments the place, where packet will be constructed, the capacity max_data_len and the free_function. The place must be aligned and the memory size must be at least AllocLen(max_data_len). The free_function is used to free the packet.
operator + and operator ! checks if the packet is a null packet.
All remaining methods cannot be used with a null packet.
free() frees the packet and sets the packet to the null state.
getData() returns the pointer to the data area.
getDataLen() returns the current data length. Initial data length is zero.
getMaxDataLen() returns the capacity of the packet.
getData() returns the data range.
getMaxData() returns the reserved range.
setDataLen() sets the data length. The len must not exceed getMaxDataLen(). The new data range is returned.
NanoPacket can be put into a NanoPacketList. A particular packet can be inserted into only one list.
template <class POD>
class NanoPacketList : NoCopy
{
....
public:
NanoPacketList() noexcept;
~NanoPacketList();
// std move
NanoPacketList(NanoPacketList<POD> &&obj) noexcept;
NanoPacketList<POD> & operator = (NanoPacketList<POD> &&obj) noexcept;
// methods
bool operator + () const;
bool operator ! () const;
void put(NanoPacket<POD> packet);
void put_first(NanoPacket<POD> packet);
NanoPacket<POD> get();
void freeAll();
void cleanAll();
// swap/move object
void objSwap(NanoPacketList<POD> &obj);
explicit NanoPacketList(ToMoveCtor<NanoPacketList<POD> > obj);
};
Constructor creates an empty list.
Destructor calls abort, if the list is not empty.
NanoPacketList is std movable. The original object is nullified during the move.
operator + and operator ! can be used to check if the list is empty.
put() puts the packet into the list tail.
put_first() puts the packet into the list head.
get() gets the first packet from the list. If the list is empty, null packet is returned.
freeAll() frees all packets from the list. List becomes empty.
cleanAll() makes the list empty, but does not free packets. Use this method with caution.
NanoPacketList is swappable and movable.
NanoPacketPool is a pool of NanoPackets.
template <class POD>
class NanoPacketPool : NoCopy
{
....
private:
virtual void post_free() {}
public:
NanoPacketPool(void *mem,ulen max_data_len,ulen count); // aligned mem,
// NanoPacket<POD>::AllocLen(max_data_len)*count length
~NanoPacketPool();
NanoPacket<POD> try_get();
};
NanoPacketPool constructor creates a packet pool in the provided memory region, max_data_len is the capacity of each packet, count is the number of packets. Memory must be aligned and of size at least NanoPacket<POD>::AllocLen(max_data_len)*count. The pool uses the memory, but is not responsible for the life-time control of it. You may use a static memory region, or allocate it dynamically. In the last case, you must do it prior the pool construction and release it after the pool destruction.
Destructor destroys the pool. All packets must be freed, otherwise abort is called.
try_get() returns a packet from the pool or the null packet. When packet is freed, the virtual method post_free() is called. You can overload this method in a derived class to implement a top level logic of packet control.
NanoPacketPool uses FastMutex to protect operations. So it can be used safely by multiple threads and even in the interrupt context on XCore targets. post_free() is called after the lock is released. On XCore it may be called in any execution context.