added buffer_new_buf() which makes it possible to back a Buffer with an existing pointer without copying

This commit is contained in:
git@daemon.de
2014-02-20 15:36:12 +01:00
parent 51e3cec60d
commit f13f60bfc2
3 changed files with 129 additions and 10 deletions

View File

@@ -74,7 +74,7 @@ typedef struct _pcp_buffer Buffer;
*/ */
Buffer *buffer_new(size_t blocksize, char *name); Buffer *buffer_new(size_t blocksize, char *name);
/** Create a new buffer. /** Create a new string buffer.
Create a new buffer, initially alloc'd to a blocksize of 32 bytes and zero-filled. Create a new buffer, initially alloc'd to a blocksize of 32 bytes and zero-filled.
The buffer will be a string buffer. See buffer_get_str(). The buffer will be a string buffer. See buffer_get_str().
@@ -85,6 +85,75 @@ Buffer *buffer_new(size_t blocksize, char *name);
*/ */
Buffer *buffer_new_str(char *name); Buffer *buffer_new_str(char *name);
/** Create a new buffer from existing data.
Create a new buffer, but don't allocate memory nor copy data.
Instead the provided data pointer will be used as internal
storage directly.
This kind of buffer can be used to put the Buffer API into
use with existing data from other sources. In most cases you'll
use it for reading. However, please be aware, that it can be
used for writing as well and in this case the data pointer
maybe resized (by calling realloc()).
When calling buffer_free() on this Buffer, the memory pointed to
by the given data pointer will not be free'd and remains accessible.
It's the responsibility of the caller to do so.
Example using mmap(2):
@code
#include <stdio.h>
#include <pcp.h>
#include <sys/mman.h>
FILE *RFD;
size_t rs;
Buffer *rb;
byte *chunk;
void *r;
if((RFD = fopen("README", "rb")) == NULL) {
fprintf(stderr, "oops, could not open README!\n");
return 1;
}
fseek(RFD, 0, SEEK_END);
rs = ftell(RFD);
fseek(RFD, 0, SEEK_SET);
void *r = mmap(NULL, rs, PROT_READ, 0, fileno(RFD), 0);
*rb = buffer_new_buf("r", r, rs);
size_t blocksize = 36;
void *chunk = malloc(blocksize);
while(buffer_done(rb) != 1) {
if(buffer_left(rb) < blocksize)
blocksize = buffer_left(rb);
buffer_get_chunk(rb, chunk, blocksize);
_dump("chunk", chunk, blocksize); // or do something else with it
}
buffer_free(rb);
munmap(r, rs);
fclose(RFD);
@endcode
\param[in] name A name for the Buffer. Just used for debugging purposes or in error messages.
\param[in] data The data pointer to use by the buffer.
\param[in] datasize The size of the data.
\return Returns a new Buffer object.
*/
Buffer *buffer_new_buf(char *name, void *data, size_t datasize);
/* initialize buffer vars */ /* initialize buffer vars */
void buffer_init(Buffer *b, size_t blocksize, char *name); void buffer_init(Buffer *b, size_t blocksize, char *name);

View File

@@ -21,13 +21,6 @@
#include "buffer.h" #include "buffer.h"
Buffer *buffer_new(size_t blocksize, char *name) {
Buffer *b = ucmalloc(sizeof(Buffer));
b->buf = ucmalloc(blocksize);
buffer_init(b, blocksize, name);
return b;
}
void buffer_init(Buffer *b, size_t blocksize, char *name) { void buffer_init(Buffer *b, size_t blocksize, char *name) {
b->name = ucmalloc(strlen(name)+1); b->name = ucmalloc(strlen(name)+1);
b->size = blocksize; b->size = blocksize;
@@ -39,22 +32,39 @@ void buffer_init(Buffer *b, size_t blocksize, char *name) {
memcpy(b->name, name, strlen(name)+1); memcpy(b->name, name, strlen(name)+1);
} }
Buffer *buffer_new(size_t blocksize, char *name) {
Buffer *b = ucmalloc(sizeof(Buffer));
b->buf = ucmalloc(blocksize);
buffer_init(b, blocksize, name);
return b;
}
Buffer *buffer_new_str(char *name) { Buffer *buffer_new_str(char *name) {
Buffer *b = buffer_new(256, name); Buffer *b = buffer_new(256, name);
b->isstring = 1; b->isstring = 1;
return b; return b;
} }
Buffer *buffer_new_buf(char *name, void *data, size_t datasize) {
Buffer *b = buffer_new(256, name);
b->allocated = 0;
b->buf = data;
b->size = datasize;
b->end = datasize;
return b;
}
void buffer_free(Buffer *b) { void buffer_free(Buffer *b) {
if(b != NULL) { if(b != NULL) {
if(b->allocated == 1) { if(b->allocated == 1) {
/* free the underlying data pointer only if we allocated it */
if(b->end > 0) { if(b->end > 0) {
buffer_clear(b); buffer_clear(b);
}
free(b->buf); free(b->buf);
} }
free(b); free(b);
} }
}
} }
void buffer_clear(Buffer *b) { void buffer_clear(Buffer *b) {

View File

@@ -1,6 +1,8 @@
#include "buffertest.h" #include "buffertest.h"
#include <sys/mman.h>
int main() { int main() {
/* testing basic Buffer api */
Buffer *test = buffer_new(16, "test"); Buffer *test = buffer_new(16, "test");
byte *a = ucmalloc(32); byte *a = ucmalloc(32);
@@ -52,6 +54,44 @@ int main() {
buffer_free(test); buffer_free(test);
/* testing pointer backed buffer */
FILE *RFD;
size_t rs;
if((RFD = fopen("README", "rb")) == NULL) {
fprintf(stderr, "oops, could not open README!\n");
return 1;
}
fseek(RFD, 0, SEEK_END);
rs = ftell(RFD);
fseek(RFD, 0, SEEK_SET);
void *r = mmap(NULL, rs, PROT_READ, 0, fileno(RFD), 0);
//unsigned char *r = urmalloc(256);
Buffer *rb = buffer_new_buf("r", r, rs);
fprintf(stderr, "r: %p rb->buf: %p\n", r, rb->buf);
buffer_info(rb);
size_t blocksize = 36;
void *chunk = malloc(blocksize);
while(buffer_done(rb) != 1) {
if(buffer_left(rb) < blocksize)
blocksize = buffer_left(rb);
buffer_get_chunk(rb, chunk, blocksize);
_dump("chunk", chunk, blocksize);
}
buffer_free(rb);
_dump("r", r, rs); /* should work! */
munmap(r, rs);
fclose(RFD);
fatals_ifany(); fatals_ifany();
return 0; return 0;