194 lines
3.6 KiB
C++
194 lines
3.6 KiB
C++
#ifndef CHUNK_BUFFER_H
|
|
#define CHUNK_BUFFER_H
|
|
|
|
#include "../Debug.h"
|
|
|
|
/**
|
|
* linked list of several chunks that are either managed or unmanaged
|
|
*/
|
|
class ChunkBuffer {
|
|
|
|
public:
|
|
|
|
/** data of certain length */
|
|
struct Data {
|
|
const uint8_t* ptr;
|
|
const uint16_t size;
|
|
Data(const uint8_t* ptr, const uint16_t size) : ptr(ptr), size(size) {;}
|
|
};
|
|
|
|
/** one data chunk within the buffer */
|
|
struct Chunk {
|
|
|
|
bool managed;
|
|
uint8_t* base; // do not modify this one!
|
|
|
|
uint8_t* ptr;
|
|
uint16_t len;
|
|
|
|
Chunk* next = nullptr;
|
|
|
|
~Chunk() {
|
|
debugMod("ChunkBuffer::Chunk", "dtor");
|
|
if (managed) {
|
|
free(base);
|
|
base = nullptr;
|
|
}
|
|
}
|
|
|
|
/** allocate a new managed chunk */
|
|
static Chunk* alloc(const uint16_t size) {
|
|
debugMod1("ChunkBuffer::Chunk", "alloc(%d)", size);
|
|
Chunk* chunk = new Chunk();
|
|
chunk->base = (uint8_t*)malloc(size);
|
|
chunk->ptr = chunk->base;
|
|
chunk->len = size;
|
|
chunk->managed = true;
|
|
return chunk;
|
|
}
|
|
|
|
/** allocate a new wrapped chunk */
|
|
static Chunk* wrap(uint8_t* ptr, const uint16_t size) {
|
|
debugMod1("ChunkBuffer::Chunk", "alloc(%d)", size);
|
|
Chunk* chunk = new Chunk();
|
|
chunk->base = ptr;
|
|
chunk->ptr = chunk->base;
|
|
chunk->len = size;
|
|
chunk->managed = false;
|
|
return chunk;
|
|
}
|
|
|
|
/** consume max(!) size bytes from this chunk */
|
|
Data consume(const uint16_t size) {
|
|
debugMod1("ChunkBuffer::Chunk", "consume(%d)", size);
|
|
const uint16_t useBytes = min(size, this->len);
|
|
Data res(ptr, useBytes);
|
|
ptr += useBytes; // adjust pointer for next consume() call
|
|
len -= useBytes; // adjuste len for next consume() call;
|
|
return res;
|
|
}
|
|
|
|
/** consume one byte, if available */
|
|
int consumeByte() {
|
|
if (len) {
|
|
uint8_t res = *ptr;
|
|
ptr += 1;
|
|
len -= 1;
|
|
return res;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
bool empty() const {
|
|
return len == 0;
|
|
}
|
|
|
|
private:
|
|
Chunk() {;}
|
|
|
|
};
|
|
|
|
static uint16_t min(const uint16_t a, const uint16_t b) {
|
|
return (a<b) ? (a) : (b);
|
|
}
|
|
|
|
private:
|
|
|
|
Chunk* root;
|
|
|
|
public:
|
|
|
|
ChunkBuffer() : root(nullptr) {
|
|
debugMod("ChunkBuffer", "ctor()");
|
|
}
|
|
|
|
/** get a block of max(!) size bytes from the buffer. might return less */
|
|
Data get(const uint16_t size) {
|
|
|
|
cleanup();
|
|
|
|
// something available?
|
|
if (!root) {
|
|
return Data(0,0);
|
|
} else {
|
|
return root->consume(size);
|
|
}
|
|
|
|
}
|
|
|
|
int getByte() {
|
|
|
|
cleanup();
|
|
|
|
if (root && !root->empty()) {
|
|
return root->consumeByte();
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
/** append the given chunk to the buffer */
|
|
void append(Chunk* c) {
|
|
|
|
debugMod("ChunkBuffer", "append()");
|
|
|
|
if (!root) {
|
|
|
|
// new chunk is the root
|
|
root = c;
|
|
|
|
} else {
|
|
|
|
// append new chunk at the end
|
|
Chunk* x = root;
|
|
while (x->next) {x = x->next;}
|
|
x->next = c;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/** allocate a new managed chunk of the given size */
|
|
Chunk* alloc(const uint16_t size) {
|
|
debugMod1("ChunkBuffer", "alloc(%d)", size);
|
|
return Chunk::alloc(size);
|
|
}
|
|
|
|
/** get a new unmanaged wrapper chunk for the given data */
|
|
Chunk* wrap(const uint8_t* data, const uint16_t size) {
|
|
debugMod1("ChunkBuffer", "wrap(%d)", size);
|
|
return Chunk::wrap((uint8_t*) data, size);
|
|
}
|
|
|
|
/** number of available bytes */
|
|
uint32_t available() const {
|
|
uint32_t s = 0;
|
|
Chunk* c = root;
|
|
while(c) {
|
|
s += c->len;
|
|
c = c->next;
|
|
}
|
|
return s;
|
|
}
|
|
|
|
/** nothing available? */
|
|
bool empty() const {
|
|
return (!root || root->len == 0);
|
|
}
|
|
|
|
private:
|
|
|
|
void cleanup() {
|
|
|
|
// current chunk empty? -> cleanup and proceed with next chunk
|
|
if (root && root->empty()) {
|
|
Chunk* old = root;
|
|
root = old->next; // next chunk is the chunk (if any) after the current (empty) one
|
|
delete old; // delete the empty chunk and free the data
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
#endif // CHUNK_BUFFER_H
|