submodule
This commit is contained in:
parent
6c6a5be4ed
commit
79a8c00636
13 changed files with 1352 additions and 1 deletions
1
src/list
1
src/list
|
@ -1 +0,0 @@
|
||||||
Subproject commit 23faa20d03b67d752e1f882f0832c941a942c75b
|
|
6
src/list/.gitignore
vendored
Normal file
6
src/list/.gitignore
vendored
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
.DS_Store
|
||||||
|
bin
|
||||||
|
.pomo
|
||||||
|
*.o
|
||||||
|
build
|
||||||
|
deps
|
74
src/list/History.md
Normal file
74
src/list/History.md
Normal 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
22
src/list/LICENSE
Normal 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
72
src/list/Makefile
Normal 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
185
src/list/Readme.md
Normal 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 <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.
|
146
src/list/benchmark.c.bak
Normal file
146
src/list/benchmark.c.bak
Normal 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
17
src/list/clib.json
Normal 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
215
src/list/src/list.c
Normal 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
130
src/list/src/list.h
Normal 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__ */
|
62
src/list/src/list_iterator.c
Normal file
62
src/list/src/list_iterator.c
Normal 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
23
src/list/src/list_node.c
Normal 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
400
src/list/test.c.bak
Normal 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;
|
||||||
|
}
|
Loading…
Reference in a new issue