finished removing linked lists from the project
the memory overhead of using malloc() is significant, as is the memory overhead of having a next pointer in each node. dynamic arrays are not overly difficult to implement, and it's my opinion at the moment that they should be preferred.partial-rewrite
parent
a72e6ba4bc
commit
c07f7c56e9
|
@ -1,216 +0,0 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
* 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
|
||||
*/
|
||||
|
|
@ -1,168 +0,0 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
* Copyright (c) 2012, 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
|
||||
* Implements the list type in "../list.h"
|
||||
*/
|
||||
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include "../list.h"
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#define list_t list__list_t
|
||||
#define node_t list__node_t
|
||||
|
||||
// since we'll be casting to `node_t *` a lot
|
||||
#define N(name) ((node_t *) name)
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
void * list__insert(list_t * list, int8_t index, void * node) {
|
||||
// if `node` does not exist
|
||||
if (!node)
|
||||
return NULL;
|
||||
|
||||
list->length++;
|
||||
|
||||
if (list->length == 1) {
|
||||
// insert as only node (no others exist yet)
|
||||
list->head = node;
|
||||
list->tail = node;
|
||||
N(node)->next = NULL;
|
||||
|
||||
} else {
|
||||
index %= list->length;
|
||||
|
||||
if (index == 0) {
|
||||
// insert as first node
|
||||
N(node)->next = list->head;
|
||||
list->head = node;
|
||||
|
||||
} else if (index == list->length-1) {
|
||||
// insert as last node
|
||||
N(list->tail)->next = node;
|
||||
list->tail = node;
|
||||
N(node)->next = NULL;
|
||||
|
||||
} else {
|
||||
// insert as other node
|
||||
node_t * previous = list->head;
|
||||
for (uint8_t i=1; i<index; i++)
|
||||
previous = previous->next;
|
||||
N(node)->next = previous->next;
|
||||
previous->next = node;
|
||||
}
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
void * list__peek(list_t * list, int8_t index) {
|
||||
// if no nodes exist
|
||||
if (list->length == 0)
|
||||
return NULL;
|
||||
|
||||
index %= list->length;
|
||||
|
||||
// if last node
|
||||
if (index == list->length-1)
|
||||
return list->tail;
|
||||
|
||||
// else
|
||||
node_t * node = list->head;
|
||||
for (uint8_t i=0; i<index; i++)
|
||||
node = N(node)->next;
|
||||
return node;
|
||||
}
|
||||
|
||||
void * list__pop_index(list_t * list, int8_t index) {
|
||||
// if no nodes exist
|
||||
if (list->length == 0)
|
||||
return NULL;
|
||||
|
||||
index %= list->length;
|
||||
|
||||
node_t * node;
|
||||
|
||||
if (index == 0) {
|
||||
// pop first node
|
||||
node = list->head;
|
||||
list->head = N(node)->next;
|
||||
|
||||
} else {
|
||||
// find the `index-1`th node
|
||||
node_t * previous = list->head;
|
||||
for (uint8_t i=1; i<index; i++)
|
||||
previous = previous->next;
|
||||
|
||||
// if last node
|
||||
if (index == list->length-1)
|
||||
list->tail = previous;
|
||||
|
||||
// pop the node at `index`
|
||||
node = previous->next;
|
||||
previous->next = N(node)->next;
|
||||
}
|
||||
|
||||
list->length--;
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
void * list__pop_node(list_t * list, void * node) {
|
||||
// if `node` does not exist, or no nodes exist
|
||||
if (!node || list->length == 0)
|
||||
return NULL;
|
||||
|
||||
node_t * previous = list->head;
|
||||
|
||||
if (node == list->head) {
|
||||
// pop first node
|
||||
list->head = N(node)->next;
|
||||
|
||||
} else {
|
||||
// find the previous node (if `node` is in `list`)
|
||||
while (previous->next != node) {
|
||||
previous = previous->next;
|
||||
if (!previous)
|
||||
return NULL; // `node` not found
|
||||
}
|
||||
|
||||
// if last node
|
||||
if (node == list->tail)
|
||||
list->tail = previous;
|
||||
|
||||
// pop the node
|
||||
previous->next = N(node)->next;
|
||||
}
|
||||
|
||||
list->length--;
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
void * list__pop_node_next(list_t * list, void * node ) {
|
||||
if (!list__pop_node(list, node))
|
||||
return NULL; // `node` was not in `list`
|
||||
|
||||
node_t * next = N(node)->next;
|
||||
free(node);
|
||||
|
||||
return next;
|
||||
}
|
||||
|
||||
void list__free_all(list_t * list) {
|
||||
node_t * node;
|
||||
while (list->head) {
|
||||
node = list->head;
|
||||
list->head = node->next;
|
||||
free(node);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
# -----------------------------------------------------------------------------
|
||||
# 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
|
||||
# list options
|
||||
#
|
||||
# This file is meant to be included by the using '.../options.mk'
|
||||
#
|
||||
|
||||
|
||||
SRC += $(wildcard $(CURDIR)/*.c)
|
||||
|
|
@ -18,7 +18,6 @@
|
|||
#include "../firmware/keyboard.h"
|
||||
#include "../firmware/lib/timer.h"
|
||||
#include "../firmware/lib/usb.h"
|
||||
#include "../firmware/lib/data-types/list.h"
|
||||
#include "./main.h"
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
|
|
@ -64,7 +64,6 @@ GENDEPFLAGS :=
|
|||
$(call include_options_once,keyboard/$(KEYBOARD_NAME))
|
||||
$(call include_options_once,lib/usb)
|
||||
$(call include_options_once,lib/timer)
|
||||
$(call include_options_once,lib/data-types/list)
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
|
|
Loading…
Reference in New Issue