217 lines
7.6 KiB
C
217 lines
7.6 KiB
C
/* ----------------------------------------------------------------------------
|
|
* Copyright (c) 2013 Ben Blazak <benblazak.dev@gmail.com>
|
|
* Released under The MIT License (see "doc/licenses/MIT.md")
|
|
* Project located at <https://github.com/benblazak/ergodox-firmware>
|
|
* ------------------------------------------------------------------------- */
|
|
|
|
/** description
|
|
* An interface to a simple linked-list that can be used to implement lists,
|
|
* queues, stacks, and things
|
|
*
|
|
* Prefix: `list__`
|
|
*
|
|
*
|
|
* Usage notes:
|
|
*
|
|
* - All functions that accept an `index` set `index %= list->length` before
|
|
* using it. This will make all passed indices valid. It also provides a
|
|
* convenient way to reference the last element of a list, by passing `-1` as
|
|
* the index (as in Python).
|
|
*
|
|
* - All pointers to `list__node_t` are accepted and returned as as `void`
|
|
* pointers, so that using files won't have to do so much work casting
|
|
* things. They are converted internally to `list__node_t` before use, and
|
|
* should be stored by using code in pointers of appropriate (non `void *`)
|
|
* type.
|
|
*
|
|
* - Full node types should be defined in the using '.c' or '.h' file, with
|
|
* something like
|
|
*
|
|
* typedef struct {
|
|
* list__node_t _super; // must be the first element
|
|
* uint8_t data;
|
|
* } node_t;
|
|
*
|
|
* - If you want to iterate through a list, use something like
|
|
*
|
|
* for (node_t * node = list->head; node; node = node->_super.next) {
|
|
* // do stuff
|
|
* }
|
|
*
|
|
* - If you want to insert a new node at the end of `list` (for example), use
|
|
* something like
|
|
*
|
|
* node_t * node = list__insert(list, -1, malloc(sizeof(node_t)));
|
|
* if (!node) return 1; // error
|
|
*
|
|
* Keep in mind that the initialization of the data stored in the node is the
|
|
* calling function's responsibility.
|
|
*
|
|
*
|
|
* Assumptions:
|
|
*
|
|
* - Lists will never contain more than 128 elements (the number of elements
|
|
* that can be indexed by an `int8_t`).
|
|
*
|
|
*
|
|
* Cautions:
|
|
*
|
|
* - This library should be used sparingly if SRAM usage is of much concern.
|
|
* `malloc()` for small amounts of data is horribly inefficient space wise.
|
|
* See [this section]
|
|
* (http://www.nongnu.org/avr-libc/user-manual/malloc.html)
|
|
* of the avr-libc user manual for details.
|
|
*/
|
|
|
|
|
|
#ifndef ERGODOX_FIRMWARE__FIRMWARE__LIB__DATA_TYPES__LIST__H
|
|
#define ERGODOX_FIRMWARE__FIRMWARE__LIB__DATA_TYPES__LIST__H
|
|
// ----------------------------------------------------------------------------
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
|
#include <stdint.h>
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
typedef struct list__node_t {
|
|
void * next; // will be cast to `list__node_t *` before use
|
|
} list__node_t;
|
|
|
|
typedef struct list__list_t {
|
|
void * head; // will be cast to `list__node_t *` before use
|
|
void * tail; // will be cast to `list__node_t *` before use
|
|
uint8_t length;
|
|
} list__list_t;
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
void * list__insert (list__list_t * list, int8_t index, void * node);
|
|
void * list__peek (list__list_t * list, int8_t index);
|
|
void * list__pop_index (list__list_t * list, int8_t index);
|
|
void * list__pop_node (list__list_t * list, void * node);
|
|
void * list__pop_node_next (list__list_t * list, void * node);
|
|
void list__free_all (list__list_t * list);
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// ----------------------------------------------------------------------------
|
|
#endif // ERGODOX_FIRMWARE__FIRMWARE__LIB__DATA_TYPES__LIST__H
|
|
|
|
|
|
|
|
// ============================================================================
|
|
// === documentation ==========================================================
|
|
// ============================================================================
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// types ----------------------------------------------------------------------
|
|
// ----------------------------------------------------------------------------
|
|
|
|
// === list__node_t ===
|
|
/** types/list__node_t/description
|
|
* The type of a "node", for the purposes of this library
|
|
*/
|
|
|
|
// === list__list_t ===
|
|
/** types/list__list_t/description
|
|
* Simple struct to define and keep track of our list
|
|
*/
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// functions ------------------------------------------------------------------
|
|
// ----------------------------------------------------------------------------
|
|
|
|
// === list__insert() ===
|
|
/** functions/list__insert/description
|
|
* Insert `node` at position `index % list->length`
|
|
*
|
|
* Arguments:
|
|
* - `list`: A pointer to the list to be operated on
|
|
* - `index`: An `int8_t` indicating the position the new node will occupy
|
|
* - `node`: A `void *` pointer to the node to insert
|
|
*
|
|
* Returns:
|
|
* - success: A `void *` pointer to the inserted node
|
|
* - failure: `NULL`
|
|
*/
|
|
|
|
// === list__peek() ===
|
|
/** functions/list__peek/description
|
|
* Return a pointer to the node at position `index % list->length`
|
|
*
|
|
* Arguments:
|
|
* - `list`: A pointer to the list to be operated on
|
|
* - `index`: An `int8_t` indicating the position the new node will occupy
|
|
*
|
|
* Returns:
|
|
* - success: A `void *` pointer to the node at position `index % list->length`
|
|
* - failure: `NULL`
|
|
*/
|
|
|
|
// === list__pop_index() ===
|
|
/** functions/list__pop_index/description
|
|
* Return a pointer to the node at position `index % list->length`, and remove
|
|
* the node from the list
|
|
*
|
|
* Warnings:
|
|
* - Does not free the node's memory; this is the calling function's
|
|
* responsibility.
|
|
*
|
|
* Arguments:
|
|
* - `list`: A pointer to the list to be operated on
|
|
* - `index`: An `int8_t` indicating the position the new node will occupy
|
|
*
|
|
* Returns:
|
|
* - success: A `void *` pointer to the node at position `index % list->length`
|
|
* - failure: `NULL`
|
|
*/
|
|
|
|
// === list__pop_node() ===
|
|
/** functions/list__pop_node/description
|
|
* Remove `node` from the list, and return a pointer to it
|
|
*
|
|
* Warnings:
|
|
* - Does not free the node's memory; this is the calling function's
|
|
* responsibility.
|
|
*
|
|
* Arguments:
|
|
* - `list`: A pointer to the list to be operated on
|
|
* - `node`: A `void *` pointer to the node to pop
|
|
*
|
|
* Returns:
|
|
* - success: A `void *` pointer to `node`
|
|
* - failure: `NULL`
|
|
*/
|
|
|
|
// === list__pop_node_next() ===
|
|
/** functions/list__pop_node_next/description
|
|
* Remove `node` from the list, free its memory, and return a pointer to the
|
|
* next element, if such an element exists
|
|
*
|
|
* Arguments:
|
|
* - `list`: A pointer to the list to be operated on
|
|
* - `node`: A `void *` pointer to the node to pop (and free)
|
|
*
|
|
* Returns:
|
|
* - success: A `void *` pointer to the next node in the list
|
|
* - failure: `NULL`
|
|
*
|
|
* Notes:
|
|
* - This is helpful, sometimes, when iterating through a list, some of who's
|
|
* members need to be removed. If performance is critical, keep in mind that
|
|
* it does have the O(n) time penalty of having to re-search the list for the
|
|
* given node's predecessor before removing the node.
|
|
*/
|
|
|
|
// === list__free_all() ===
|
|
/** functions/list__free_all/description
|
|
* Free all node pointers in `list`
|
|
*
|
|
* Arguments:
|
|
* - `list`: A pointer to the list to be operated on
|
|
*/
|
|
|