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
Ben Blazak 2013-07-23 22:39:54 -07:00
parent a72e6ba4bc
commit c07f7c56e9
5 changed files with 0 additions and 401 deletions

View File

@ -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
*/

View File

@ -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);
}
}

View File

@ -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)

View File

@ -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"
// ----------------------------------------------------------------------------

View File

@ -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)
# -----------------------------------------------------------------------------