Skip to content

Instantly share code, notes, and snippets.

@trentgill
Last active February 7, 2017 03:43
Show Gist options
  • Save trentgill/22a01f4e5daa5eae2530ea20a5dcf2c1 to your computer and use it in GitHub Desktop.
Save trentgill/22a01f4e5daa5eae2530ea20a5dcf2c1 to your computer and use it in GitHub Desktop.
Simple program demonstrating a doubly-linked-list
/* 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;
}
#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);
}
#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