Skip to content

Instantly share code, notes, and snippets.

@tjhv
Created February 17, 2018 05:19
Show Gist options
  • Save tjhv/3be76a3efd2df7635483badccda1e188 to your computer and use it in GitHub Desktop.
Save tjhv/3be76a3efd2df7635483badccda1e188 to your computer and use it in GitHub Desktop.
Rough implementation of the linked list data structure with functions to help visualize the memory layout and check integrity of linkage.
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#include <assert.h>
#undef DEBUG_VERBOSE
void debug_print(char *fmt, ...)
{
#ifdef DEBUG_VERBOSE
va_list a_list;
va_start(a_list, fmt);
vprintf(fmt, a_list);
va_end(a_list);
#endif
}
typedef struct Node_s
{
void *obj;
struct Node_s *next;
struct Node_s *prev;
uint16_t reference;
} Node_t;
typedef struct List_s
{
Node_t *first;
Node_t *last;
size_t count;
} List_t;
void insert_multi(List_t *, uint8_t, ...);
Node_t * insert_after(List_t *, void *, void *);
Node_t * insert_before(List_t *, void *, void *);
Node_t * insert(List_t *, void *);
bool contains(List_t *, void *);
Node_t * find(List_t *, void *);
Node_t * retrieve_after(List_t *, void *);
Node_t * retrieve_before(List_t *, void *);
void uninsert_multi(List_t *, uint8_t, ...);
void uninsert(List_t *, void *);
void clear_list(List_t *);
Node_t * reset_ref(List_t *, void *);
void remove_ref(List_t *, void *);
size_t count(List_t *);
void display(List_t *);
void check_integrity(List_t *);
int main(void)
{
List_t *head = malloc(sizeof(*head));
head->first = NULL;
head->last = NULL;
head->count = 0;
int x=4, y=5, z=6, a=1, b=2, c=3, g=9, m=10;
insert_multi(head, 6, &a, &b, &c, &x, &y, &z);
count(head);
display(head);
insert_after(head, &g, &x);
insert_before(head, &m, &g);
insert_before(head, &g, &a);
insert_after(head, &g, &a);
check_integrity(head);
count(head);
//uninsert_multi(head, 7, &a, &b, &c, &x, &y, &z, &g);
//clear_list(head);
display(head);
count(head);
return 0;
}
void insert_multi(List_t *head, uint8_t nargs, ...)
{
assert(head);
va_list a_list;
va_start(a_list, nargs);
uint8_t i = 0;
for(i = 0; i < nargs; ++i)
insert(head, va_arg(a_list, void *));
va_end(a_list);
}
Node_t * insert_after(List_t *head, void *obj, void *aobj)
{
assert(head && obj && aobj);
Node_t *ref = find(head, obj);
if(ref)
{
debug_print("%s - object @%p already exists at node @%p, increased reference count\n", __func__, obj, ref);
++ref->reference;
return ref;
}
Node_t *tmp = find(head, aobj);
if(tmp)
{
Node_t *otmp = malloc(sizeof(*otmp));
assert(otmp);
debug_print("%s - inserting @%p at node @%p\n",
__func__, obj, otmp);
otmp->next = tmp->next;
if(tmp->next)
tmp->next->prev = otmp;
otmp->prev = tmp;
otmp->obj = obj;
if(head->last == tmp)
head->last = otmp;
tmp->next = otmp;
++head->count;
otmp->reference = 1;
return otmp;
}
debug_print("%s - object @%p not found\n", __func__, aobj);
return NULL;
}
Node_t * insert_before(List_t *head, void *obj, void *bobj)
{
assert(head && obj && bobj);
Node_t *ref = find(head, obj);
if(ref)
{
debug_print("%s - object @%p already exists at node @%p, increased reference count\n", __func__, obj, ref);
++ref->reference;
return ref;
}
Node_t *tmp = find(head, bobj);
if(tmp)
{
Node_t *otmp = malloc(sizeof(*otmp));
assert(otmp);
debug_print("%s - inserting @%p at node @%p\n",
__func__, obj, otmp);
otmp->next = tmp;
otmp->prev = tmp->prev;
if(tmp->prev)
tmp->prev->next = otmp;
otmp->obj = obj;
if(head->first == tmp)
head->first = otmp;
tmp->prev = otmp;
++head->count;
otmp->reference = 1;
return otmp;
}
debug_print("%s - object @%p not found\n", __func__, bobj);
return NULL;
}
Node_t * insert(List_t *head, void *obj)
{
assert(head && obj);
Node_t *ref = find(head, obj);
if(ref)
{
debug_print("%s - object @%p already exists at node @%p, increased reference count\n", __func__, obj, ref);
++ref->reference;
return ref;
}
Node_t *tmp = malloc(sizeof(*tmp));
assert(tmp);
debug_print("%s - inserting object @%p at node @%p\n", __func__, obj, tmp);
tmp->next = head->first;
if(head->first)
{
tmp->prev = head->first->prev;
head->first->prev = tmp;
}
else
{
tmp->prev = NULL;
}
tmp->obj = obj;
if(head->count < 2)
head->last = head->first;
++head->count;
tmp->reference = 1;
return (head->first = tmp);
}
bool contains(List_t *head, void *obj)
{
if(find(head, obj))
return true;
return false;
}
Node_t * find(List_t *head, void *obj)
{
assert(head && obj);
debug_print("%s - searching nodes for object @%p\n", __func__, obj);
int i = 0;
Node_t *tmp = NULL;
for(tmp = head->first; tmp; tmp = tmp->next)
{
++i;
if(tmp->obj == obj)
{
debug_print("%s - found @%p at node @%p after %d tries.\n",
__func__, obj, tmp, i);
return tmp;
}
debug_print("%s - skipping node @%p\n", __func__, tmp);
}
debug_print("%s - unable to find @%p after %d tries!\n", __func__, obj, i);
return NULL;
}
Node_t * retrieve_after(List_t *head, void *obj)
{
assert(head && obj);
Node_t *tmp = find(head, obj);
if(tmp)
{
return tmp->next;
}
return NULL;
}
Node_t * retrieve_before(List_t *head, void *obj)
{
assert(head && obj);
Node_t *tmp = find(head, obj);
if(tmp)
{
return tmp->prev;
}
return NULL;
}
void uninsert_multi(List_t *head, uint8_t nargs, ...)
{
assert(head);
va_list a_list;
va_start(a_list, nargs);
uint8_t i = 0;
for(i = 0; i < nargs; ++i)
uninsert(head, va_arg(a_list, void *));
va_end(a_list);
}
void uninsert(List_t *head, void *obj)
{
assert(head && obj);
debug_print("%s - attempting to remove node for object @%p\n",
__func__, obj);
Node_t *tmp = find(head, obj);
if(tmp)
{
if(tmp->reference > 1)
{
--tmp->reference;
debug_print("%s - %d ref for object @%p node @%p\n",
__func__, tmp->reference, obj, tmp);
return;
}
if(tmp->next)
tmp->next->prev = tmp->prev;
if(tmp->prev)
tmp->prev->next = tmp->next;
if(head->last == tmp)
head->last = tmp->prev;
if(head->first == tmp)
head->first = tmp->next;
--tmp->reference;
debug_print("%s - removed node @%p for object @%p\n",
__func__, tmp, tmp->obj);
tmp->obj = NULL;
free(tmp);
tmp = NULL;
--head->count;
return;
}
debug_print("%s - no nodes with object @%p exist!\n", __func__, obj);
}
void clear_list(List_t *head)
{
assert(head);
Node_t *tmp = NULL, *next = NULL;
debug_print("%s - starting cycle\n", __func__);
for(tmp = head->first; tmp; tmp = next)
{
debug_print("%s - removing @%p\n",
__func__, tmp);
next = tmp->next;
tmp->prev = NULL;
tmp->next = NULL;
tmp->obj = NULL;
free(tmp);
tmp = NULL;
--head->count;
}
head->first = NULL;
head->last = NULL;
debug_print("%s - completed\n", __func__);
}
Node_t * reset_ref(List_t *head, void *obj)
{
assert(head && obj);
Node_t *tmp = find(head, obj);
if(tmp)
{
debug_print("%s - reset ref for object @%p at node @%p, from %d to 1\n", __func__, obj, tmp, tmp->reference);
tmp->reference = 1;
return tmp;
}
debug_print("%s - no references for object @%p exist!\n", __func__, obj);
return NULL;
}
void remove_ref(List_t *head, void *obj)
{
assert(head && obj);
Node_t *tmp = reset_ref(head, obj);
if(tmp)
{
debug_print("%s - removing all refs for object @%p\n",
__func__, obj);
uninsert(head, obj);
return;
}
debug_print("%s - no references for @%p exist!\n", __func__, obj);
}
size_t count(List_t *head)
{
assert(head);
printf("%s - nodes @%zu\n", __func__, head->count);
return head->count;
}
void display(List_t *head)
{
assert(head);
printf("%s - printing...\n", __func__);
Node_t *tmp = NULL;
for(tmp = head->first; tmp; tmp = tmp->next)
{
printf("@%p <- @%p -> @%p, obj @%p : %d\n",
tmp->prev, tmp, tmp->next, tmp->obj, tmp->reference);
}
printf("%s - head first @%p, head last @%p\n",
__func__, head->first, head->last);
printf("%s - complete\n", __func__);
}
void check_integrity(List_t *head)
{
assert(head);
printf("%s - checking...\n", __func__);
uint8_t pass = 0, fail = 0;
Node_t *tmp = NULL, *last = NULL;
for(tmp = head->first; tmp;)
{
last = tmp;
tmp = tmp->next;
if(((tmp != last) && ((tmp != NULL && last != NULL) != 0)))
{
if(((last->next == tmp) && (tmp->prev == last)))
{
printf("%s - passed: node @%p and @%p\n",
__func__, last, tmp);
++pass;
continue;
}
printf("%s - failed: node @%p and @%p\n",
__func__, last, tmp);
++fail;
}
else if ((pass == 0 && fail == 0))
{
printf("%s - not enough nodes to compare.\n",
__func__);
}
}
printf("%s - check complete, %d passes and %d fails\n",
__func__, pass, fail);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment