Skip to content

Commit

Permalink
Add tiny_queue (#10)
Browse files Browse the repository at this point in the history
  • Loading branch information
ryanplusplus authored Nov 4, 2024
1 parent 53a101f commit 425c628
Show file tree
Hide file tree
Showing 6 changed files with 583 additions and 3 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ jobs:

strategy:
matrix:
os: [ubuntu-20.04, ubuntu-22.04, ubuntu-latest, macos-12, macos-13]
os: [ubuntu-22.04, ubuntu-24.04, ubuntu-latest, macos-13]

steps:
- name: Install CppUTest
Expand Down
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,9 @@
See [include/hal](include/hal) for a list of all interfaces.

### Data Structures
`tiny` provides heapless, arbitrarily-sized (intrusive) list and ring buffer data structures. See:
`tiny` provides heapless, arbitrarily-sized (intrusive) list, queue, and ring buffer data structures. See:
- [`tiny_list`](include/tiny_list.h)
- [`tiny_queue`](include/tiny_queue.h)
- [`tiny_ring_buffer`](include/tiny_ring_buffer.h)

### Software Timers
Expand Down
66 changes: 66 additions & 0 deletions include/tiny_queue.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/*!
* @file
* @brief FIFO queue for arbitrarily-sized elements.
*/

#ifndef tiny_queue_h
#define tiny_queue_h

#include <stddef.h>
#include <stdint.h>
#include "tiny_ring_buffer.h"

typedef struct {
uint16_t element_count;
tiny_ring_buffer_t ring_buffer;
} tiny_queue_t;

/*!
* Initialize a queue with the provided buffer.
*/
void tiny_queue_init(
tiny_queue_t* self,
void* buffer,
size_t buffer_size);

/*!
* Add an element to the queue. Returns true if the element was successfully enqueued, false otherwise
*/
bool tiny_queue_enqueue(tiny_queue_t* self, const void* element, uint16_t size);

/*!
* Remove an element from the queue and copy it into the provided element buffer.
* @pre The queue is not empty
*/
void tiny_queue_dequeue(tiny_queue_t* self, void* element, uint16_t* size);

/*!
* Similar to Dequeue but the element is not retrieved.
* @pre The queue is not empty
*/
void tiny_queue_discard(tiny_queue_t* self);

/*!
* Peeks an element from the queue without removing it and copies it into the provided element buffer.
* @pre 0 <= index < The count of elements in the queue
*/
void tiny_queue_peek(tiny_queue_t* self, void* element, uint16_t* size, uint16_t index);

/*!
* Peek part of an element. Only copies out up to the specified number of bytes.
* @pre 0 <= index < The count of elements in the queue
*/
void tiny_queue_peek_partial(tiny_queue_t* self, void* element, uint16_t size_limit, uint16_t index);

/*!
* Peek part of an element. Only copies out up to the specified number of bytes.
* @pre 0 <= index < The count of elements in the queue
*/
void tiny_queue_peek_size(tiny_queue_t* self, uint16_t* size, uint16_t index);

/*!
* Get the number of elements in the queue.
*/
uint16_t tiny_queue_count(tiny_queue_t* self);

#endif
2 changes: 1 addition & 1 deletion library.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
"maintainer": true
}
],
"version": "6.3.0",
"version": "6.4.0",
"frameworks": "*",
"platforms": "*",
"export": {
Expand Down
143 changes: 143 additions & 0 deletions src/tiny_queue.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
/*!
* @file
* @brief
*/

#include "tiny_queue.h"

static void insert_element_size(tiny_queue_t* self, uint16_t element_size)
{
uint8_t* destination = (uint8_t*)&element_size;
for(uint16_t i = 0; i < sizeof(uint16_t); i++) {
tiny_ring_buffer_insert(&self->ring_buffer, destination);
destination++;
}
}

static void insert_element(tiny_queue_t* self, const void* element, uint16_t element_size)
{
const uint8_t* source = element;
for(uint16_t i = 0; i < element_size; i++) {
tiny_ring_buffer_insert(&self->ring_buffer, source);
source++;
}
}

static void remove_element_size(tiny_queue_t* self, uint16_t* sizePlaceHolder)
{
uint8_t* destination = (uint8_t*)sizePlaceHolder;
for(uint16_t i = 0; i < sizeof(uint16_t); i++) {
tiny_ring_buffer_remove(&self->ring_buffer, destination);
destination++;
}
}

static void remove_element(tiny_queue_t* self, void* element, uint16_t element_size)
{
uint8_t* destination = element;
for(uint16_t i = 0; i < element_size; i++) {
tiny_ring_buffer_remove(&self->ring_buffer, destination);
destination++;
}
}

static void discard_element(tiny_queue_t* self, uint16_t element_size)
{
for(uint16_t i = 0; i < element_size; i++) {
uint8_t discard;
tiny_ring_buffer_remove(&self->ring_buffer, &discard);
}
}

static void peek_element_size_at_ring_buffer_index(tiny_queue_t* self, uint16_t* element_size, uint16_t location)
{
uint8_t* destination = (uint8_t*)element_size;
for(uint16_t i = location; i < location + sizeof(uint16_t); i++) {
tiny_ring_buffer_at(&self->ring_buffer, i, destination);
destination++;
}
}

static uint16_t ring_buffer_index_for_element_index(tiny_queue_t* self, uint16_t element_index)
{
uint16_t element_size;
uint16_t location = 0;
for(uint16_t i = 0; i < element_index; i++) {
peek_element_size_at_ring_buffer_index(self, &element_size, location);
location += element_size + sizeof(uint16_t);
}
return location;
}

static void peek_element_at_ring_buffer_index(tiny_queue_t* self, void* element, uint16_t element_size, uint16_t location)
{
uint8_t* destination = element;
for(uint16_t i = location; i < location + element_size; i++) {
tiny_ring_buffer_at(&self->ring_buffer, i, destination);
destination++;
}
}

bool tiny_queue_enqueue(tiny_queue_t* self, const void* element, uint16_t element_size)
{
size_t required_space = element_size + sizeof(uint16_t);
size_t available_space = tiny_ring_buffer_capacity(&self->ring_buffer) - tiny_ring_buffer_count(&self->ring_buffer);

if(required_space <= available_space) {
insert_element_size(self, element_size);
insert_element(self, element, element_size);
self->element_count++;
return true;
}
else {
return false;
}
}

void tiny_queue_dequeue(tiny_queue_t* self, void* element, uint16_t* sizeStorage)
{
remove_element_size(self, sizeStorage);
remove_element(self, element, *sizeStorage);
self->element_count--;
}

void tiny_queue_discard(tiny_queue_t* self)
{
uint16_t sizeStorage;
remove_element_size(self, &sizeStorage);
discard_element(self, sizeStorage);
self->element_count--;
}

void tiny_queue_peek(tiny_queue_t* self, void* element, uint16_t* sizeStorage, uint16_t element_index)
{
uint16_t i = ring_buffer_index_for_element_index(self, element_index);
peek_element_size_at_ring_buffer_index(self, sizeStorage, i);
peek_element_at_ring_buffer_index(self, element, *sizeStorage, i + sizeof(uint16_t));
}

void tiny_queue_peek_partial(tiny_queue_t* self, void* element, uint16_t size, uint16_t element_index)
{
uint16_t i = ring_buffer_index_for_element_index(self, element_index);
peek_element_at_ring_buffer_index(self, element, size, i + sizeof(uint16_t));
}

void tiny_queue_peek_size(tiny_queue_t* self, uint16_t* sizeStorage, uint16_t element_index)
{
uint16_t i = ring_buffer_index_for_element_index(self, element_index);
peek_element_size_at_ring_buffer_index(self, sizeStorage, i);
}

uint16_t tiny_queue_count(tiny_queue_t* self)
{
return self->element_count;
}

void tiny_queue_init(
tiny_queue_t* self,
void* storage,
size_t storageSize)
{
self->element_count = 0;
tiny_ring_buffer_init(&self->ring_buffer, storage, sizeof(uint8_t), storageSize);
}
Loading

0 comments on commit 425c628

Please sign in to comment.