sc/buffer/sc_buf.h
2021-02-06 08:11:54 +03:00

407 lines
11 KiB
C

/*
* MIT License
*
* Copyright (c) 2021 Ozan Tezcan
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef SC_BUF_H
#define SC_BUF_H
#include <assert.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#ifdef SC_HAVE_CONFIG_H
#include "sc_config.h"
#else
#define sc_buf_malloc malloc
#define sc_buf_realloc realloc
#define sc_buf_free free
#endif
#define SC_BUF_CORRUPT 1u
#define SC_BUF_OOM 3u
#define SC_BUF_REF 8
#define SC_BUF_DATA 16
#define SC_BUF_READ (SC_BUF_REF | SC_BUF_DATA)
struct sc_buf
{
unsigned char *mem;
uint32_t cap;
uint32_t limit;
uint32_t rpos;
uint32_t wpos;
unsigned int error;
bool ref;
};
/**
* Create buffer
*
* @param buf buffer
* @param cap initial capacity
* @return 'false' on out of memory.
*/
bool sc_buf_init(struct sc_buf *buf, uint32_t cap);
/**
* Destroy buffer
* @param buf buffer
*/
void sc_buf_term(struct sc_buf *buf);
/**
* Wrap memory into buffer, write position will be '0' after this call.
* Useful for using with pre-allocated/stack allocated buffers.
*
* @param data data pointer
* @param len len
* @param flags if set 'SC_BUF_REF', buffer will not try to expand itself and
* 'sc_buf_term' will not try to 'free()' buffer.
* if set 'SC_BUF_DATA', buffer wpos will be 'len'.
* flags can be combined : SC_BUF_REF | SC_BUF_DATA
* @return
*/
struct sc_buf sc_buf_wrap(void *data, uint32_t len, int flags);
/**
* Set limit of the buffer, when buffer reaches limit, it will set buffer's
* 'out of memory' flag. Default is UINT32_MAX.
*
* @param buf buffer
* @param limit limit
*/
void sc_buf_limit(struct sc_buf *buf, uint32_t limit);
/**
* @param buf buffer
* @param pos pos
* @return buffer address at 'pos'
*/
void *sc_buf_at(struct sc_buf *buf, uint32_t pos);
/**
* @param buf buffer
* @return current capacity.
*/
uint32_t sc_buf_cap(struct sc_buf *buf);
/**
* Reserve space
*
* @param buf buffer
* @param len len
* @return 'false' on out of memory or hits the 'limit'.
* 'out memory flag' will be set to check it later.
*/
bool sc_buf_reserve(struct sc_buf *buf, uint32_t len);
/**
* @param buf buffer
* @return 'true' if buffer is valid. Buffer can be invalid either on
* allocation failure or when you try to read data more than buffer
* has.
*/
bool sc_buf_valid(struct sc_buf *buf);
/**
* @param buf buffer
* @return current remaining space to write
*/
uint32_t sc_buf_quota(struct sc_buf *buf);
/**
* @param buf buffer
* @return current byte count in the buffer
*/
uint32_t sc_buf_size(struct sc_buf *buf);
/**
* Set read and write position to '0', clear error flag.
* @param buf buffer
*/
void sc_buf_clear(struct sc_buf *buf);
/**
* Compact buffer, e.g if bytes in buffer at [3, 20],
* it will be moved to [0, 17]
*
* @param buf buffer
*/
void sc_buf_compact(struct sc_buf *buf);
/**
* Advance read position, useful when you pass underlying array to another
* function which operates on void*. e.g socket write() call.
*
* @param buf buffer
* @param len len
*/
void sc_buf_mark_read(struct sc_buf *buf, uint32_t len);
/**
* Advance read position, useful when you pass underlying array to another
* function which operates on void*. e.g socket read() call.
*
* @param buf buffer
* @param len len
*/
void sc_buf_mark_write(struct sc_buf *buf, uint32_t len);
/**
* @param buf buffer
* @return current read position
*/
uint32_t sc_buf_rpos(struct sc_buf *buf);
/**
* @param buf buffer
* @return new read position
*/
void sc_buf_set_rpos(struct sc_buf *buf, uint32_t pos);
/**
* @param buf buffer
* @return current write position
*/
uint32_t sc_buf_wpos(struct sc_buf *buf);
/**
* @param buf buffer
* @return new write position
*/
void sc_buf_set_wpos(struct sc_buf *buf, uint32_t pos);
/**
* Get address of read position. Useful for e.g : write(fd, sc_buf_rbuf(buf) ..)
*
* @param buf buffer
* @return read address
*/
void *sc_buf_rbuf(struct sc_buf *buf);
/**
* Get address of write position. Useful for e.g : read(fd, sc_buf_wbuf(buf) ..)
*
* @param buf buffer
* @return write address
*/
void *sc_buf_wbuf(struct sc_buf *buf);
/**
* Copy from src to dest, it will copy maximum amount of bytes without expanding
* dest buffer size
*
* @param dest Destination buffer
* @param src Source buffer
*/
void sc_buf_move(struct sc_buf *dest, struct sc_buf *src);
/**
* Read from buffer without advancing read position. 'peek' functions will set
* error flags if buffer does not have required amount of data.
*/
uint8_t sc_buf_peek_8_at(struct sc_buf *buf, uint32_t pos);
uint16_t sc_buf_peek_16_at(struct sc_buf *buf, uint32_t pos);
uint32_t sc_buf_peek_32_at(struct sc_buf *buf, uint32_t pos);
uint64_t sc_buf_peek_64_at(struct sc_buf *buf, uint32_t pos);
uint8_t sc_buf_peek_8(struct sc_buf *buf);
uint16_t sc_buf_peek_16(struct sc_buf *buf);
uint32_t sc_buf_peek_32(struct sc_buf *buf);
uint64_t sc_buf_peek_64(struct sc_buf *buf);
uint32_t sc_buf_peek_data(struct sc_buf *buf, uint32_t pos, unsigned char *dest,
uint32_t len);
/**
* Set value at current write position. 'set' functions will not try to expand
* buffer if there is no space and error flags will be set.
*/
void sc_buf_set_8_at(struct sc_buf *buf, uint32_t pos, uint8_t val);
void sc_buf_set_16_at(struct sc_buf *buf, uint32_t pos, uint16_t val);
void sc_buf_set_32_at(struct sc_buf *buf, uint32_t pos, uint32_t val);
void sc_buf_set_64_at(struct sc_buf *buf, uint32_t pos, uint64_t val);
void sc_buf_set_8(struct sc_buf *buf, uint8_t val);
void sc_buf_set_16(struct sc_buf *buf, uint16_t val);
void sc_buf_set_32(struct sc_buf *buf, uint32_t val);
void sc_buf_set_64(struct sc_buf *buf, uint64_t val);
uint32_t sc_buf_set_data(struct sc_buf *buf, uint32_t pos, const void *src,
uint32_t len);
/**
* Get values from buffer, read position will be advanced.
*/
bool sc_buf_get_bool(struct sc_buf *buf);
uint8_t sc_buf_get_8(struct sc_buf *buf);
uint16_t sc_buf_get_16(struct sc_buf *buf);
uint32_t sc_buf_get_32(struct sc_buf *buf);
uint64_t sc_buf_get_64(struct sc_buf *buf);
double sc_buf_get_double(struct sc_buf *buf);
/**
* Read string. Strings are stored as [4 bytes length][string bytes]['\0'].
* So you can use return value without copying/freeing until you overwrite it
* in the buffer.
*
* @param buf buffer
* @return Pointer to string, possibly NULL if NULL has been put before.
*/
const char *sc_buf_get_str(struct sc_buf *buf);
/**
* Get binary data, returned pointer is valid until buffer is altered.
*
* @param buf buffer
* @param len data len
* @return pointer to data.
*/
void *sc_buf_get_blob(struct sc_buf *buf, uint32_t len);
/**
* Get binary data to destination buffer. If buffer does not have 'len' bytes,
* error flags will be set.
*
* @param buf buffer
* @param dest destination
* @param len len
*/
void sc_buf_get_data(struct sc_buf *buf, void *dest, uint32_t len);
/**
* Put functions, 'val' will be copied to the buffer and write position will
* be advanced.
*/
void sc_buf_put_bool(struct sc_buf *buf, bool val);
void sc_buf_put_8(struct sc_buf *buf, uint8_t val);
void sc_buf_put_16(struct sc_buf *buf, uint16_t val);
void sc_buf_put_32(struct sc_buf *buf, uint32_t val);
void sc_buf_put_64(struct sc_buf *buf, uint64_t val);
void sc_buf_put_double(struct sc_buf *buf, double val);
/**
* Write string. Strings are stored as [4 bytes length][string bytes]['\0'].
* NULL values are accepted, stored as [4 bytes length] = -1.
*
* @param buf buffer
* @param str string
*/
void sc_buf_put_str(struct sc_buf *buf, const char *str);
/**
* Write string. Strings are stored as [4 bytes length][string bytes]['\0'].
* NULL values are accepted, stored as [4 bytes length] = -1.
*
* @param buf buffer
* @param str string
* @param len string len excluding '\0' byte at the end
*/
void sc_buf_put_str_len(struct sc_buf *buf, const char *str, int len);
/**
* Put formatted string, passes arguments to vsnprintf
*
* @param buf buffer
* @param fmt fmt
* @param ... arguments
*/
void sc_buf_put_fmt(struct sc_buf *buf, const char *fmt, ...);
/**
* Put formatted string, passes arguments to vsnprintf but concatenates strings.
* Only useful if you want to append strings. It doesn't store string as length
* prefixed string. So, only valid use case is :
*
* e.g
*
* char tmp[128];
* struct sc_buf buf = sc_buf_wrap(tmp, sizeof(tmp), SC_BUF_REF);
* sc_buf_put_text(&buf, "Hello");
* sc_buf_put_text(&buf, " world");
*
* printf("%s", buf.mem); // Prints "Hello world"
*
*
* @param buf buffer
* @param fmt fmt
* @param ... arguments
*/
void sc_buf_put_text(struct sc_buf *buf, const char *fmt, ...);
/**
* Put binary data, it will store len in 4 bytes first, then binary data.
*
* @param buf buffer
* @param ptr data
* @param len data len
*/
void sc_buf_put_blob(struct sc_buf *buf, const void *ptr, uint32_t len);
/**
* Write 'len' bytes to buffer, on out of memory, error flag will be set.
*
* @param buf buffer
* @param dest dest
* @param len len
*/
void sc_buf_put_raw(struct sc_buf *buf, const void *ptr, uint32_t len);
/**
* Get encoded length of the variables.
*/
// clang-format off
static inline uint32_t sc_buf_bool_len(bool val) {(void) val; return 1;}
static inline uint32_t sc_buf_8_len(uint8_t val) {(void) val; return 1;}
static inline uint32_t sc_buf_16_len(uint16_t val){(void) val; return 2;}
static inline uint32_t sc_buf_32_len(uint32_t val){(void) val; return 4;}
static inline uint32_t sc_buf_64_len(uint64_t val){(void) val; return 8;}
static inline uint32_t sc_buf_double_len(double val){(void) val; return 8;}
// clang-format on
static inline uint32_t sc_buf_blob_len(void *ptr, uint32_t len)
{
(void) ptr;
assert(len <= INT32_MAX - 4);
return len + sc_buf_32_len(len);
}
static inline uint32_t sc_buf_str_len(const char *str)
{
const uint32_t bytes = sc_buf_32_len(UINT32_MAX) + sc_buf_8_len('\0');
if (str == NULL) {
return sc_buf_32_len(UINT32_MAX);
}
assert(strlen(str) <= INT32_MAX - 5);
return bytes + (uint32_t) strlen(str);
}
#endif