update buffer implementation
This commit is contained in:
parent
167408b11d
commit
a4e515660b
|
@ -24,45 +24,78 @@
|
||||||
|
|
||||||
/*
|
/*
|
||||||
SBuffer can be used to read or write a buffer, but cannot be used for both
|
SBuffer can be used to read or write a buffer, but cannot be used for both
|
||||||
read & write at a same time.
|
read & write at a same time. Below is an example:
|
||||||
Read example:
|
|
||||||
SBuffer rbuf;
|
|
||||||
if (tbufBeginOperation(&rbuf) != 0) {
|
|
||||||
// handling errors
|
|
||||||
}
|
|
||||||
tbufInitRead(&rbuf, data, 1024);
|
|
||||||
int32_t a = tbufReadInt32(&rbuf);
|
|
||||||
// other read functions
|
|
||||||
|
|
||||||
Write example:
|
int main(int argc, char** argv) {
|
||||||
|
//--------------------- write ------------------------
|
||||||
SBuffer wbuf;
|
SBuffer wbuf;
|
||||||
if (tbufBeginOperation(&wbuf) != 0) {
|
int32_t code = tbufBeginWrite(&wbuf);
|
||||||
// handling errors
|
if (code != 0) {
|
||||||
|
// handle errors
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
tbufInitWrite(&wbuf, 1024);
|
|
||||||
tbufWriteInt32(&wbuf, 10);
|
// reserve 1024 bytes for the buffer to improve performance
|
||||||
// other write functions
|
tbufEnsureCapacity(&wbuf, 1024);
|
||||||
size_t size = tbufGetSize(&wbuf);
|
|
||||||
char* data = tbufGetBuffer(&wbuf, true);
|
// write 5 integers to the buffer
|
||||||
tbufUninitWrite(&wbuf);
|
for (int i = 0; i < 5; i++) {
|
||||||
|
tbufWriteInt32(&wbuf, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
// write a string to the buffer
|
||||||
|
tbufWriteString(&wbuf, "this is a string.\n");
|
||||||
|
|
||||||
|
// acquire the result and close the write buffer
|
||||||
|
size_t size = tbufTell(&wbuf);
|
||||||
|
char* data = tbufGetData(&wbuf, true);
|
||||||
|
tbufClose(&wbuf, true);
|
||||||
|
|
||||||
|
|
||||||
|
//------------------------ read -----------------------
|
||||||
|
SBuffer rbuf;
|
||||||
|
code = tbufBeginRead(&rbuf, data, size);
|
||||||
|
if (code != 0) {
|
||||||
|
printf("you will see this message after print out 5 integers and a string.\n");
|
||||||
|
tbufClose(&rbuf, false);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// read & print out 5 integers
|
||||||
|
for (int i = 0; i < 5; i++) {
|
||||||
|
printf("%d\n", tbufReadInt32(&rbuf));
|
||||||
|
}
|
||||||
|
|
||||||
|
// read & print out a string
|
||||||
|
printf(tbufReadString(&rbuf, NULL));
|
||||||
|
|
||||||
|
// try read another integer, this result in an error as there no this integer
|
||||||
|
tbufReadInt32(&rbuf);
|
||||||
|
|
||||||
|
printf("you should not see this message.\n");
|
||||||
|
tbufClose(&rbuf, false);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct {
|
||||||
jmp_buf jb;
|
jmp_buf jb;
|
||||||
char* buf;
|
char* data;
|
||||||
size_t pos;
|
size_t pos;
|
||||||
size_t size;
|
size_t size;
|
||||||
} SBuffer;
|
} SBuffer;
|
||||||
|
|
||||||
|
|
||||||
// common functions can be used in both read & write
|
// common functions can be used in both read & write
|
||||||
#define tbufBeginOperation(buf) setjmp((buf)->jb)
|
#define tbufThrowError(buf, code) longjmp((buf)->jb, (code))
|
||||||
size_t tbufTell(SBuffer* buf);
|
size_t tbufTell(SBuffer* buf);
|
||||||
size_t tbufSeekTo(SBuffer* buf, size_t pos);
|
size_t tbufSeekTo(SBuffer* buf, size_t pos);
|
||||||
size_t tbufSkip(SBuffer* buf, size_t size);
|
size_t tbufSkip(SBuffer* buf, size_t size);
|
||||||
|
void tbufClose(SBuffer* buf, bool keepData);
|
||||||
|
|
||||||
|
|
||||||
// basic read functions
|
// basic read functions
|
||||||
void tbufInitRead(SBuffer* buf, void* data, size_t size);
|
#define tbufBeginRead(buf, data, len) (((buf)->data = (char*)data), ((buf)->pos = 0), ((buf)->size = ((data) == NULL) ? 0 : (len)), setjmp((buf)->jb))
|
||||||
char* tbufRead(SBuffer* buf, size_t size);
|
char* tbufRead(SBuffer* buf, size_t size);
|
||||||
void tbufReadToBuffer(SBuffer* buf, void* dst, size_t size);
|
void tbufReadToBuffer(SBuffer* buf, void* dst, size_t size);
|
||||||
const char* tbufReadString(SBuffer* buf, size_t* len);
|
const char* tbufReadString(SBuffer* buf, size_t* len);
|
||||||
|
@ -70,10 +103,9 @@ size_t tbufReadToString(SBuffer* buf, char* dst, size_t size);
|
||||||
|
|
||||||
|
|
||||||
// basic write functions
|
// basic write functions
|
||||||
void tbufInitWrite(SBuffer* buf, size_t size);
|
#define tbufBeginWrite(buf) ((buf)->data = NULL, ((buf)->pos = 0), ((buf)->size = 0), setjmp((buf)->jb))
|
||||||
void tbufEnsureCapacity(SBuffer* buf, size_t size);
|
void tbufEnsureCapacity(SBuffer* buf, size_t size);
|
||||||
char* tbufGetResult(SBuffer* buf, bool takeOver);
|
char* tbufGetData(SBuffer* buf, bool takeOver);
|
||||||
void tbufUninitWrite(SBuffer* buf);
|
|
||||||
void tbufWrite(SBuffer* buf, const void* data, size_t size);
|
void tbufWrite(SBuffer* buf, const void* data, size_t size);
|
||||||
void tbufWriteAt(SBuffer* buf, size_t pos, const void* data, size_t size);
|
void tbufWriteAt(SBuffer* buf, size_t pos, const void* data, size_t size);
|
||||||
void tbufWriteStringLen(SBuffer* buf, const char* str, size_t len);
|
void tbufWriteStringLen(SBuffer* buf, const char* str, size_t len);
|
||||||
|
@ -81,24 +113,24 @@ void tbufWriteString(SBuffer* buf, const char* str);
|
||||||
|
|
||||||
|
|
||||||
// read & write function for primitive types
|
// read & write function for primitive types
|
||||||
#ifndef TBUFFER_DEFINE_OPERATION
|
#ifndef TBUFFER_DEFINE_FUNCTION
|
||||||
#define TBUFFER_DEFINE_OPERATION(type, name) \
|
#define TBUFFER_DEFINE_FUNCTION(type, name) \
|
||||||
type tbufRead##name(SBuffer* buf); \
|
type tbufRead##name(SBuffer* buf); \
|
||||||
void tbufWrite##name(SBuffer* buf, type data); \
|
void tbufWrite##name(SBuffer* buf, type data); \
|
||||||
void tbufWrite##name##At(SBuffer* buf, size_t pos, type data);
|
void tbufWrite##name##At(SBuffer* buf, size_t pos, type data);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
TBUFFER_DEFINE_OPERATION( bool, Bool )
|
TBUFFER_DEFINE_FUNCTION( bool, Bool )
|
||||||
TBUFFER_DEFINE_OPERATION( char, Char )
|
TBUFFER_DEFINE_FUNCTION( char, Char )
|
||||||
TBUFFER_DEFINE_OPERATION( int8_t, Int8 )
|
TBUFFER_DEFINE_FUNCTION( int8_t, Int8 )
|
||||||
TBUFFER_DEFINE_OPERATION( uint8_t, Unt8 )
|
TBUFFER_DEFINE_FUNCTION( uint8_t, Unt8 )
|
||||||
TBUFFER_DEFINE_OPERATION( int16_t, Int16 )
|
TBUFFER_DEFINE_FUNCTION( int16_t, Int16 )
|
||||||
TBUFFER_DEFINE_OPERATION( uint16_t, Uint16 )
|
TBUFFER_DEFINE_FUNCTION( uint16_t, Uint16 )
|
||||||
TBUFFER_DEFINE_OPERATION( int32_t, Int32 )
|
TBUFFER_DEFINE_FUNCTION( int32_t, Int32 )
|
||||||
TBUFFER_DEFINE_OPERATION( uint32_t, Uint32 )
|
TBUFFER_DEFINE_FUNCTION( uint32_t, Uint32 )
|
||||||
TBUFFER_DEFINE_OPERATION( int64_t, Int64 )
|
TBUFFER_DEFINE_FUNCTION( int64_t, Int64 )
|
||||||
TBUFFER_DEFINE_OPERATION( uint64_t, Uint64 )
|
TBUFFER_DEFINE_FUNCTION( uint64_t, Uint64 )
|
||||||
TBUFFER_DEFINE_OPERATION( float, Float )
|
TBUFFER_DEFINE_FUNCTION( float, Float )
|
||||||
TBUFFER_DEFINE_OPERATION( double, Double )
|
TBUFFER_DEFINE_FUNCTION( double, Double )
|
||||||
|
|
||||||
#endif
|
#endif
|
|
@ -13,7 +13,11 @@
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define TBUFFER_DEFINE_OPERATION(type, name) \
|
#include <stdlib.h>
|
||||||
|
#include <memory.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#define TBUFFER_DEFINE_FUNCTION(type, name) \
|
||||||
type tbufRead##name(SBuffer* buf) { \
|
type tbufRead##name(SBuffer* buf) { \
|
||||||
type ret; \
|
type ret; \
|
||||||
tbufReadToBuffer(buf, &ret, sizeof(type)); \
|
tbufReadToBuffer(buf, &ret, sizeof(type)); \
|
||||||
|
@ -38,7 +42,8 @@ size_t tbufTell(SBuffer* buf) {
|
||||||
|
|
||||||
size_t tbufSeekTo(SBuffer* buf, size_t pos) {
|
size_t tbufSeekTo(SBuffer* buf, size_t pos) {
|
||||||
if (pos > buf->size) {
|
if (pos > buf->size) {
|
||||||
longjmp(buf->jb, 1);
|
// TODO: update error code, other tbufThrowError need to be changed too
|
||||||
|
tbufThrowError(buf, 1);
|
||||||
}
|
}
|
||||||
size_t old = buf->pos;
|
size_t old = buf->pos;
|
||||||
buf->pos = pos;
|
buf->pos = pos;
|
||||||
|
@ -49,18 +54,20 @@ size_t tbufSkip(SBuffer* buf, size_t size) {
|
||||||
return tbufSeekTo(buf, buf->pos + size);
|
return tbufSeekTo(buf, buf->pos + size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void tbufClose(SBuffer* buf, bool keepData) {
|
||||||
|
if (!keepData) {
|
||||||
|
free(buf->data);
|
||||||
|
}
|
||||||
|
buf->data = NULL;
|
||||||
|
buf->pos = 0;
|
||||||
|
buf->size = 0;
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// read functions
|
// read functions
|
||||||
|
|
||||||
void tbufInitRead(SBuffer* buf, void* data, size_t size) {
|
|
||||||
buf->buf = (char*)data;
|
|
||||||
buf->pos = 0;
|
|
||||||
// empty buffer is not an error, but read an empty buffer is
|
|
||||||
buf->size = (data == NULL) ? 0 : size;
|
|
||||||
}
|
|
||||||
|
|
||||||
char* tbufRead(SBuffer* buf, size_t size) {
|
char* tbufRead(SBuffer* buf, size_t size) {
|
||||||
char* ret = buf->buf + buf->pos;
|
char* ret = buf->data + buf->pos;
|
||||||
tbufSkip(buf, size);
|
tbufSkip(buf, size);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -72,8 +79,8 @@ void tbufReadToBuffer(SBuffer* buf, void* dst, size_t size) {
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* tbufReadString(SBuffer* buf, size_t* len) {
|
const char* tbufReadString(SBuffer* buf, size_t* len) {
|
||||||
uint16_t l = tbufReadUint16();
|
uint16_t l = tbufReadUint16(buf);
|
||||||
char* ret = buf->buf + buf->pos;
|
char* ret = buf->data + buf->pos;
|
||||||
tbufSkip(buf, l + 1);
|
tbufSkip(buf, l + 1);
|
||||||
ret[l] = 0; // ensure the string end with '\0'
|
ret[l] = 0; // ensure the string end with '\0'
|
||||||
if (len != NULL) {
|
if (len != NULL) {
|
||||||
|
@ -83,9 +90,12 @@ const char* tbufReadString(SBuffer* buf, size_t* len) {
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t tbufReadToString(SBuffer* buf, char* dst, size_t size) {
|
size_t tbufReadToString(SBuffer* buf, char* dst, size_t size) {
|
||||||
|
assert(dst != NULL);
|
||||||
size_t len;
|
size_t len;
|
||||||
const char* str = tbufReadString(buf, &len);
|
const char* str = tbufReadString(buf, &len);
|
||||||
if (len >= size) len = size - 1;
|
if (len >= size) {
|
||||||
|
len = size - 1;
|
||||||
|
}
|
||||||
memcpy(dst, str, len);
|
memcpy(dst, str, len);
|
||||||
dst[len] = 0;
|
dst[len] = 0;
|
||||||
return len;
|
return len;
|
||||||
|
@ -98,57 +108,53 @@ size_t tbufReadToString(SBuffer* buf, char* dst, size_t size) {
|
||||||
void tbufEnsureCapacity(SBuffer* buf, size_t size) {
|
void tbufEnsureCapacity(SBuffer* buf, size_t size) {
|
||||||
size += buf->pos;
|
size += buf->pos;
|
||||||
if (size > buf->size) {
|
if (size > buf->size) {
|
||||||
char* nbuf = NULL;
|
|
||||||
size_t nsize = size + buf->size;
|
size_t nsize = size + buf->size;
|
||||||
nbuf = realloc(buf->buf, nsize);
|
char* data = realloc(buf->data, nsize);
|
||||||
if (nbuf == NULL) {
|
if (data == NULL) {
|
||||||
longjmp(buf->jb, 2);
|
tbufThrowError(buf, 2);
|
||||||
}
|
}
|
||||||
buf->buf = nbuf;
|
buf->data = data;
|
||||||
buf->size = nsize;
|
buf->size = nsize;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void tbufInitWrite(SBuffer* buf, size_t size) {
|
char* tbufGetData(SBuffer* buf, bool takeOver) {
|
||||||
buf->buf = NULL;
|
char* ret = buf->data;
|
||||||
buf->pos = 0;
|
|
||||||
buf->size = 0;
|
|
||||||
tbufEnsureCapacity(buf, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
char* tbufGetResult(SBuffer* buf, bool takeOver) {
|
|
||||||
char* ret = buf->buf;
|
|
||||||
if (takeOver) {
|
if (takeOver) {
|
||||||
buf->pos = 0;
|
buf->pos = 0;
|
||||||
buf->size = 0;
|
buf->size = 0;
|
||||||
buf->buf = NULL;
|
buf->data = NULL;
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void tbufUninitWrite(SBuffer* buf) {
|
void tbufEndWrite(SBuffer* buf) {
|
||||||
free(buf->buf);
|
free(buf->data);
|
||||||
|
buf->data = NULL;
|
||||||
|
buf->pos = 0;
|
||||||
|
buf->size = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void tbufWrite(SBuffer* buf, const void* data, size_t size) {
|
void tbufWrite(SBuffer* buf, const void* data, size_t size) {
|
||||||
tbufEnsureCapacity(size);
|
assert(data != NULL);
|
||||||
memcpy(buf->buf + buf->pos, data, size);
|
tbufEnsureCapacity(buf, size);
|
||||||
|
memcpy(buf->data + buf->pos, data, size);
|
||||||
buf->pos += size;
|
buf->pos += size;
|
||||||
}
|
}
|
||||||
|
|
||||||
void tbufWriteAt(SBuffer* buf, size_t pos, const void* data, size_t size) {
|
void tbufWriteAt(SBuffer* buf, size_t pos, const void* data, size_t size) {
|
||||||
|
assert(data != NULL);
|
||||||
// this function can only be called to fill the gap on previous writes,
|
// this function can only be called to fill the gap on previous writes,
|
||||||
// so 'pos + size <= buf->pos' must be true
|
// so 'pos + size <= buf->pos' must be true
|
||||||
if (pos + size > buf->pos) {
|
assert(pos + size <= buf->pos);
|
||||||
longjmp(buf->jb, 3);
|
memcpy(buf->data + pos, data, size);
|
||||||
}
|
|
||||||
memcpy(buf->buf + pos, data, size);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void tbufWriteStringLen(SBuffer* buf, const char* str, size_t len) {
|
void tbufWriteStringLen(SBuffer* buf, const char* str, size_t len) {
|
||||||
if (len > 0xffff) {
|
// maximum string length is 65535, if longer string is required
|
||||||
longjmp(buf->jb , 4);
|
// this function and the corresponding read function need to be
|
||||||
}
|
// revised.
|
||||||
|
assert(len <= 0xffff);
|
||||||
tbufWriteUint16(buf, (uint16_t)len);
|
tbufWriteUint16(buf, (uint16_t)len);
|
||||||
tbufWrite(buf, str, len + 1);
|
tbufWrite(buf, str, len + 1);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue