mirror of
https://codeberg.org/scip/pcp.git
synced 2025-12-17 12:00:56 +01:00
added buffer_new_buf() which makes it possible to back a Buffer with an existing pointer without copying
This commit is contained in:
@@ -74,7 +74,7 @@ typedef struct _pcp_buffer Buffer;
|
||||
*/
|
||||
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.
|
||||
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);
|
||||
|
||||
|
||||
/** 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 */
|
||||
void buffer_init(Buffer *b, size_t blocksize, char *name);
|
||||
|
||||
|
||||
@@ -21,13 +21,6 @@
|
||||
|
||||
#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) {
|
||||
b->name = ucmalloc(strlen(name)+1);
|
||||
b->size = blocksize;
|
||||
@@ -39,23 +32,40 @@ void buffer_init(Buffer *b, size_t blocksize, char *name) {
|
||||
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 *b = buffer_new(256, name);
|
||||
b->isstring = 1;
|
||||
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) {
|
||||
if(b != NULL) {
|
||||
if(b->allocated == 1) {
|
||||
/* free the underlying data pointer only if we allocated it */
|
||||
if(b->end > 0) {
|
||||
buffer_clear(b);
|
||||
}
|
||||
free(b->buf);
|
||||
}
|
||||
free(b);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void buffer_clear(Buffer *b) {
|
||||
b->offset = 0;
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
#include "buffertest.h"
|
||||
#include <sys/mman.h>
|
||||
|
||||
int main() {
|
||||
/* testing basic Buffer api */
|
||||
Buffer *test = buffer_new(16, "test");
|
||||
|
||||
byte *a = ucmalloc(32);
|
||||
@@ -52,6 +54,44 @@ int main() {
|
||||
|
||||
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();
|
||||
|
||||
return 0;
|
||||
|
||||
Reference in New Issue
Block a user