submodule

This commit is contained in:
maxchen32 2024-01-06 23:47:47 +08:00
parent 6c6a5be4ed
commit 79a8c00636
13 changed files with 1352 additions and 1 deletions

@ -1 +0,0 @@
Subproject commit 23faa20d03b67d752e1f882f0832c941a942c75b

6
src/list/.gitignore vendored Normal file
View file

@ -0,0 +1,6 @@
.DS_Store
bin
.pomo
*.o
build
deps

74
src/list/History.md Normal file
View file

@ -0,0 +1,74 @@
0.4.1 / 2023-05-05
==================
* Minor fixes for debian packaging (#43)
0.1.0 / 2020-05-15
==================
* Update list.h to allow configuration header set up LIST macros (#27)
* fix typo in README (#19)
0.0.8 / 2015-01-30
==================
* fix `list_at` unsigned compare error (bolasblack, #13)
* travis: Fail the build if any memory is leaked
* travis: Update before installing deps
* test: Fix memory leaks
0.0.7 / 2014-06-02
==================
* ci: Remove benchmarks
* add travis
* test: Fix 'unused parameter' warning
* readme: Update benchmarks
* benchmark: Fix 'unused parameter' warning
* benchmark: Use clibs/bench for CPU time
* readme: Correct types
* readme: Add syntax highlighting
* iterator: set to `NULL` after freeing
0.0.6 / 2014-05-06
==================
* list.h: Fix header guards
* Add “list” prefix to sources
0.0.5 / 2013-10-20
==================
* add package.json
* fix free in link_remove(). Closes #3
0.0.4 / 2011-04-15
==================
* pop -> rpop
* shift -> lpop
* push -> rpush
* unshift -> lpush
0.0.3 / 2010-11-27
==================
* Added `make install`
* Added `list_shift()`
* Added `list_pop()`
* Lowercased function names and typedefs
* Wrap with extern "C" when \_\_cplusplus
* Installing `list.h`
0.0.2 / 2010-08-21
==================
* Added `ListNode *List_at(List *self, int index)`
* Added `void List_remove(List *self, ListNode *node)`
* Added `make liblist.a`
0.0.1 / 2010-08-13
==================
* Initial release

22
src/list/LICENSE Normal file
View file

@ -0,0 +1,22 @@
(The MIT License)
Copyright (c) 2009-2010 TJ Holowaychuk <tj@vision-media.ca>
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
'Software'), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

72
src/list/Makefile Normal file
View file

@ -0,0 +1,72 @@
AR ?= ar
CC ?= gcc
STRIP ?= strip
PREFIX ?= /usr/local
LIBDIR ?= $(PREFIX)/lib
INCLUDEDIR ?= $(PREFIX)/include
INCLUDESUBDIR ?= /clibs
DESTDIR ?=
CFLAGS = -O3 -std=c99 -Wall -Wextra -Ideps
LDFLAGS ?= -Wl,-z,now
SRCS = src/list.c \
src/list_node.c \
src/list_iterator.c
OBJS = $(SRCS:.c=.o)
MAJOR_VERSION = 0
MINOR_VERSION = 4
PATCH_VERSION = 1
all: build/libclibs_list.a build/libclibs_list.so.$(MAJOR_VERSION).$(MINOR_VERSION).$(PATCH_VERSION)
install: all
test -d $(DESTDIR)$(LIBDIR) || -mkdir $(DESTDIR)$(LIBDIR)
cp -f build/libclibs_list.a $(DESTDIR)$(LIBDIR)/libclibs_list.a
cp -f build/libclibs_list.so.$(MAJOR_VERSION).$(MINOR_VERSION).$(PATCH_VERSION) $(DESTDIR)$(LIBDIR)/libclibs_list.so.$(MAJOR_VERSION).$(MINOR_VERSION).$(PATCH_VERSION)
ln -sf libclibs_list.so.$(MAJOR_VERSION).$(MINOR_VERSION).$(PATCH_VERSION) $(DESTDIR)$(LIBDIR)/libclibs_list.so.$(MAJOR_VERSION)
ln -sf libclibs_list.so.$(MAJOR_VERSION) $(DESTDIR)$(LIBDIR)/libclibs_list.so
test -d $(DESTDIR)$(INCLUDEDIR)$(INCLUDESUBDIR) || -mkdir $(DESTDIR)$(INCLUDEDIR)$(INCLUDESUBDIR)/
cp -f src/list.h $(DESTDIR)$(INCLUDEDIR)$(INCLUDESUBDIR)/list.h
uninstall:
rm -f $(DESTDIR)$(LIBDIR)/libclibs_list.a
rm -f $(DESTDIR)$(LIBDIR)/libclibs_list.so
rm -f $(DESTDIR)$(LIBDIR)/libclibs_list.so.$(MAJOR_VERSION)
rm -f $(DESTDIR)$(LIBDIR)/libclibs_list.so.$(MAJOR_VERSION).$(MINOR_VERSION)
rm -f $(DESTDIR)$(LIBDIR)/libclibs_list.so.$(MAJOR_VERSION).$(MINOR_VERSION).$(PATCH_VERSION)
rm -f $(DESTDIR)$(INCLUDEDIR)$(INCLUDESUBDIR)/list.h
build/libclibs_list.a: $(OBJS)
-mkdir build
$(AR) rcs $@ $^
build/libclibs_list.so.$(MAJOR_VERSION).$(MINOR_VERSION).$(PATCH_VERSION): $(OBJS)
-mkdir build
$(CC) $(LDFLAGS) -shared -lc -Wl,-soname,`basename $@ | sed s/\.${MINOR_VERSION}.${PATCH_VERSION}//` src/*.o -o $@
$(STRIP) --strip-unneeded --remove-section=.comment --remove-section=.note $@
bin/test: test.o $(OBJS)
-mkdir bin
$(CC) $^ -o $@
bin/benchmark: benchmark.o $(OBJS)
-mkdir bin
$(CC) $^ -o $@
%.o: %.c
$(CC) $< $(CFLAGS) -c -o $@
clean:
rm -fr bin build *.o src/*.o
test: bin/test
@./$<
benchmark: bin/benchmark
@./$<
.PHONY: test benchmark clean install uninstall

185
src/list/Readme.md Normal file
View file

@ -0,0 +1,185 @@
# list
C doubly linked list implementation.
## API
Below is the public api currently provided by "list".
## list_t *list_new();
Allocate and initialize a `list`.
list_t *mylist = list_new();
## list_node_t \*list_node_new(void *val)
Allocate and initialize a `list_node_t` with the given _val_.
```c
list_node_t *node = list_node_new("my value");
node->val; // "my value"
```
## list_node_t \* list_rpush(list_t \*self, list_node_t *node)
Append _node_ to _self_, returning _node_.
```c
list_rpush(list, list_node_new("value"));
list->tail->val; // "value"
```
## list_node_t \* list_rpop(list_t \*self)
Return / detach node from the end of the list, or __NULL__.
```c
list_node_t *last = list_rpop(names);
```
## list_node_t \*list_lpush(list_t \*self, list_node_t *node)
Prepend _node_ to _self_, returning _node_.
```c
list_lpush(list, list_node_new("value"));
list->head->val; // "value"
```
## list_node_t \*list_find(list_t \*self, void *val)
Return the `list_node_t` containing _val_ or __NULL__.
```c
list_node_t *node = list_find(list, "some value");
```
## list_node_t \*list_at(list_t *self, int index)
Return the `list_node_t` at the given _index_, where _index_
may also be a negative integer indicating an index from the
list _tail_.
```c
list_at(list, 0); // first
list_at(list, 1); // second
list_at(list, -1); // last
list_at(list, -3); // third last
```
## void list_remove(list_t \*self, list_node_t *node)
Remove _node_ from the list, freeing it and it's value.
```c
list_remove(list, node);
```
## void list_destroy(list_t *self)
Free the list and all nodes.
```c
list_destroy(list);
```
## list_iterator_t \*list_iterator_new(list_t *list, list_direction_t direction)
Allocate and initialize a `list_iterator_t` with the given _direction_,
where _direction_ may be __LIST_HEAD__ or __LIST_TAIL__.
```c
list_node_t *node;
list_iterator_t *it = list_iterator_new(list, LIST_HEAD);
while ((node = list_iterator_next(it))) {
puts(node->val);
}
```
## list_node_t \*list_iterator_next(list_iterator_t *self)
Return the next `list_node_t` or __NULL__.
## void list_iterator_destroy(list_iterator_t *self);
Free the iterator only.
```c
list_iterator_destroy(it);
```
## Examples
list iteration:
```c
list_t *langs = list_new();
list_node_t *c = list_rpush(langs, list_node_new("c"));
list_node_t *js = list_rpush(langs, list_node_new("js"));
list_node_t *ruby = list_rpush(langs, list_node_new("ruby"));
list_node_t *node;
list_iterator_t *it = list_iterator_new(langs, LIST_HEAD);
while ((node = list_iterator_next(it))) {
puts(node->val);
}
list_iterator_destroy(it);
list_destroy(langs);
```
stdout:
c
js
ruby
## Benchmarks
$ make benchmark
10,000,000 nodes
lpush: 0.5000s
rpush: 0.5000s
lpop: 0.0312s
rpop: 0.0312s
find (last node): 0.0312s
iterate: 0.0625s
at(100,000): 0.0000s
at(1,000,000): 0.0000s
at(-100,000): 0.0000s
## Testing
$ make test
## License
(The MIT License)
Copyright (c) 2009-2010 TJ Holowaychuk &lt;tj@vision-media.ca&gt;
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
'Software'), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

146
src/list/benchmark.c.bak Normal file
View file

@ -0,0 +1,146 @@
#include <stdio.h>
#include "bench/bench.h"
#include "src/list.h"
static void
bm(char *label, void (*fn)()) {
printf(" %18s", label);
fflush(stdout);
fn();
}
static int nnodes = 10000000;
static float startTime;
static void
start() {
startTime = cpu();
}
static void
stop() {
float duration = cpu() - startTime;
printf(": \x1b[32m%.4f\x1b[0ms\n", duration);
}
static void
bm_rpush() {
start();
int n = nnodes;
list_t *list = list_new();
while (n--) {
list_rpush(list, list_node_new("foo"));
}
stop();
}
static void
bm_lpush() {
start();
int n = nnodes;
list_t *list = list_new();
while (n--) {
list_lpush(list, list_node_new("foo"));
}
stop();
}
static void
bm_find() {
int n = nnodes;
list_t *list = list_new();
while (n--) {
list_lpush(list, list_node_new("foo"));
}
list_rpush(list, list_node_new("bar"));
start();
list_find(list, "bar");
stop();
}
static void
bm_iterate() {
int n = nnodes;
list_t *list = list_new();
while (n--) {
list_lpush(list, list_node_new("foo"));
}
list_iterator_t *it = list_iterator_new(list, LIST_HEAD);
list_node_t *node;
start();
while ((node = list_iterator_next(it)))
;
stop();
}
static void
bm_rpop() {
int n = nnodes;
list_t *list = list_new();
while (n--) {
list_lpush(list, list_node_new("foo"));
}
list_node_t *node;
start();
while ((node = list_rpop(list)))
;
stop();
}
static void
bm_lpop() {
int n = nnodes;
list_t *list = list_new();
while (n--) {
list_lpush(list, list_node_new("foo"));
}
list_node_t *node;
start();
while ((node = list_lpop(list)))
;
stop();
}
static list_t *list;
static void
bm_at() {
start();
list_at(list, 100000);
stop();
}
static void
bm_at2() {
start();
list_at(list, 1000000);
stop();
}
static void
bm_at3() {
start();
list_at(list, -100000);
stop();
}
int
main(void){
int n = nnodes;
list = list_new();
while (n--) list_lpush(list, list_node_new("foo"));
puts("\n 10,000,000 nodes\n");
bm("lpush", bm_lpush);
bm("rpush", bm_rpush);
bm("lpop", bm_lpop);
bm("rpop", bm_rpop);
bm("find (last node)", bm_find);
bm("iterate", bm_iterate);
bm("at(100,000)", bm_at);
bm("at(1,000,000)", bm_at2);
bm("at(-100,000)", bm_at3);
puts("");
return 0;
}

17
src/list/clib.json Normal file
View file

@ -0,0 +1,17 @@
{
"name": "list",
"version": "0.4.1",
"repo": "clibs/list",
"description": "Simple linked list",
"keywords": ["list", "structure"],
"license": "MIT",
"src": [
"src/list_iterator.c",
"src/list.c",
"src/list_node.c",
"src/list.h"
],
"development": {
"bench": "*"
}
}

215
src/list/src/list.c Normal file
View file

@ -0,0 +1,215 @@
//
// list.c
//
// Copyright (c) 2010 TJ Holowaychuk <tj@vision-media.ca>
//
#include "list.h"
/*
* Allocate a new list_t. NULL on failure.
*/
list_t *
list_new(void) {
list_t *self;
if (!(self = LIST_MALLOC(sizeof(list_t))))
return NULL;
self->head = NULL;
self->tail = NULL;
self->free = NULL;
self->match = NULL;
self->len = 0;
return self;
}
/*
* Free the list.
* @self: Pointer to the list
*/
void
list_destroy(list_t *self) {
unsigned int len = self->len;
list_node_t *next;
list_node_t *curr = self->head;
while (len--) {
next = curr->next;
if (self->free) self->free(curr->val);
LIST_FREE(curr);
curr = next;
}
LIST_FREE(self);
}
/*
* Append the given node to the list
* and return the node, NULL on failure.
* @self: Pointer to the list for popping node
* @node: the node to push
*/
list_node_t *
list_rpush(list_t *self, list_node_t *node) {
if (!node) return NULL;
if (self->len) {
node->prev = self->tail;
node->next = NULL;
self->tail->next = node;
self->tail = node;
} else {
self->head = self->tail = node;
node->prev = node->next = NULL;
}
++self->len;
return node;
}
/*
* Return / detach the last node in the list, or NULL.
* @self: Pointer to the list for popping node
*/
list_node_t *
list_rpop(list_t *self) {
if (!self->len) return NULL;
list_node_t *node = self->tail;
if (--self->len) {
(self->tail = node->prev)->next = NULL;
} else {
self->tail = self->head = NULL;
}
node->next = node->prev = NULL;
return node;
}
/*
* Return / detach the first node in the list, or NULL.
* @self: Pointer to the list for popping node
*/
list_node_t *
list_lpop(list_t *self) {
if (!self->len) return NULL;
list_node_t *node = self->head;
if (--self->len) {
(self->head = node->next)->prev = NULL;
} else {
self->head = self->tail = NULL;
}
node->next = node->prev = NULL;
return node;
}
/*
* Prepend the given node to the list
* and return the node, NULL on failure.
* @self: Pointer to the list for pushing node
* @node: the node to push
*/
list_node_t *
list_lpush(list_t *self, list_node_t *node) {
if (!node) return NULL;
if (self->len) {
node->next = self->head;
node->prev = NULL;
self->head->prev = node;
self->head = node;
} else {
self->head = self->tail = node;
node->prev = node->next = NULL;
}
++self->len;
return node;
}
/*
* Return the node associated to val or NULL.
* @self: Pointer to the list for finding given value
* @val: Value to find
*/
list_node_t *
list_find(list_t *self, void *val) {
list_iterator_t *it = list_iterator_new(self, LIST_HEAD);
list_node_t *node;
while ((node = list_iterator_next(it))) {
if (self->match) {
if (self->match(val, node->val)) {
list_iterator_destroy(it);
return node;
}
} else {
if (val == node->val) {
list_iterator_destroy(it);
return node;
}
}
}
list_iterator_destroy(it);
return NULL;
}
/*
* Return the node at the given index or NULL.
* @self: Pointer to the list for finding given index
* @index: the index of node in the list
*/
list_node_t *
list_at(list_t *self, int index) {
list_direction_t direction = LIST_HEAD;
if (index < 0) {
direction = LIST_TAIL;
index = ~index;
}
if ((unsigned)index < self->len) {
list_iterator_t *it = list_iterator_new(self, direction);
list_node_t *node = list_iterator_next(it);
while (index--) node = list_iterator_next(it);
list_iterator_destroy(it);
return node;
}
return NULL;
}
/*
* Remove the given node from the list, freeing it and it's value.
* @self: Pointer to the list to delete a node
* @node: Pointer the node to be deleted
*/
void
list_remove(list_t *self, list_node_t *node) {
node->prev
? (node->prev->next = node->next)
: (self->head = node->next);
node->next
? (node->next->prev = node->prev)
: (self->tail = node->prev);
if (self->free) self->free(node->val);
LIST_FREE(node);
--self->len;
}

130
src/list/src/list.h Normal file
View file

@ -0,0 +1,130 @@
//
// list.h
//
// Copyright (c) 2010 TJ Holowaychuk <tj@vision-media.ca>
//
#ifndef __CLIBS_LIST_H__
#define __CLIBS_LIST_H__
#ifdef __cplusplus
extern "C" {
#endif
#include <stdlib.h>
// Library version
#define LIST_VERSION "0.4.1"
// Memory management macros
#ifdef LIST_CONFIG_H
#define _STR(x) #x
#define STR(x) _STR(x)
#include STR(LIST_CONFIG_H)
#undef _STR
#undef STR
#endif
#ifndef LIST_MALLOC
#define LIST_MALLOC malloc
#endif
#ifndef LIST_FREE
#define LIST_FREE free
#endif
/*
* list_t iterator direction.
*/
typedef enum {
LIST_HEAD
, LIST_TAIL
} list_direction_t;
/*
* list_t node struct.
*/
typedef struct list_node {
struct list_node *prev;
struct list_node *next;
void *val;
} list_node_t;
/*
* list_t struct.
*/
typedef struct {
list_node_t *head;
list_node_t *tail;
unsigned int len;
void (*free)(void *val);
int (*match)(void *a, void *b);
} list_t;
/*
* list_t iterator struct.
*/
typedef struct {
list_node_t *next;
list_direction_t direction;
} list_iterator_t;
// Node prototypes.
list_node_t *
list_node_new(void *val);
// list_t prototypes.
list_t *
list_new(void);
list_node_t *
list_rpush(list_t *self, list_node_t *node);
list_node_t *
list_lpush(list_t *self, list_node_t *node);
list_node_t *
list_find(list_t *self, void *val);
list_node_t *
list_at(list_t *self, int index);
list_node_t *
list_rpop(list_t *self);
list_node_t *
list_lpop(list_t *self);
void
list_remove(list_t *self, list_node_t *node);
void
list_destroy(list_t *self);
// list_t iterator prototypes.
list_iterator_t *
list_iterator_new(list_t *list, list_direction_t direction);
list_iterator_t *
list_iterator_new_from_node(list_node_t *node, list_direction_t direction);
list_node_t *
list_iterator_next(list_iterator_t *self);
void
list_iterator_destroy(list_iterator_t *self);
#ifdef __cplusplus
}
#endif
#endif /* __CLIBS_LIST_H__ */

View file

@ -0,0 +1,62 @@
//
// iterator.c
//
// Copyright (c) 2010 TJ Holowaychuk <tj@vision-media.ca>
//
#include "list.h"
/*
* Allocate a new list_iterator_t. NULL on failure.
* Accepts a direction, which may be LIST_HEAD or LIST_TAIL.
*/
list_iterator_t *
list_iterator_new(list_t *list, list_direction_t direction) {
list_node_t *node = direction == LIST_HEAD
? list->head
: list->tail;
return list_iterator_new_from_node(node, direction);
}
/*
* Allocate a new list_iterator_t with the given start
* node. NULL on failure.
*/
list_iterator_t *
list_iterator_new_from_node(list_node_t *node, list_direction_t direction) {
list_iterator_t *self;
if (!(self = LIST_MALLOC(sizeof(list_iterator_t))))
return NULL;
self->next = node;
self->direction = direction;
return self;
}
/*
* Return the next list_node_t or NULL when no more
* nodes remain in the list.
*/
list_node_t *
list_iterator_next(list_iterator_t *self) {
list_node_t *curr = self->next;
if (curr) {
self->next = self->direction == LIST_HEAD
? curr->next
: curr->prev;
}
return curr;
}
/*
* Free the list iterator.
*/
void
list_iterator_destroy(list_iterator_t *self) {
LIST_FREE(self);
self = NULL;
}

23
src/list/src/list_node.c Normal file
View file

@ -0,0 +1,23 @@
//
// node.c
//
// Copyright (c) 2010 TJ Holowaychuk <tj@vision-media.ca>
//
#include "list.h"
/*
* Allocates a new list_node_t. NULL on failure.
*/
list_node_t *
list_node_new(void *val) {
list_node_t *self;
if (!(self = LIST_MALLOC(sizeof(list_node_t))))
return NULL;
self->prev = NULL;
self->next = NULL;
self->val = val;
return self;
}

400
src/list/test.c.bak Normal file
View file

@ -0,0 +1,400 @@
#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "src/list.h"
// Helpers
#define test(fn) \
puts("... " # fn); \
test_##fn(); //Call the test function
// For counting destroyed time
static int freeProxyCalls = 0;
void
freeProxy(void *val) {
++freeProxyCalls;
free(val);
}
typedef struct {
char *name;
} User;
static int
User_equal(void *a1, void *b1) {
User *a = a1;
User *b = b1;
return 0 == strcmp(a->name, b->name);
}
// Tests
static void
test_list_node_new() {
char *val = "some value";
list_node_t *node = list_node_new(val);
assert(node->val == val);
free(node);
}
static void
test_list_rpush() {
// Setup
list_t *list = list_new();
list_node_t *a = list_node_new("a");
list_node_t *b = list_node_new("b");
list_node_t *c = list_node_new("c");
// a b c
list_rpush(list, a);
list_rpush(list, b);
list_rpush(list, c);
// Assertions
assert(a == list->head);
assert(c == list->tail);
assert(3 == list->len);
assert(b == a->next);
assert(NULL == a->prev);
assert(c == b->next);
assert(a == b->prev);
assert(NULL == c->next);
assert(b == c->prev);
list_destroy(list);
}
static void
test_list_lpush() {
// Setup
list_t *list = list_new();
list_node_t *a = list_node_new("a");
list_node_t *b = list_node_new("b");
list_node_t *c = list_node_new("c");
// c b a
list_rpush(list, a);
list_lpush(list, b);
list_lpush(list, c);
// Assertions
assert(c == list->head);
assert(a == list->tail);
assert(3 == list->len);
assert(NULL == a->next);
assert(b == a->prev);
assert(a == b->next);
assert(c == b->prev);
assert(b == c->next);
assert(NULL == c->prev);
list_destroy(list);
}
static void
test_list_at() {
// Setup
list_t *list = list_new();
list_node_t *a = list_node_new("a");
list_node_t *b = list_node_new("b");
list_node_t *c = list_node_new("c");
// a b c
list_rpush(list, a);
list_rpush(list, b);
list_rpush(list, c);
// Assertions
assert(a == list_at(list, 0));
assert(b == list_at(list, 1));
assert(c == list_at(list, 2));
assert(NULL == list_at(list, 3));
assert(c == list_at(list, -1));
assert(b == list_at(list, -2));
assert(a == list_at(list, -3));
assert(NULL == list_at(list, -4));
list_destroy(list);
}
static void
test_list_destroy() {
// Setup
list_t *a = list_new();
list_destroy(a);
// a b c
list_t *b = list_new();
list_rpush(b, list_node_new("a"));
list_rpush(b, list_node_new("b"));
list_rpush(b, list_node_new("c"));
list_destroy(b);
// Assertions
list_t *c = list_new();
c->free = freeProxy;
list_rpush(c, list_node_new(list_node_new("a")));
list_rpush(c, list_node_new(list_node_new("b")));
list_rpush(c, list_node_new(list_node_new("c")));
list_destroy(c);
assert(3 == freeProxyCalls);
freeProxyCalls=0;
}
static void
test_list_destroy_complexver() {
// Setup
list_t *a = list_new();
list_destroy(a);
// a b c
list_t *b = list_new();
list_rpush(b, list_node_new("a"));
list_rpush(b, list_node_new("b"));
list_rpush(b, list_node_new("c"));
list_destroy(b);
// Assertions
list_t *c = list_new();
c->free = freeProxy;
list_rpush(c, list_node_new(list_node_new("a")));
list_rpush(c, list_node_new(list_node_new("b")));
list_rpush(c, list_node_new(list_node_new("c")));
list_destroy(c);
assert(3 == freeProxyCalls);
freeProxyCalls=0;
list_t *d = list_new();
d->free = freeProxy;
list_rpush(d, list_node_new(list_node_new("a")));
list_rpush(d, list_node_new(list_node_new("b")));
list_rpush(d, list_node_new(list_node_new("c")));
list_destroy(d);
assert(3 == freeProxyCalls);
freeProxyCalls=0;
}
static void
test_list_empty_list_destroy() {
list_t *list = list_new();
list_destroy(list);
freeProxyCalls=0;
}
static void
test_list_find() {
// Setup
list_t *langs = list_new();
list_node_t *js = list_rpush(langs, list_node_new("js"));
list_node_t *ruby = list_rpush(langs, list_node_new("ruby"));
list_t *users = list_new();
users->match = User_equal;
User userTJ = { "tj" };
User userSimon = { "simon" };
User userTaylor = { "taylor" };
list_node_t *tj = list_rpush(users, list_node_new(&userTJ));
list_node_t *simon = list_rpush(users, list_node_new(&userSimon));
// Assertions
list_node_t *a = list_find(langs, "js");
list_node_t *b = list_find(langs, "ruby");
list_node_t *c = list_find(langs, "foo");
assert(js == a);
assert(ruby == b);
assert(NULL == c);
list_destroy(langs);
a = list_find(users, &userTJ);
b = list_find(users, &userSimon);
c = list_find(users, &userTaylor);
assert(tj == a);
assert(simon == b);
assert(NULL == c);
list_destroy(users);
}
static void
test_list_remove() {
// Setup
list_t *list = list_new();
list_node_t *a = list_rpush(list, list_node_new("a"));
list_node_t *b = list_rpush(list, list_node_new("b"));
list_node_t *c = list_rpush(list, list_node_new("c"));
// Assertions
assert(3 == list->len);
list_remove(list, b);
assert(2 == list->len);
assert(a == list->head);
assert(c == list->tail);
assert(c == a->next);
assert(NULL == a->prev);
assert(NULL == c->next);
assert(a == c->prev);
list_remove(list, a);
assert(1 == list->len);
assert(c == list->head);
assert(c == list->tail);
assert(NULL == c->next);
assert(NULL == c->prev);
list_remove(list, c);
assert(0 == list->len);
assert(NULL == list->head);
assert(NULL == list->tail);
list_destroy(list);
}
static void
test_list_rpop() {
// Setup
list_t *list = list_new();
list_node_t *a = list_rpush(list, list_node_new("a"));
list_node_t *b = list_rpush(list, list_node_new("b"));
list_node_t *c = list_rpush(list, list_node_new("c"));
// Assertions
assert(3 == list->len);
assert(c == list_rpop(list));
assert(2 == list->len);
assert(a == list->head);
assert(b == list->tail);
assert(a == b->prev);
assert(NULL == list->tail->next && "new tail node next is not NULL");
assert(NULL == c->prev && "detached node prev is not NULL");
assert(NULL == c->next && "detached node next is not NULL");
free(c);
assert(b == list_rpop(list));
assert(1 == list->len);
assert(a == list->head);
assert(a == list->tail);
free(b);
assert(a == list_rpop(list));
assert(0 == list->len);
assert(NULL == list->head);
assert(NULL == list->tail);
free(a);
assert(NULL == list_rpop(list));
assert(0 == list->len);
list_destroy(list);
}
static void
test_list_lpop() {
// Setup
list_t *list = list_new();
list_node_t *a = list_rpush(list, list_node_new("a"));
list_node_t *b = list_rpush(list, list_node_new("b"));
list_node_t *c = list_rpush(list, list_node_new("c"));
// Assertions
assert(3 == list->len);
assert(a == list_lpop(list));
assert(2 == list->len);
assert(b == list->head);
assert(NULL == list->head->prev && "new head node prev is not NULL");
assert(NULL == a->prev && "detached node prev is not NULL");
assert(NULL == a->next && "detached node next is not NULL");
free(a);
assert(b == list_lpop(list));
assert(1 == list->len);
free(b);
assert(c == list_lpop(list));
assert(0 == list->len);
assert(NULL == list->head);
assert(NULL == list->tail);
free(c);
assert(NULL == list_lpop(list));
assert(0 == list->len);
list_destroy(list);
}
static void
test_list_iterator_t() {
// Setup
list_t *list = list_new();
list_node_t *tj = list_node_new("tj");
list_node_t *taylor = list_node_new("taylor");
list_node_t *simon = list_node_new("simon");
// tj taylor simon
list_rpush(list, tj);
list_rpush(list, taylor);
list_rpush(list, simon);
// Assertions
// From head
list_iterator_t *it = list_iterator_new(list, LIST_HEAD);
list_node_t *a = list_iterator_next(it);
list_node_t *b = list_iterator_next(it);
list_node_t *c = list_iterator_next(it);
list_node_t *d = list_iterator_next(it);
assert(a == tj);
assert(b == taylor);
assert(c == simon);
assert(NULL == d);
list_iterator_destroy(it);
// From tail
it = list_iterator_new(list, LIST_TAIL);
list_node_t *a2 = list_iterator_next(it);
list_node_t *b2 = list_iterator_next(it);
list_node_t *c2 = list_iterator_next(it);
list_node_t *d2 = list_iterator_next(it);
assert(a2 == simon);
assert(b2 == taylor);
assert(c2 == tj);
assert(NULL == d2);
list_iterator_destroy(it);
list_destroy(list);
}
int
main(void){
printf("\nlist_t: %ld\n", sizeof(list_t));
printf("list_node_t: %ld\n", sizeof(list_node_t));
printf("list_iterator_t: %ld\n\n", sizeof(list_iterator_t));
test(list_node_new);
test(list_rpush);
test(list_lpush);
test(list_find);
test(list_at);
test(list_remove);
test(list_rpop);
test(list_lpop);
test(list_destroy);
test(list_empty_list_destroy)
test(list_destroy_complexver)
test(list_iterator_t);
puts("... 100%");
return 0;
}