Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add tiny_queue #10

Merged
merged 1 commit into from
Nov 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading