diff options
Diffstat (limited to 'src/lib/buffer.h')
-rw-r--r-- | src/lib/buffer.h | 199 |
1 files changed, 199 insertions, 0 deletions
diff --git a/src/lib/buffer.h b/src/lib/buffer.h new file mode 100644 index 0000000..902ec88 --- /dev/null +++ b/src/lib/buffer.h @@ -0,0 +1,199 @@ +#ifndef BUFFER_H +#define BUFFER_H + +struct buffer { + union { + struct { + const void *data; + const size_t used; + }; + void *priv[9]; + }; +}; + +/* WARNING: Be careful with functions that return pointers to data. + With dynamic buffers they are valid only as long as buffer is not + realloc()ed. You shouldn't rely on it being valid if you have modified + buffer in any way. */ + +/* Create a modifiable buffer from given data. Writes past this size will + i_panic(). */ +void buffer_create_from_data(buffer_t *buffer, void *data, size_t size); +/* Create a non-modifiable buffer from given data. */ +void buffer_create_from_const_data(buffer_t *buffer, + const void *data, size_t size); +#define buffer_create_from_data(b,d,s) \ + TYPE_CHECKS(void, \ + COMPILE_ERROR_IF_TRUE(__builtin_object_size((d),1) < ((s)>0?(s):1)), \ + buffer_create_from_data((b), (d), (s))) +#define buffer_create_from_const_data(b,d,s) \ + TYPE_CHECKS(void, \ + COMPILE_ERROR_IF_TRUE(__builtin_object_size((d),1) < ((s)>0?(s):1)), \ + buffer_create_from_const_data((b), (d), (s))) + +/* Creates a dynamically growing buffer. Whenever write would exceed the + current size it's grown. */ +buffer_t *buffer_create_dynamic(pool_t pool, size_t init_size); +/* Create a dynamically growing buffer with a maximum size. Writes past the + maximum size will i_panic(). Internally allow it to grow max_size+1 so + str_c() NUL can be used. */ +buffer_t *buffer_create_dynamic_max(pool_t pool, size_t init_size, + size_t max_size); + +#define t_buffer_create(init_size) \ + buffer_create_dynamic(pool_datastack_create(), (init_size)) + +/* Free the memory used by buffer. Not needed if the memory is free'd + directly from the memory pool. */ +void buffer_free(buffer_t **buf); +/* Free the memory used by buffer structure, but return the buffer data + unfree'd. */ +void *buffer_free_without_data(buffer_t **buf); + +/* Returns the pool buffer was created with. */ +pool_t buffer_get_pool(const buffer_t *buf) ATTR_PURE; + +/* Write data to buffer at specified position. If pos is beyond the buffer's + current size, it is zero-filled up to that point (even if data_size==0). */ +void buffer_write(buffer_t *buf, size_t pos, + const void *data, size_t data_size); +/* Append data to buffer. */ +void buffer_append(buffer_t *buf, const void *data, size_t data_size); +/* Append character to buffer. */ +void buffer_append_c(buffer_t *buf, unsigned char chr); + +/* Insert the provided data into the buffer at position pos. If pos points past + the current buffer size, the gap is zero-filled. */ +void buffer_insert(buffer_t *buf, size_t pos, + const void *data, size_t data_size); +/* Delete data with the indicated size from the buffer at position pos. The + deleted block may cross the current buffer size boundary, which is ignored. + */ +void buffer_delete(buffer_t *buf, size_t pos, size_t size); +/* Replace the data in the buffer with the indicated size at position pos with + the provided data. This is a more optimized version of + buffer_delete(buf, pos, size); buffer_insert(buf, pos, data, data_size); */ +void buffer_replace(buffer_t *buf, size_t pos, size_t size, + const void *data, size_t data_size); + +/* Fill buffer with zero bytes. */ +void buffer_write_zero(buffer_t *buf, size_t pos, size_t data_size); +void buffer_append_zero(buffer_t *buf, size_t data_size); +void buffer_insert_zero(buffer_t *buf, size_t pos, size_t data_size); + +/* Copy data from buffer to another. The buffers may be same in which case + it's internal copying, possibly with overlapping positions (ie. memmove() + like functionality). copy_size may be set to SIZE_MAX to copy the rest of + the used data in buffer. */ +void buffer_copy(buffer_t *dest, size_t dest_pos, + const buffer_t *src, size_t src_pos, size_t copy_size); +/* Append data to buffer from another. copy_size may be set to SIZE_MAX to + copy the rest of the used data in buffer. */ +void buffer_append_buf(buffer_t *dest, const buffer_t *src, + size_t src_pos, size_t copy_size); + +/* Returns pointer to specified position in buffer. WARNING: The returned + address may become invalid if you add more data to buffer. */ +void *buffer_get_space_unsafe(buffer_t *buf, size_t pos, size_t size); +/* Increase the buffer usage by given size, and return a pointer to beginning + of it. */ +void *buffer_append_space_unsafe(buffer_t *buf, size_t size); + +/* Like buffer_get_data(), but don't return it as const. Returns NULL if the + buffer is non-modifiable. WARNING: The returned address may become invalid + if you add more data to buffer. */ +void *buffer_get_modifiable_data(const buffer_t *buf, size_t *used_size_r) + ATTR_NULL(2); + +/* Set the "used size" of buffer, ie. 0 would set the buffer empty. + Must not be used to grow buffer. The data after the buffer's new size will + be effectively lost, because e.g. buffer_get_space_unsafe() will zero out + the contents. */ +void buffer_set_used_size(buffer_t *buf, size_t used_size); + +/* Returns the current buffer size. */ +size_t buffer_get_size(const buffer_t *buf) ATTR_PURE; +/* Returns how many bytes we can write to buffer without increasing its size. + With dynamic buffers this is buffer_get_size()-1, because the extra 1 byte + is reserved for str_c()'s NUL. */ +size_t buffer_get_writable_size(const buffer_t *buf) ATTR_PURE; +/* Returns the maximum number of bytes we can append to the buffer. If the + buffer is dynamic, this is always near SIZE_MAX. */ +size_t buffer_get_avail_size(const buffer_t *buf) ATTR_PURE; + +/* Returns TRUE if buffer contents are identical. */ +bool buffer_cmp(const buffer_t *buf1, const buffer_t *buf2); + +/* Returns pointer to beginning of buffer data. Current used size of buffer is + stored in used_size if it's non-NULL. */ +static inline const void * ATTR_NULL(2) +buffer_get_data(const buffer_t *buf, size_t *used_size_r) +{ + if (used_size_r != NULL) + *used_size_r = buf->used; + return buf->data; +} + +/* Returns the current used buffer size. */ +static inline size_t ATTR_PURE +buffer_get_used_size(const buffer_t *buf) +{ + return buf->used; +} + +/* Crash if buffer was allocated from data stack and stack frame has changed. + This can be used as an assert-like check to verify that it's valid to + increase the buffer size here, instead of crashing only randomly when the + buffer needs to be increased. */ +void buffer_verify_pool(buffer_t *buf); + +/* This will truncate your byte buffer to contain at most + given number of bits. + + 1 bits: 01 00000001 + 2 bits: 03 00000011 + 3 bits: 07 00000111 + 4 bits: 0f 00001111 + 5 bits: 1f 00011111 + 6 bits: 3f 00111111 + 7 bits: 7f 01111111 + 8 bits: ff 11111111 + 9 bits: 01ff 0000000111111111 +10 bits: 03ff 0000001111111111 +11 bits: 07ff 0000011111111111 +12 bits: 0fff 0000111111111111 +13 bits: 1fff 0001111111111111 +14 bits: 3fff 0011111111111111 +15 bits: 7fff 0111111111111111 +16 bits: ffff 1111111111111111 + + and so forth + +*/ +void buffer_truncate_rshift_bits(buffer_t *buf, size_t bits); + +enum buffer_append_result { + /* Stream reached EOF successfully */ + BUFFER_APPEND_OK = 0, + /* Error was encountered */ + BUFFER_APPEND_READ_ERROR = -1, + /* Stream is non-blocking, call again later */ + BUFFER_APPEND_READ_MORE = -2, + /* Stream was consumed up to max_read_size */ + BUFFER_APPEND_READ_MAX_SIZE = -3, +}; + +/* Attempt to fully read a stream. Since this can be a network stream, it + can return BUFFER_APPEND_READ_MORE, which means you need to call this + function again. It is caller's responsibility to keep track of + max_read_size in case more reading is needed. */ +enum buffer_append_result +buffer_append_full_istream(buffer_t *buf, struct istream *is, size_t max_read_size, + const char **error_r); + +/* Attempt to fully read a file. BUFFER_APPEND_READ_MORE is never returned. */ +enum buffer_append_result +buffer_append_full_file(buffer_t *buf, const char *file, size_t max_read_size, + const char **error_r); + +#endif |