Skip to content

Commit

Permalink
#124 add ringbuf and strbuf from flecs.util
Browse files Browse the repository at this point in the history
  • Loading branch information
SanderMertens committed Apr 8, 2020
1 parent 92c50b8 commit f47d3f8
Show file tree
Hide file tree
Showing 5 changed files with 768 additions and 0 deletions.
2 changes: 2 additions & 0 deletions include/flecs.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,10 @@ typedef char bool;

#include "flecs/util/os_api.h"
#include "flecs/util/vector.h"
#include "flecs/util/ringbuf.h"
#include "flecs/util/sparse.h"
#include "flecs/util/map.h"
#include "flecs/util/strbuf.h"
#include "flecs/util/os_api.h"

#ifdef __cplusplus
Expand Down
61 changes: 61 additions & 0 deletions include/flecs/util/ringbuf.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@


#ifndef FLECS_RINGBUF_H_
#define FLECS_RINGBUF_H_

#ifdef __cplusplus
extern "C" {
#endif

typedef struct ecs_ringbuf_t ecs_ringbuf_t;

FLECS_EXPORT
ecs_ringbuf_t* _ecs_ringbuf_new(
size_t elem_size,
int32_t elem_count);

#define ecs_ringbuf_new(T, elem_count)\
_ecs_ringbuf_new(sizeof(T), elem_count)

FLECS_EXPORT
void* _ecs_ringbuf_push(
ecs_ringbuf_t *buffer,
size_t elem_size);

#define ecs_ringbuf_push(buffer, T)\
(T*)_ecs_ringbuf_push(buffer, sizeof(T))

FLECS_EXPORT
void* _ecs_ringbuf_get(
ecs_ringbuf_t *buffer,
size_t elem_size,
int32_t index);

#define ecs_ringbuf_get(buffer, T, index)\
(T*)_ecs_ringbuf_get(buffer, sizeof(T), index)

FLECS_EXPORT
void* _ecs_ringbuf_last(
ecs_ringbuf_t *buffer,
size_t elem_size);

#define ecs_ringbuf_last(buffer, T)\
(T*)_ecs_ringbuf_last(buffer, elem_size)

FLECS_EXPORT
int32_t ecs_ringbuf_index(
ecs_ringbuf_t *buffer);

FLECS_EXPORT
int32_t ecs_ringbuf_count(
ecs_ringbuf_t *buffer);

FLECS_EXPORT
void ecs_ringbuf_free(
ecs_ringbuf_t *buffer);

#ifdef __cplusplus
}
#endif

#endif
168 changes: 168 additions & 0 deletions include/flecs/util/strbuf.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
#ifndef FLECS_STRBUF_H_
#define FLECS_STRBUF_H_

#ifdef __cplusplus
extern "C" {
#endif

#define ECS_STRBUF_INIT (ecs_strbuf_t){0}
#define ECS_STRBUF_ELEMENT_SIZE (511)
#define ECS_STRBUF_MAX_LIST_DEPTH (32)

/* A buffer builds up a list of elements which individually can be up to N bytes
* large. While appending, data is added to these elements. More elements are
* added on the fly when needed. When an application calls ecs_strbuf_get, all
* elements are combined in one string and the element administration is freed.
*
* This approach prevents reallocs of large blocks of memory, and therefore
* copying large blocks of memory when appending to a large buffer. A buffer
* preallocates some memory for the element overhead so that for small strings
* there is hardly any overhead, while for large strings the overhead is offset
* by the reduced time spent on copying memory.
*/

typedef struct ecs_strbuf_element {
bool buffer_embedded;
uint32_t pos;
char *buf;
struct ecs_strbuf_element *next;
} ecs_strbuf_element;

typedef struct ecs_strbuf_element_embedded {
ecs_strbuf_element super;
char buf[ECS_STRBUF_ELEMENT_SIZE + 1];
} ecs_strbuf_element_embedded;

typedef struct ecs_strbuf_element_str {
ecs_strbuf_element super;
char *alloc_str;
} ecs_strbuf_element_str;

typedef struct ecs_strbuf_list_elem {
uint32_t count;
const char *separator;
} ecs_strbuf_list_elem;

typedef struct ecs_strbuf_t {
/* When set by an application, append will write to this buffer */
char *buf;

/* The maximum number of characters that may be printed */
uint32_t max;

/* Size of elements minus current element */
uint32_t size;

/* The number of elements in use */
uint32_t elementCount;

/* Always allocate at least one element */
ecs_strbuf_element_embedded firstElement;

/* The current element being appended to */
ecs_strbuf_element *current;

/* Stack that keeps track of number of list elements, used for conditionally
* inserting a separator */
ecs_strbuf_list_elem list_stack[ECS_STRBUF_MAX_LIST_DEPTH];
uint32_t list_sp;
} ecs_strbuf_t;

/* Append format string to a buffer.
* Returns false when max is reached, true when there is still space */
FLECS_EXPORT
bool ecs_strbuf_append(
ecs_strbuf_t *buffer,
const char *fmt,
...);

/* Append format string with argument list to a buffer.
* Returns false when max is reached, true when there is still space */
FLECS_EXPORT
bool ecs_strbuf_vappend(
ecs_strbuf_t *buffer,
const char *fmt,
va_list args);

/* Append string to buffer.
* Returns false when max is reached, true when there is still space */
FLECS_EXPORT
bool ecs_strbuf_appendstr(
ecs_strbuf_t *buffer,
const char *str);

/* Append source buffer to destination buffer.
* Returns false when max is reached, true when there is still space */
FLECS_EXPORT
bool ecs_strbuf_mergebuff(
ecs_strbuf_t *dst_buffer,
ecs_strbuf_t *src_buffer);

/* Append string to buffer, transfer ownership to buffer.
* Returns false when max is reached, true when there is still space */
FLECS_EXPORT
bool ecs_strbuf_appendstr_zerocpy(
ecs_strbuf_t *buffer,
char *str);

/* Append string to buffer, do not free/modify string.
* Returns false when max is reached, true when there is still space */
FLECS_EXPORT
bool ecs_strbuf_appendstr_zerocpy_const(
ecs_strbuf_t *buffer,
const char *str);

/* Append n characters to buffer.
* Returns false when max is reached, true when there is still space */
FLECS_EXPORT
bool ecs_strbuf_appendstrn(
ecs_strbuf_t *buffer,
const char *str,
uint32_t n);

/* Return result string (also resets buffer) */
FLECS_EXPORT
char *ecs_strbuf_get(
ecs_strbuf_t *buffer);

/* Reset buffer without returning a string */
FLECS_EXPORT
void ecs_strbuf_reset(
ecs_strbuf_t *buffer);

/* Push a list */
FLECS_EXPORT
void ecs_strbuf_list_push(
ecs_strbuf_t *buffer,
const char *list_open,
const char *separator);

/* Pop a new list */
FLECS_EXPORT
void ecs_strbuf_list_pop(
ecs_strbuf_t *buffer,
const char *list_close);

/* Insert a new element in list */
FLECS_EXPORT
void ecs_strbuf_list_next(
ecs_strbuf_t *buffer);

/* Append formatted string as a new element in list */
FLECS_EXPORT
bool ecs_strbuf_list_append(
ecs_strbuf_t *buffer,
const char *fmt,
...);

/* Append string as a new element in list */
FLECS_EXPORT
bool ecs_strbuf_list_appendstr(
ecs_strbuf_t *buffer,
const char *str);

#ifdef __cplusplus
}
#endif

#endif
85 changes: 85 additions & 0 deletions src/ringbuf.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@

#include "flecs_private.h"

struct ecs_ringbuf_t {
ecs_vector_t *data;
int32_t index;
#ifndef NDEBUG
size_t elem_size;
#endif
};

ecs_ringbuf_t* _ecs_ringbuf_new(
size_t elem_size,
int32_t elem_count)
{
ecs_ringbuf_t *result = ecs_os_malloc(sizeof(ecs_ringbuf_t));
ecs_assert(result != NULL, ECS_OUT_OF_MEMORY, NULL);

result->data = ecs_vector_new(elem_size, elem_count);
result->index = 0;
return result;
}

void* _ecs_ringbuf_push(
ecs_ringbuf_t *buffer,
size_t elem_size)
{
ecs_assert(elem_size == buffer->elem_size, ECS_INVALID_PARAMETER, NULL);

int32_t size = ecs_vector_size(buffer->data);
int32_t count = ecs_vector_count(buffer->data);
void *result;

if (count == buffer->index) {
result = _ecs_vector_add(&buffer->data, elem_size);
} else {
result = _ecs_vector_get(buffer->data, elem_size, buffer->index);
}

buffer->index = (buffer->index + 1) % size;

return result;
}

void ecs_ringbuf_free(
ecs_ringbuf_t *buffer)
{
ecs_vector_free(buffer->data);
ecs_os_free(buffer);
}

void* _ecs_ringbuf_get(
ecs_ringbuf_t *buffer,
size_t elem_size,
int32_t index)
{
int32_t count = ecs_vector_count(buffer->data);
int32_t size = ecs_vector_size(buffer->data);
index = ((buffer->index - count + size) + (int32_t)index) % size;
return _ecs_vector_get(buffer->data, elem_size, index);
}

void* _ecs_ringbuf_last(
ecs_ringbuf_t *buffer,
size_t elem_size)
{
int32_t index = buffer->index;
if (!index) {
index = ecs_vector_size(buffer->data);
}

return _ecs_vector_get(buffer->data, elem_size, index - 1);
}

int32_t ecs_ringbuf_index(
ecs_ringbuf_t *buffer)
{
return buffer->index;
}

int32_t ecs_ringbuf_count(
ecs_ringbuf_t *buffer)
{
return ecs_vector_count(buffer->data);
}
Loading

0 comments on commit f47d3f8

Please sign in to comment.