diff --git a/CMakeLists.txt b/CMakeLists.txt index 9fed4fa..a53356c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,6 +3,7 @@ project(UDPConnection) set(UDPConnection_SOURCES src/UDPConnection.c + src/Deque.c ) set(CMAKE_C_FLAGS "-Wall -Wno-missing-braces") diff --git a/src/Deque.c b/src/Deque.c index 622d65a..ea8dbba 100644 --- a/src/Deque.c +++ b/src/Deque.c @@ -3,13 +3,60 @@ #include #include -void UDPC_Deque_init(UDPC_Deque *deque, uint32_t alloc_size) +int UDPC_Deque_init(UDPC_Deque *deque, uint32_t alloc_size) { - deque->head = 0; - deque->tail = 0; - deque->size = 0; + UDPC_Deque_clear(deque); deque->alloc_size = alloc_size; deque->buf = malloc(alloc_size); + if(deque->buf) + { + return 1; + } + else + { + return 0; + } +} + +void UDPC_Deque_destroy(UDPC_Deque *deque) +{ + free(deque->buf); + deque->buf = NULL; +} + +int UDPC_Deque_realloc(UDPC_Deque *deque, uint32_t new_size) +{ + if(new_size < deque->size) + { + return 0; + } + else if(deque->size != 0 && deque->tail <= deque->head) + { + char *buf = malloc(new_size); + memcpy(buf, &deque->buf[deque->head], deque->alloc_size - deque->head); + if(deque->tail != 0) + { + memcpy(&buf[deque->alloc_size - deque->head], deque->buf, deque->tail); + } + free(deque->buf); + deque->buf = buf; + deque->alloc_size = new_size; + return 1; + } + else + { + void *buf = realloc(deque->buf, new_size); + if(buf) + { + deque->buf = buf; + deque->alloc_size = new_size; + return 1; + } + else + { + return 0; + } + } } int UDPC_Deque_push_back(UDPC_Deque *deque, const char *data, uint32_t size) @@ -86,12 +133,18 @@ uint32_t UDPC_Deque_get_available(UDPC_Deque *deque) return deque->alloc_size - deque->size; } +uint32_t UDPC_Deque_get_used(UDPC_Deque *deque) +{ + return deque->size; +} + int UDPC_Deque_get_back(UDPC_Deque *deque, char **data, uint32_t *size) { int returnValue = 1; if(deque->size == 0) { *size = 0; + *data = NULL; return 0; } else if(*size > deque->size) @@ -122,6 +175,7 @@ int UDPC_Deque_get_front(UDPC_Deque *deque, char **data, uint32_t *size) if(deque->size == 0) { *size = 0; + *data = NULL; return 0; } else if(*size > deque->size) @@ -154,9 +208,7 @@ void UDPC_Deque_pop_back(UDPC_Deque *deque, uint32_t size) } else if(deque->size <= size) { - deque->head = 0; - deque->tail = 0; - deque->size = 0; + UDPC_Deque_clear(deque); return; } @@ -180,9 +232,7 @@ void UDPC_Deque_pop_front(UDPC_Deque *deque, uint32_t size) } else if(deque->size <= size) { - deque->head = 0; - deque->tail = 0; - deque->size = 0; + UDPC_Deque_clear(deque); return; } @@ -201,3 +251,78 @@ void UDPC_Deque_pop_front(UDPC_Deque *deque, uint32_t size) } } } + +int UDPC_Deque_index(UDPC_Deque *deque, uint32_t unitSize, uint32_t index, char **out) +{ + uint32_t pos = unitSize * index; + uint32_t abspos; + if(pos >= deque->alloc_size) + { + *out = NULL; + return 0; + } + + *out = malloc(unitSize); + + if(pos + deque->head >= deque->alloc_size) + { + abspos = pos + deque->head - deque->alloc_size; + } + else + { + abspos = pos + deque->head; + } + + if(abspos + unitSize >= deque->alloc_size) + { + memcpy(*out, &deque->buf[abspos], deque->alloc_size - abspos); + memcpy(*out, deque->buf, unitSize - (deque->alloc_size - abspos)); + } + else + { + memcpy(*out, &deque->buf[abspos], unitSize); + } + + return 1; +} + +int UDPC_Deque_index_rev(UDPC_Deque *deque, uint32_t unitSize, uint32_t index, char **out) +{ + uint32_t pos = unitSize * (index + 1); + uint32_t abspos; + if(pos >= deque->alloc_size) + { + *out = NULL; + return 0; + } + + *out = malloc(unitSize); + + if(pos > deque->tail) + { + abspos = deque->alloc_size - (pos - deque->tail); + } + else + { + abspos = deque->tail - pos; + } + + if(abspos + unitSize >= deque->alloc_size) + { + memcpy(*out, &deque->buf[abspos], deque->alloc_size - abspos); + memcpy(*out, deque->buf, unitSize - (deque->alloc_size - abspos)); + } + else + { + memcpy(*out, &deque->buf[abspos], unitSize); + } + + return 1; +} + +void UDPC_Deque_clear(UDPC_Deque *deque) +{ + deque->head = 0; + deque->tail = 0; + deque->size = 0; +} diff --git a/src/Deque.h b/src/Deque.h index dccc6f6..a67b7c3 100644 --- a/src/Deque.h +++ b/src/Deque.h @@ -12,7 +12,22 @@ typedef struct char *buf; } UDPC_Deque; -void UDPC_Deque_init(UDPC_Deque *deque, uint32_t alloc_size); +/*! + * \return non-zero on success + */ +int UDPC_Deque_init(UDPC_Deque *deque, uint32_t alloc_size); + +/*! + * Frees resources used by a UDPC_Deque + */ +void UDPC_Deque_destroy(UDPC_Deque *deque); + +/*! + * Fails if new_size is smaller than current size of Deque. + * On failure, deque remains unchanged. + * \return non-zero on success + */ +int UDPC_Deque_realloc(UDPC_Deque *deque, uint32_t new_size); /*! * If there was not enough space in the Deque, then no data is inserted at all. @@ -26,8 +41,16 @@ int UDPC_Deque_push_back(UDPC_Deque *deque, const char *data, uint32_t size); */ int UDPC_Deque_push_front(UDPC_Deque *deque, const char *data, uint32_t size); +/*! + * \return size in bytes of available data + */ uint32_t UDPC_Deque_get_available(UDPC_Deque *deque); +/*! + * \return size in bytes of used data + */ +uint32_t UDPC_Deque_get_used(UDPC_Deque *deque); + /*! * \brief Get data from back of deque * Data must be free'd after use as it was allocated with malloc. @@ -64,4 +87,28 @@ void UDPC_Deque_pop_back(UDPC_Deque *deque, uint32_t size); */ void UDPC_Deque_pop_front(UDPC_Deque *deque, uint32_t size); +/*! + * \brief Get a unitSize sized chunk of data at position unitSize * index + * The data will be indexed relative to the head of the Deque. + * The out pointer will be malloc'd with size unitSize and will have a copy of + * the data at the specified unitSize * index. + * Note that the out data must be free'd, but nothing will be malloc'd on fail + * and *out will be set to NULL. + * \return non-zero if unitSize * index < allocated_size_of_Deque + */ +int UDPC_Deque_index(UDPC_Deque *deque, uint32_t unitSize, uint32_t index, char **out); + +/*! + * \brief Get a unitSize sized chunk of data at position relative to tail + * The out pointer will be malloc'd with size unitSize and will have a copy of + * the data at the specified unitSize * (index + 1) relative to tail in reverse + * direction. + * Note that the out data must be free'd, but nothing will be malloc'd on fail + * and *out will be set to NULL. + * \return non-zero if unitSize * (index + 1) < allocated_size_of_Deque + */ +int UDPC_Deque_index_rev(UDPC_Deque *deque, uint32_t unitSize, uint32_t index, char **out); + +void UDPC_Deque_clear(UDPC_Deque *deque); + #endif