ref: cfd7660a044c8bd3ad0c33a237155b05248c0b0b
parent: 4ef01c1a0db8591883c74126cb81684ae4298b48
author: henesy <henesy.dev@gmail.com>
date: Fri Mar 4 00:21:44 EST 2022
init from stream
--- /dev/null
+++ b/ds.h
@@ -1,0 +1,4 @@
+#pragma src "/usr/glenda/src/ds"
+#pragma lib "libds.a"
+
+extern void* ecalloc(ulong, ulong);
--- /dev/null
+++ b/list.c
@@ -1,0 +1,66 @@
+#include <u.h>
+#include <libc.h>
+#include "ds.h"
+#include "list.h"
+
+// Return an allocated, empty, list.
+List*
+mklist(void)
+{
+ List *l = ecalloc(1, sizeof (List));
+ l->size = 0;
+ return l;
+}
+
+// Prepend to the front of the list.
+List*
+listprepend(List *l, void *datum)
+{
+ if(l == nil)
+ // Nil pointer
+ return l;
+
+ ListNode *n = ecalloc(1, sizeof (ListNode));
+
+ if(l->head == nil){
+ // Empty list, be the head
+ l->head = n;
+ }else{
+ // Replace head
+ n->next = l->head;
+ l->head = n;
+ }
+
+ l->head->datum = datum;
+ l->size++;
+
+ return l;
+}
+
+// Append to the end of the list.
+List*
+listappend(List *l, void *datum)
+{
+ if(l == nil)
+ // Nil pointer
+ return l;
+
+ ListNode *n = ecalloc(1, sizeof (ListNode));
+
+ if(l->head == nil){
+ // Empty list, be the head
+ l->head = n;
+ }else{
+ // Replace tail
+ ListNode *ln;
+ for(ln = l->head; ln->next != nil; ln = ln->next)
+ ;
+ ln->next = n;
+ n->next = nil;
+ }
+
+ n->datum = datum;
+ l->size++;
+
+ return l;
+}
--- /dev/null
+++ b/list.h
@@ -1,0 +1,28 @@
+// Defines a node in a list
+typedef struct ListNode ListNode;
+struct ListNode {
+ void *datum; // Data stored in node
+ ListNode *next; // Next node in the list
+
+ // Doubly-linked things
+ union {
+ ListNode *prev; // Previous node in the list
+ char empty; // Stub for space savings in single
+ };
+};
+
+// Defines a list from the head;
+typedef struct List List;
+struct List {
+ ListNode *head;
+ usize size;
+};
+
+// Return an allocated, empty, list.
+List* mklist(void);
+
+// Prepend to the front of the list.
+List* listprepend(List*, void*);
+
+// Append to the end of the list.
+List* listappend(List*, void*);
--- /dev/null
+++ b/mkfile
@@ -1,0 +1,22 @@
+</$objtype/mkfile
+
+LIBDIR =
+LIB = /$objtype/lib/libds.a
+
+OFILES=\
+ util.$O \
+ list.$O \
+
+HFILES=/sys/include/ds.h
+
+UPDATE=\
+ mkfile\
+ $HFILES\
+ ${OFILES:%.$O=%.c}\
+ ${LIB:/$objtype/%=/386/%}\
+
+</sys/src/cmd/mksyslib
+
+test:V: all
+ cd tests
+ mk test
--- /dev/null
+++ b/tests/main.c
@@ -1,0 +1,120 @@
+#include <u.h>
+#include <libc.h>
+#include "../ds.h"
+#include "../list.h"
+
+usize passed = 0;
+usize failed = 0;
+
+// Print whether a given test passes or fails.
+void
+tfail(char *t, int tf, char *msg)
+{
+ if(tf){
+ passed++;
+ fprint(2, "pass: %s\n", t);
+ }else{
+ failed++;
+ fprint(2, "fail: %s failed → %s\n", t, msg);
+ }
+ free(msg);
+}
+
+// End testing if a given test does not pass.
+void
+tfatal(char *t, int tf, char *msg)
+{
+ if(tf){
+ passed++;
+ fprint(2, "pass: %s\n", t);
+ free(msg);
+ }else{
+ failed++;
+ sysfatal("fail: %s hard failed → %s", t, msg);
+ }
+}
+
+// Test whether we can create a list.
+void
+testmklist(void)
+{
+ char *t = "mklist";
+ List *l = mklist();
+ tfatal(t, l != nil, smprint("list allocation failed"));
+ free(l);
+}
+
+void
+testprependlist(void)
+{
+ char *t = "prependlist";
+ List *l = mklist();
+ int i;
+ int n = 7;
+ for(i = 0; i < n; i++){
+ int v = i*i;
+ listprepend(l, &v);
+ }
+
+ tfail(t, l->size == n,
+ smprint("size → expected %d, got %ld", n, l->size)
+ );
+
+ ListNode *ln;
+ usize count = 0;
+ for(ln = l->head; ln != nil; ln = ln->next)
+ count++;
+
+ tfail(t, l->size == n,
+ smprint("size → iteration %d, got %ld", n, l->size)
+ );
+
+ // TODO - delete/free contents
+
+ free(l);
+}
+
+void
+testappendlist(void)
+{
+ char *t = "appendlist";
+ List *l = mklist();
+ int i;
+ int n = 7;
+ for(i = 0; i < n; i++){
+ int v = i*i;
+ listappend(l, &v);
+ }
+
+ tfail(t, l->size == n,
+ smprint("size → expected %d, got %ld", n, l->size)
+ );
+
+ ListNode *ln;
+ usize count = 0;
+ for(ln = l->head; ln != nil; ln = ln->next)
+ count++;
+
+ tfail(t, l->size == n,
+ smprint("size → iteration %d, got %ld", n, l->size)
+ );
+
+ // TODO - delete/free contents
+
+ free(l);
+}
+
+void
+main(int, char*[])
+{
+ // Lists
+ testmklist();
+ testprependlist();
+ testappendlist();
+
+ // Final output
+ double percent = (double)((double)passed/(double)(passed+failed))*100.0;
+ print("%ld passed. %ld failed. %3.0f%% passing.\n", passed, failed, percent);
+
+ exits(nil);
+}
--- /dev/null
+++ b/tests/mkfile
@@ -1,0 +1,10 @@
+</$objtype/mkfile
+
+LDFLAGS = ($LDFLAGS '-I../')
+
+OFILES = main.$O\
+
+</sys/src/cmd/mkone
+
+test:V: all
+ $O.out
--- /dev/null
+++ b/util.c
@@ -1,0 +1,13 @@
+#include <u.h>
+#include <libc.h>
+#include "ds.h"
+
+// Guarded calloc(2)
+void*
+ecalloc(ulong n, ulong size)
+{
+ void *m = calloc(n, size);
+ if(m == nil)
+ sysfatal("err: calloc failed → %r");
+ return m;
+}