Last active
February 7, 2017 03:43
-
-
Save trentgill/22a01f4e5daa5eae2530ea20a5dcf2c1 to your computer and use it in GitHub Desktop.
Simple program demonstrating a doubly-linked-list
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* A simple program demonstrating a doubly-linked-list library. | |
Intended to store arbitrary timestamps that must be maintained | |
in chronological order w/ neighbour access. */ | |
#include <stdio.h> | |
#include "wrCueList.h" | |
cueList myCues; | |
int main(void) { | |
int location; | |
cl_init( &myCues ); // init start and end | |
cl_move_last( &myCues, 50 ); // move last cue to make room between cues | |
cl_goto_prev( &myCues ); // selects 1st cue | |
cl_add_now( &myCues, 25 ); // adds a cue & selects it | |
cl_add_now( &myCues, 35 ); // adds a cue & selects it | |
cl_move_here( &myCues, 33); | |
cl_goto_next( &myCues ); | |
cl_print_here( &myCues ); // prints timestamp of last cue = 50 | |
return 0; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stm32f4xx.h> | |
#include <stdlib.h> | |
#include <stdio.h> | |
#include "wrCueList.h" | |
#include "../(_)/lib/debug.h" // USART_() functions for 'sprintf' functionality over serial debugger | |
int cl_init( cueList* cl ){ | |
// USART_puts("\n\rcl_init"); | |
node_t *head = NULL; | |
head = malloc(sizeof(node_t)); | |
if(head == NULL) { return -1; USART_puts("\n\rERROR"); } // memory allocation failed | |
cl->start = head; // create external pointer to head | |
cl->selected = head; // default to start of tape selection | |
cl->n_selected = 0; // at index0 | |
cl->here = head; // default to first cue | |
cl->n_here = 0; // at first index | |
cl->n_count = 1; // 1 node | |
cl->last = head; | |
cl->ix_limit = CUELIMIT; | |
head->ts = 0; // timestamp is 0 | |
head->prev = NULL; // this is the first node | |
head->next = NULL; | |
head->next = malloc(sizeof(node_t)); // create last node | |
if(head->next == NULL) { return -1; USART_puts("\n\rERROR"); } // malloc failed | |
cl->n_count++; // added a node | |
cl->last = head->next; // move last marker | |
head->next->ts = 2; | |
head->next->prev = head; // point back to initial node | |
head->next->next = NULL; // 2 nodes total | |
return cl->last->ts; // return timestamp of last touched location | |
} | |
// ADD A CUE | |
int cl_add_now( cueList* cl, int timestamp ){ | |
USART_puts("\n\rcl_add_now"); | |
if( timestamp == ( cl->here->ts ) ) { | |
return -1; // a cue already exists at this timestamp | |
} | |
// create new node | |
node_t *now; | |
now = malloc(sizeof(node_t)); // allocate memory | |
if(now == NULL) { USART_puts("\n\rERROR"); return -1; } // malloc failed | |
now->next = cl->here->next; | |
now->prev = cl->here; | |
now->ts = timestamp; | |
// splice new node between here and here->next | |
cl->here->next->prev = now; // point back first (avoid losing reference) | |
cl->here->next = now; // update *here to new interim cue | |
// state machine update | |
cl->here = cl->here->next; // move to new cue | |
cl->n_here++; // moved forward 1 cue | |
cl->n_count++; // added a new cue | |
// SHOULD CUE AN SDCARD WRITE TO UPDATE SAVED FILES | |
cl_print_here( cl ); | |
return cl->n_here; // return cue index(?) | |
} | |
// REMOVE A CUE | |
int cl_rm_here( cueList* cl ){ | |
USART_puts("\n\rcl_rm_here"); | |
if( cl->here == cl->start ) { | |
USART_puts("\n\rERROR at start"); | |
return -1; // can't delete marker bc only start/end exists! | |
// don't worry about cl->last bc main loop stops it ever entering | |
// instead moves *last to be 1/2 frames past | |
} | |
node_t *before = cl->here->prev; // save current location | |
// move neighbours to skip *here | |
cl->here->next->prev = cl->here->prev; | |
cl->here->prev->next = cl->here->next; | |
// null pointers before freeing mem ?? | |
cl->here->prev = NULL; | |
cl->here->next = NULL; | |
free(cl->here); // free mem of current node | |
// state machine update | |
cl->here = before; // reassign *here to saved here->prev pointer | |
cl->n_here--; // deleted current cue, so falling back one | |
cl->n_count--; // deleted a cue | |
return cl->n_here; | |
} | |
// MOVE TIMESTAMPS OF EXISTING CUES | |
void cl_move_here( cueList* cl, int timestamp ){ | |
USART_puts("\n\rcl_mv_here"); | |
cl->here->ts = timestamp; | |
cl_print_here( cl ); | |
} | |
void cl_move_last( cueList* cl, int timestamp ){ | |
int32_t tmp = cl->last->ts - 1; // 1 mark before end | |
USART_puts("\n\rcl_mv_last"); | |
if(timestamp >= tmp) { | |
cl->last->ts = timestamp + 1; // move 'end' marker | |
USART_putn(cl->last->ts); // TIMESTAMP | |
} | |
} | |
// JUMP TO CUE | |
// private func! | |
void _update_sel_cue( cueList* cl ){ | |
// update cues->selected pointer | |
cl->cues->selected = cl->cues->here; | |
cl->cues->n_selected = cl->cues->n_here; | |
cl->c_now = cl->cues->here->ts; // grab cue point | |
} | |
void cl_goto_next( cueList* cl ){ | |
// move *here to next location | |
if(cl->cues->here->next->next == NULL) { // already at last 'real' cue | |
USART_puts("\n\rERROR: already at end"); | |
} | |
cl->cues->here = cl->cues->here->next; | |
cl->cues->n_here++; | |
_update_sel_cue(cl); | |
} | |
void cl_goto_prev( cueList* cl ){ | |
// move *here to prev location | |
if(cl->cues->here->prev == NULL ) { // avoid jumping to random NULL pointer | |
USART_puts("\n\rERROR: at start"); | |
_update_sel_cue(cl); | |
return; | |
} | |
cl->cues->here = cl->cues->here->prev; | |
cl->cues->n_here--; | |
_update_sel_cue(cl); | |
} | |
void cl_print_here( cueList* cl ){ | |
USART_puts("\n\rCurrent TS & Ix:"); | |
USART_putn(cl->here->ts); | |
USART_putn(cl->n_here); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef __wrCueList__ | |
#define __wrCueList__ | |
#define CUELIMIT 100 // Max size of Cue List | |
typedef struct node{ | |
int32_t ts; // timestamp (in increments of uSD block size) | |
struct node *prev; // pointer to prev node | |
struct node *next; // pointer to next node | |
} node_t; // "node_t" is shorthand for "struct node" | |
// i think indices might be unnecessary altogether! | |
// as long as we hold onto the appropriate pointers, everything is fully accessible!? | |
typedef struct _cueList { // meta struct for whole CLL | |
struct node *start; // start of CLL | |
struct node *here; // pointer to current selection | |
struct node *last; // last touched point of audio (end of the tape) | |
struct node *selected; // most recently called cue | |
int32_t n_here; // index of here* | |
int32_t n_selected; // index of selected* | |
int32_t n_count; // total number of nodes in CLL | |
int32_t ix_limit; // artificial memory limit to avoid massive leaks | |
// could add more pointers to random-access cues | |
// nb: need to maintain additional ix's for all RAM points though! | |
} cueList; | |
int cl_init( cueList* cl ); | |
int cl_add_now( cueList* cl, int timestamp ); | |
int cl_rm_here( cueList* cl ); | |
void cl_move_here( cueList* cl, int timestamp ); | |
void cl_move_last( cueList* cl, int timestamp ); | |
void cl_goto_next( cueList* cl ); | |
void cl_goto_prev( cueList* cl ); | |
void cl_print_here( cueList* cl ); | |
#endif |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment