From d94521db4cdcc0440f1dc56406c88fbb95acb371 Mon Sep 17 00:00:00 2001 From: Tobias Boege Date: Sat, 18 Aug 2012 11:07:14 +0000 Subject: [PATCH] [CONFIGURATION] * NEW: Add gb.adt component [GB.ADT] * NEW: gb.adt is a component to provide abstract datatypes. * NEW: Add List and ListRoot classes for circular double-linked lists which can be embedded into other classes or used standalone. * NEW: Add Deque class as a base for new Stack, Queue and PrioQueue classes on top of linked lists (thus different from related Variant[] semantics). * NEW: Add Circular class for ring buffers. git-svn-id: svn://localhost/gambas/trunk@5052 867c0c6c-44f3-4631-809d-bfa615b0a4ec --- configure.ac | 1 + gb.adt/AUTHORS | 0 gb.adt/COPYING | 1 + gb.adt/ChangeLog | 0 gb.adt/INSTALL | 1 + gb.adt/Makefile.am | 3 + gb.adt/NEWS | 0 gb.adt/README | 0 gb.adt/acinclude.m4 | 1 + gb.adt/component.am | 1 + gb.adt/configure.ac | 17 ++ gb.adt/depcomp | 1 + gb.adt/gambas.h | 1 + gb.adt/gb_common.h | 1 + gb.adt/m4 | 1 + gb.adt/missing | 1 + gb.adt/reconf | 1 + gb.adt/src/Makefile.am | 15 + gb.adt/src/c_circular.c | 307 ++++++++++++++++++++ gb.adt/src/c_circular.h | 33 +++ gb.adt/src/c_deque.c | 346 +++++++++++++++++++++++ gb.adt/src/c_deque.h | 37 +++ gb.adt/src/c_list.c | 548 ++++++++++++++++++++++++++++++++++++ gb.adt/src/c_list.h | 92 ++++++ gb.adt/src/gb.adt.component | 4 + gb.adt/src/main.c | 54 ++++ gb.adt/src/main.h | 11 + 27 files changed, 1478 insertions(+) create mode 100644 gb.adt/AUTHORS create mode 120000 gb.adt/COPYING create mode 100644 gb.adt/ChangeLog create mode 120000 gb.adt/INSTALL create mode 100644 gb.adt/Makefile.am create mode 100644 gb.adt/NEWS create mode 100644 gb.adt/README create mode 120000 gb.adt/acinclude.m4 create mode 120000 gb.adt/component.am create mode 100644 gb.adt/configure.ac create mode 120000 gb.adt/depcomp create mode 120000 gb.adt/gambas.h create mode 120000 gb.adt/gb_common.h create mode 120000 gb.adt/m4 create mode 120000 gb.adt/missing create mode 120000 gb.adt/reconf create mode 100644 gb.adt/src/Makefile.am create mode 100644 gb.adt/src/c_circular.c create mode 100644 gb.adt/src/c_circular.h create mode 100644 gb.adt/src/c_deque.c create mode 100644 gb.adt/src/c_deque.h create mode 100644 gb.adt/src/c_list.c create mode 100644 gb.adt/src/c_list.h create mode 100644 gb.adt/src/gb.adt.component create mode 100644 gb.adt/src/main.c create mode 100644 gb.adt/src/main.h diff --git a/configure.ac b/configure.ac index 0f099503e..cacea6784 100644 --- a/configure.ac +++ b/configure.ac @@ -39,6 +39,7 @@ GB_CONFIG_SUBDIRS(gsl, gb.gsl) GB_CONFIG_SUBDIRS(ncurses, gb.ncurses) GB_CONFIG_SUBDIRS(media, gb.media) GB_CONFIG_SUBDIRS(jit, gb.jit) +GB_CONFIG_SUBDIRS(adt, gb.adt) AC_CONFIG_SUBDIRS(comp) AC_CONFIG_SUBDIRS(app) diff --git a/gb.adt/AUTHORS b/gb.adt/AUTHORS new file mode 100644 index 000000000..e69de29bb diff --git a/gb.adt/COPYING b/gb.adt/COPYING new file mode 120000 index 000000000..012065c85 --- /dev/null +++ b/gb.adt/COPYING @@ -0,0 +1 @@ +../COPYING \ No newline at end of file diff --git a/gb.adt/ChangeLog b/gb.adt/ChangeLog new file mode 100644 index 000000000..e69de29bb diff --git a/gb.adt/INSTALL b/gb.adt/INSTALL new file mode 120000 index 000000000..99d491b4f --- /dev/null +++ b/gb.adt/INSTALL @@ -0,0 +1 @@ +../INSTALL \ No newline at end of file diff --git a/gb.adt/Makefile.am b/gb.adt/Makefile.am new file mode 100644 index 000000000..07d95de31 --- /dev/null +++ b/gb.adt/Makefile.am @@ -0,0 +1,3 @@ +ACLOCAL_AMFLAGS = -I m4 --install +SUBDIRS = @ADT_DIR@ +EXTRA_DIST = reconf spec gambas.h gb*.h diff --git a/gb.adt/NEWS b/gb.adt/NEWS new file mode 100644 index 000000000..e69de29bb diff --git a/gb.adt/README b/gb.adt/README new file mode 100644 index 000000000..e69de29bb diff --git a/gb.adt/acinclude.m4 b/gb.adt/acinclude.m4 new file mode 120000 index 000000000..d84c32a31 --- /dev/null +++ b/gb.adt/acinclude.m4 @@ -0,0 +1 @@ +../acinclude.m4 \ No newline at end of file diff --git a/gb.adt/component.am b/gb.adt/component.am new file mode 120000 index 000000000..2f0eee34f --- /dev/null +++ b/gb.adt/component.am @@ -0,0 +1 @@ +../component.am \ No newline at end of file diff --git a/gb.adt/configure.ac b/gb.adt/configure.ac new file mode 100644 index 000000000..6b009aa29 --- /dev/null +++ b/gb.adt/configure.ac @@ -0,0 +1,17 @@ +dnl ---- configure.ac for gb.adt + +AC_INIT(configure.ac) +AC_CONFIG_MACRO_DIR([m4]) +GB_INIT(gb.adt) +AC_PROG_LIBTOOL + +GB_COMPONENT( + adt, ADT, gb.adt, [src], +) + +AC_OUTPUT( \ +Makefile \ +src/Makefile \ +) + +GB_PRINT_MESSAGES diff --git a/gb.adt/depcomp b/gb.adt/depcomp new file mode 120000 index 000000000..7ef7de62b --- /dev/null +++ b/gb.adt/depcomp @@ -0,0 +1 @@ +../depcomp \ No newline at end of file diff --git a/gb.adt/gambas.h b/gb.adt/gambas.h new file mode 120000 index 000000000..03677ecd0 --- /dev/null +++ b/gb.adt/gambas.h @@ -0,0 +1 @@ +../main/share/gambas.h \ No newline at end of file diff --git a/gb.adt/gb_common.h b/gb.adt/gb_common.h new file mode 120000 index 000000000..707d79da6 --- /dev/null +++ b/gb.adt/gb_common.h @@ -0,0 +1 @@ +../main/share/gb_common.h \ No newline at end of file diff --git a/gb.adt/m4 b/gb.adt/m4 new file mode 120000 index 000000000..7d49a2a4b --- /dev/null +++ b/gb.adt/m4 @@ -0,0 +1 @@ +../m4 \ No newline at end of file diff --git a/gb.adt/missing b/gb.adt/missing new file mode 120000 index 000000000..f3ade9ba1 --- /dev/null +++ b/gb.adt/missing @@ -0,0 +1 @@ +../missing \ No newline at end of file diff --git a/gb.adt/reconf b/gb.adt/reconf new file mode 120000 index 000000000..48a376da6 --- /dev/null +++ b/gb.adt/reconf @@ -0,0 +1 @@ +../reconf \ No newline at end of file diff --git a/gb.adt/src/Makefile.am b/gb.adt/src/Makefile.am new file mode 100644 index 000000000..5a1178582 --- /dev/null +++ b/gb.adt/src/Makefile.am @@ -0,0 +1,15 @@ +COMPONENT = gb.adt +include $(top_srcdir)/component.am + +gblib_LTLIBRARIES = gb.adt.la + +gb_adt_la_LIBADD = @ADT_LIB@ +gb_adt_la_LDFLAGS = -module @LD_FLAGS@ @ADT_LDFLAGS@ +gb_adt_la_CPPFLAGS = @ADT_INC@ + +gb_adt_la_SOURCES = \ + main.h main.c \ + c_list.h c_list.c \ + c_deque.h c_deque.c \ + c_circular.h c_circular.c + diff --git a/gb.adt/src/c_circular.c b/gb.adt/src/c_circular.c new file mode 100644 index 000000000..8314bf145 --- /dev/null +++ b/gb.adt/src/c_circular.c @@ -0,0 +1,307 @@ +/* + * c_circular.c - Circular/Ring buffer type + * + * Copyright (C) 2012 Tobias Boege + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#define __C_CIRCULAR_C + +#include "../gambas.h" +#include "c_circular.h" + +typedef struct { + GB_BASE ob; + GB_VARIANT_VALUE *elements; + size_t size; /* Mirror of the array's size to speed things up */ + int reader; + int writer; + int overwrite; + int empty : 1; + int full : 1; +} CCIRCULAR; + +static int CCIRCULAR_size(CCIRCULAR *circ) +{ + return circ->size; +} + +static int CCIRCULAR_is_empty(CCIRCULAR *circ) +{ + return circ->empty; +} + +static int CCIRCULAR_is_full(CCIRCULAR *circ) +{ + return circ->full; +} + +/* + * All movements go forward. This means that moving the writer could never + * induce an 'empty' state and conversely moving the reader could never make + * the circular 'full'. + */ + +static void CCIRCULAR_move_index(CCIRCULAR *circ, int *idx, int pos) +{ + size_t size = CCIRCULAR_size(circ); + + if (pos >= size) + pos %= size; + *idx = pos; + /* Set empty/full flags */ + if (circ->reader == circ->writer) { + /* But only if we really operated on the given @circ */ + if (idx == &circ->reader) + circ->empty = 1; + else if (idx == &circ->writer) + circ->full = 1; + } else { + circ->empty = circ->full = 0; + } +} + +static void CCIRCULAR_inc_index(CCIRCULAR *circ, int *idx) +{ + CCIRCULAR_move_index(circ, idx, *idx + 1); +} + +static void CCIRCULAR_reset(CCIRCULAR *circ) +{ + circ->reader = circ->writer = 0; + circ->empty = 1; + if (!circ->size) + circ->full = 1; + else + circ->full = 0; +} + +static void CCIRCULAR_init(CCIRCULAR *circ, size_t size, int overwrite) +{ + circ->size = size; + GB.NewArray(&circ->elements, sizeof(GB_VARIANT_VALUE), circ->size); + CCIRCULAR_reset(circ); + circ->overwrite = overwrite; +} + +static void CCIRCULAR_destroy(CCIRCULAR *circ) +{ + GB.FreeArray((void *) &circ->elements); +} + +#define THIS ((CCIRCULAR *) _object) + +BEGIN_METHOD(Circular_new, GB_INTEGER size; GB_BOOLEAN overwrite) + + CCIRCULAR_init(THIS, VARG(size), VARGOPT(overwrite, 1)); + +END_METHOD + +static GB_VARIANT_VALUE *CCIRCULAR_read(CCIRCULAR *circ) +{ + GB_VARIANT_VALUE *var; + + if (CCIRCULAR_is_empty(circ)) + return NULL; + var = &circ->elements[circ->reader]; + CCIRCULAR_inc_index(circ, &circ->reader); + return var; +} + +static void CCIRCULAR_read_and_free_all(CCIRCULAR *circ) +{ + GB_VARIANT_VALUE *var; + + while (!CCIRCULAR_is_empty(circ)) { + var = CCIRCULAR_read(circ); + GB.StoreVariant(NULL, var); + } + CCIRCULAR_reset(circ); +} + +BEGIN_METHOD_VOID(Circular_free) + + CCIRCULAR_read_and_free_all(THIS); + CCIRCULAR_destroy(THIS); + +END_METHOD + +static void CCIRCULAR_write(CCIRCULAR *circ, GB_VARIANT *variant) +{ + if (CCIRCULAR_is_full(circ)) { + if (circ->overwrite) /* Consume oldest value and continue */ + CCIRCULAR_read(circ); + else /* Do nothing */ + return; + } + GB.StoreVariant(variant, &circ->elements[circ->writer]); + CCIRCULAR_inc_index(circ, &circ->writer); +} + +BEGIN_METHOD(Circular_Write, GB_VARIANT value) + + CCIRCULAR_write(THIS, ARG(value)); + +END_METHOD + +BEGIN_METHOD_VOID(Circular_Read) + + if (CCIRCULAR_is_empty(THIS)) { + GB.ReturnNull(); + GB.ReturnConvVariant(); + return; + } + GB.ReturnVariant(CCIRCULAR_read(THIS)); + +END_METHOD + +BEGIN_METHOD_VOID(Circular_Peek) + + if (CCIRCULAR_is_empty(THIS)) { + GB.ReturnNull(); + GB.ReturnConvVariant(); + return; + } + GB.ReturnVariant(&THIS->elements[THIS->reader]); + +END_METHOD + +static void CCIRCULAR_resize(CCIRCULAR *circ, size_t new) +{ + size_t old = CCIRCULAR_size(circ); + + if (old == new) + return; + if (old < new) { + GB_VARIANT_VALUE *buf; + int i; + + buf = GB.Insert(&circ->elements, old, new - old); + for (i = 0; old < new; old++, i++) + buf[i].type = GB_T_NULL; + } else { + int i; + + for (i = new; i < old; i++) + GB.StoreVariant(NULL, &circ->elements[i]); + GB.Remove(&circ->elements, new, old - new); + /* Move the indices accordingly */ + if (circ->reader > new) + circ->reader = new; + if (circ->writer > new) + circ->writer = new; + /* 0-length circular? */ + if (!new) { + circ->empty = circ->full = 1; + } + } + circ->size = new; +} + +BEGIN_METHOD(Circular_Resize, GB_INTEGER size) + + CCIRCULAR_resize(THIS, VARG(size)); + +END_METHOD + +BEGIN_METHOD_VOID(Circular_Clear) + + CCIRCULAR_read_and_free_all(THIS); + +END_METHOD + +BEGIN_METHOD_VOID(Circular_Reset) + + CCIRCULAR_reset(THIS); + +END_METHOD + +BEGIN_PROPERTY(Circular_IsEmpty) + + GB.ReturnBoolean(CCIRCULAR_is_empty(THIS)); + +END_PROPERTY + +BEGIN_PROPERTY(Circular_IsFull) + + GB.ReturnBoolean(CCIRCULAR_is_full(THIS)); + +END_PROPERTY + +BEGIN_PROPERTY(Circular_Reader) + + if (READ_PROPERTY) { + GB.ReturnInteger(THIS->reader); + return; + } + CCIRCULAR_move_index(THIS, &THIS->reader, VPROP(GB_INTEGER)); + +END_PROPERTY + +BEGIN_PROPERTY(Circular_Writer) + + if (READ_PROPERTY) { + GB.ReturnInteger(THIS->writer); + return; + } + CCIRCULAR_move_index(THIS, &THIS->writer, VPROP(GB_INTEGER)); + +END_PROPERTY + +BEGIN_PROPERTY(Circular_Size) + + if (READ_PROPERTY) { + GB.ReturnInteger(CCIRCULAR_size(THIS)); + return; + } + CCIRCULAR_resize(THIS, VPROP(GB_INTEGER)); + +END_PROPERTY + +BEGIN_PROPERTY(Circular_Overwrite) + + if (READ_PROPERTY) { + GB.ReturnBoolean(THIS->overwrite); + return; + } + THIS->overwrite = VPROP(GB_BOOLEAN); + +END_PROPERTY + +GB_DESC CCircularDesc[] = { + GB_DECLARE("Circular", sizeof(CCIRCULAR)), + + GB_METHOD("_new", NULL, Circular_new, "(Size)i[(Overwrite)b]"), + GB_METHOD("_free", NULL, Circular_free, NULL), + + GB_METHOD("Write", NULL, Circular_Write, "(Value)v"), + GB_METHOD("Read", "v", Circular_Read, NULL), + GB_METHOD("Peek", "v", Circular_Peek, NULL), + + GB_METHOD("Resize", NULL, Circular_Resize, "(Size)i"), + GB_METHOD("Clear", NULL, Circular_Clear, NULL), + GB_METHOD("Reset", NULL, Circular_Reset, NULL), + + GB_PROPERTY_READ("IsEmpty", "b", Circular_IsEmpty), + GB_PROPERTY_READ("IsFull", "b", Circular_IsFull), + GB_PROPERTY("Reader", "i", Circular_Reader), + GB_PROPERTY("Writer", "i", Circular_Writer), + GB_PROPERTY("Size", "i", Circular_Size), + GB_PROPERTY("Overwrite", "b", Circular_Overwrite), + + GB_END_DECLARE +}; diff --git a/gb.adt/src/c_circular.h b/gb.adt/src/c_circular.h new file mode 100644 index 000000000..fb5ba804c --- /dev/null +++ b/gb.adt/src/c_circular.h @@ -0,0 +1,33 @@ +/* + * c_circular.h + * + * Copyright (C) 2012 Tobias Boege + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#ifndef __C_CIRCULAR_H +#define __C_CIRCULAR_H + +#include "../gambas.h" + +extern GB_INTERFACE GB; + +#ifndef __C_CIRCULAR_C +extern GB_DESC CCircularDesc[]; +#endif + +#endif /* !__C_CIRCULAR_H */ diff --git a/gb.adt/src/c_deque.c b/gb.adt/src/c_deque.c new file mode 100644 index 000000000..738b2094a --- /dev/null +++ b/gb.adt/src/c_deque.c @@ -0,0 +1,346 @@ +/* + * c_deque.c - Deque, FILO and FIFO types + * + * Copyright (C) 2012 Tobias Boege + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#define __C_DEQUE_C + +#include "../gambas.h" +#include "c_list.h" +#include "c_deque.h" + +typedef struct { + GB_VARIANT_VALUE var; + CLIST *list; +} CDEQUE_ELEM; + +static CDEQUE_ELEM *CDEQUE_new_elem(GB_VARIANT *variant) +{ + CDEQUE_ELEM *new; + + GB.Alloc((void **) &new, sizeof(*new)); + new->var.type = GB_T_NULL; + new->list = List.New(new); + GB.StoreVariant(variant, &new->var); + return new; +} + +static void CDEQUE_real_destroy_elem(CDEQUE_ELEM *elem) +{ + GB.StoreVariant(NULL, &elem->var); + List.Destroy(elem->list); + GB.Free((void **) &elem); +} + +static void CDEQUE_destroy_elem(CDEQUE_ELEM *elem) +{ + List.Unlink(elem->list); + /* FIXME: This is a 'horrible hack' */ + GB.Post(CDEQUE_real_destroy_elem, (intptr_t) elem); +} + +typedef struct { + GB_BASE ob; + CLIST *elements; +} CDEQUE; + +static int CDEQUE_is_empty(CDEQUE *dq) +{ + return List.IsEmpty(dq->elements); +} + +static void CDEQUE_init(CDEQUE *dq) +{ + dq->elements = List.NewRoot(); +} + +#define THIS ((CDEQUE *) _object) + +BEGIN_METHOD_VOID(Deque_new) + + CDEQUE_init(THIS); + +END_METHOD + +static CDEQUE_ELEM *CDEQUE_pop_front(CDEQUE *dq) +{ + CDEQUE_ELEM *elem; + + if (CDEQUE_is_empty(dq)) + return NULL; + elem = dq->elements->next->data; + CDEQUE_destroy_elem(elem); + return elem; +} + +static void CDEQUE_pop_and_free_all(CDEQUE *dq) +{ + while (!CDEQUE_is_empty(dq)) + CDEQUE_pop_front(dq); +} + +BEGIN_METHOD_VOID(Deque_free) + + CDEQUE_pop_and_free_all(THIS); + List.DestroyRoot(THIS->elements); + +END_METHOD + +static void CDEQUE_push_front(CDEQUE *dq, CDEQUE_ELEM *elem) +{ + List.AddAfter(dq->elements, elem->list); +} + +BEGIN_METHOD(Deque_PushFront, GB_VARIANT value) + + CDEQUE_ELEM *elem; + + elem = CDEQUE_new_elem(ARG(value)); + CDEQUE_push_front(THIS, elem); + +END_METHOD + +static void CDEQUE_push_back(CDEQUE *dq, CDEQUE_ELEM *elem) +{ + List.AddBefore(dq->elements, elem->list); +} + +BEGIN_METHOD(Deque_PushBack, GB_VARIANT value) + + CDEQUE_ELEM *elem; + + elem = CDEQUE_new_elem(ARG(value)); + CDEQUE_push_back(THIS, elem); + +END_METHOD + +BEGIN_METHOD_VOID(Deque_PopFront) + + CDEQUE_ELEM *elem; + + if (CDEQUE_is_empty(THIS)) { + GB.ReturnNull(); + GB.ReturnConvVariant(); + return; + } + elem = CDEQUE_pop_front(THIS); + GB.ReturnVariant(&elem->var); + +END_METHOD + +static CDEQUE_ELEM *CDEQUE_pop_back(CDEQUE *dq) +{ + CDEQUE_ELEM *elem; + + if (CDEQUE_is_empty(dq)) + return NULL; + elem = dq->elements->prev->data; + CDEQUE_destroy_elem(elem); + return elem; +} + +BEGIN_METHOD_VOID(Deque_PopBack) + + CDEQUE_ELEM *elem; + + if (CDEQUE_is_empty(THIS)) { + GB.ReturnNull(); + GB.ReturnConvVariant(); + return; + } + elem = CDEQUE_pop_back(THIS); + GB.ReturnVariant(&elem->var); + +END_METHOD + +BEGIN_METHOD_VOID(Deque_PeekFront) + + CDEQUE_ELEM *elem; + + if (CDEQUE_is_empty(THIS)) { + GB.ReturnNull(); + GB.ReturnConvVariant(); + } else { + elem = (CDEQUE_ELEM *) THIS->elements->next->data; + GB.ReturnVariant(&elem->var); + } + +END_METHOD + +BEGIN_METHOD_VOID(Deque_PeekBack) + + CDEQUE_ELEM *elem; + + if (CDEQUE_is_empty(THIS)) { + GB.ReturnNull(); + GB.ReturnConvVariant(); + } else { + elem = (CDEQUE_ELEM *) THIS->elements->prev->data; + GB.ReturnVariant(&elem->var); + } + +END_METHOD + +BEGIN_METHOD_VOID(Deque_Clear) + + CDEQUE_pop_and_free_all(THIS); + +END_METHOD + +BEGIN_PROPERTY(Deque_IsEmpty) + + GB.ReturnBoolean(CDEQUE_is_empty(THIS)); + +END_PROPERTY + +BEGIN_PROPERTY(Deque_Size) + + size_t size; + CLIST *node; + + size = 0; + clist_for_each(node, THIS->elements) + size++; + GB.ReturnInteger(size); + +END_PROPERTY + +/* + * Double-ended queue + */ + +GB_DESC CDequeDesc[] = { + GB_DECLARE("Deque", sizeof(CDEQUE)), + + GB_METHOD("_new", NULL, Deque_new, NULL), + GB_METHOD("_free", NULL, Deque_free, NULL), + + GB_METHOD("PushFront", NULL, Deque_PushFront, "(Value)v"), + GB_METHOD("PushBack", NULL, Deque_PushBack, "(Value)v"), + GB_METHOD("PopFront", "v", Deque_PopFront, NULL), + GB_METHOD("PopBack", "v", Deque_PopBack, NULL), + GB_METHOD("PeekFront", "v", Deque_PeekFront, NULL), + GB_METHOD("PeekBack", "v", Deque_PeekBack, NULL), + + GB_METHOD("Clear", NULL, Deque_Clear, NULL), + + GB_PROPERTY_READ("IsEmpty", "b", Deque_IsEmpty), + GB_PROPERTY_READ("Size", "i", Deque_Size), + + GB_END_DECLARE +}; + +/* + * FILO + */ + +GB_DESC CStackDesc[] = { + GB_DECLARE("Stack", sizeof(CDEQUE)), + + GB_METHOD("_new", NULL, Deque_new, NULL), + GB_METHOD("_free", NULL, Deque_free, NULL), + + GB_METHOD("Push", NULL, Deque_PushBack, "(Value)v"), + GB_METHOD("Pop", "v", Deque_PopBack, NULL), + GB_METHOD("Peek", "v", Deque_PeekBack, NULL), + + GB_METHOD("Clear", NULL, Deque_Clear, NULL), + + GB_PROPERTY_READ("IsEmpty", "b", Deque_IsEmpty), + GB_PROPERTY_READ("Size", "i", Deque_Size), + + GB_END_DECLARE +}; + +/* + * FIFO + */ + +GB_DESC CQueueDesc[] = { + GB_DECLARE("Queue", sizeof(CDEQUE)), + + GB_METHOD("_new", NULL, Deque_new, NULL), + GB_METHOD("_free", NULL, Deque_free, NULL), + + GB_METHOD("Enqueue", NULL, Deque_PushBack, "(Value)v"), + GB_METHOD("Enq", NULL, Deque_PushBack, "(Value)v"), + GB_METHOD("Dequeue", "v", Deque_PopFront, NULL), + GB_METHOD("Deq", "v", Deque_PopFront, NULL), + GB_METHOD("Peek", "v", Deque_PeekFront, NULL), + + GB_METHOD("Clear", NULL, Deque_Clear, NULL), + + GB_PROPERTY_READ("IsEmpty", "b", Deque_IsEmpty), + GB_PROPERTY_READ("Size", "i", Deque_Size), + + GB_END_DECLARE +}; + +/* + * We keep the Priority queue sorted by a special Enqueue() function. + * The higher the priority, the closer to the beginning the value will be + * enqueued. For equal priorities, the later added element will be enqueued + * at a higher index. + */ + +static void CPRIOQ_enqueue(CDEQUE *dq, CDEQUE_ELEM *elem, int prio) +{ + CLIST *next; + + /* Just find the right node to prepend the new value to */ + clist_for_each(next, dq->elements) + /* We use CLIST's uptr for the prio */ + if (prio > (int) next->uptr) + break; + elem->list->uptr = prio; + List.AddBefore(next, elem->list); +} + +BEGIN_METHOD(PrioQueue_Enqueue, GB_VARIANT value; GB_INTEGER prio) + + CDEQUE_ELEM *elem; + + elem = CDEQUE_new_elem(ARG(value)); + CPRIOQ_enqueue(THIS, elem, VARG(prio)); + +END_METHOD + +/* + * Priority FIFO + */ + +GB_DESC CPrioQueueDesc[] = { + GB_DECLARE("PrioQueue", sizeof(CDEQUE)), + + GB_METHOD("_new", NULL, Deque_new, NULL), + GB_METHOD("_free", NULL, Deque_free, NULL), + + GB_METHOD("Enqueue", NULL, PrioQueue_Enqueue, "(Value)v(Prio)i"), + GB_METHOD("Enq", NULL, PrioQueue_Enqueue, "(Value)v(Prio)i"), + GB_METHOD("Dequeue", "v", Deque_PopFront, NULL), + GB_METHOD("Deq", "v", Deque_PopFront, NULL), + GB_METHOD("Peek", "v", Deque_PeekFront, NULL), + + GB_METHOD("Clear", NULL, Deque_Clear, NULL), + + GB_PROPERTY_READ("IsEmpty", "b", Deque_IsEmpty), + GB_PROPERTY_READ("Size", "i", Deque_Size), + + GB_END_DECLARE +}; diff --git a/gb.adt/src/c_deque.h b/gb.adt/src/c_deque.h new file mode 100644 index 000000000..6cd4ff6bd --- /dev/null +++ b/gb.adt/src/c_deque.h @@ -0,0 +1,37 @@ +/* + * c_deque.h + * + * Copyright (C) 2012 Tobias Boege + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#ifndef __C_DEQUE_H +#define __C_DEQUE_H + +#include "../gambas.h" + +extern GB_INTERFACE GB; + +#ifndef __C_DEQUE_C +extern GB_DESC CDequeDesc[]; +extern GB_DESC CStackDesc[]; +extern GB_DESC CQueueDesc[]; +extern GB_DESC CPrioQueueDesc[]; +#endif + +#endif /* !__C_DEQUE_H */ + diff --git a/gb.adt/src/c_list.c b/gb.adt/src/c_list.c new file mode 100644 index 000000000..204b9248d --- /dev/null +++ b/gb.adt/src/c_list.c @@ -0,0 +1,548 @@ +/* + * c_list.c - (Embedded) circular double-linked lists + * + * Copyright (C) 2012 Tobias Boege + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#define __C_LIST_C + +#include "../gambas.h" +#include "c_list.h" + +static DECLARE_CLIST_ROOT(free_nodes); + +/* Component unload. Free all re-use nodes */ +void CLIST_exit(void) +{ + CLIST *node, *next; + + clist_for_each_safe(node, &free_nodes, next) + GB.Free((void **) &node); +} + +static int CLIST_is_root(CLIST *list) +{ + /* Root nodes have their data member point to their structure. This + * means that they carry no information and that is pointless for + * real nodes. */ + return list->data == list; +} + +static int CLIST_is_empty(CLIST *list) +{ + return list->next == list; +} + +static int CLIST_is_linked(CLIST *node) +{ + return node->has_link_ref; +} + +static void CLIST_init(CLIST *node, void *data) +{ + node->prev = node->next = node; + node->data = data; +} + +/* Forward */ +static CLIST *CLIST_extract(CLIST *, int); +static void CLIST_add_after(CLIST *, CLIST *); +static void CLIST_unlink(CLIST *); + +static CLIST *CLIST_new(void *data) +{ + CLIST *new; + + /* Try to get a recycled node first */ + if (!CLIST_is_empty(&free_nodes)) + new = CLIST_extract(free_nodes.next, 1); + else + GB.Alloc((void **) &new, sizeof(*new)); + CLIST_init(new, data); + return new; +} + +static void *CLIST_destroy(CLIST *node) +{ + void *data = node->data; + + /* Recycle */ + CLIST_unlink(node); + CLIST_add_after(&free_nodes, node); + return data; +} + +static void CLIST_init_root(CLIST *node) +{ + node->prev = node->next = node->data = node; +} + +static CLIST *CLIST_new_root(void) +{ + CLIST *new; + + new = CLIST_new(NULL); + CLIST_init_root(new); + return new; +} + +static void CLIST_destroy_root(CLIST *node) +{ + CLIST_destroy(node); +} + +#define THIS ((CLIST *) _object) + +BEGIN_METHOD(List_new, GB_OBJECT obj; /* Usually 'Me' from container obj */ + GB_BOOLEAN embedded) /* obj is container of THIS? */ + + int embedded = VARGOPT(embedded, 0); + + CLIST_init(THIS, VARG(obj)); + THIS->embedded = embedded; + THIS->has_link_ref = 0; + /* If the list embedded, we must not reference the container as that + * would cause not-so-easy to resolve circular references and thus + * memory errors. */ + if (!embedded) + GB.Ref(THIS->data); + +END_METHOD + +BEGIN_METHOD_VOID(List_free) + + if (!THIS->embedded) + GB.Unref(&THIS->data); + +END_METHOD + +static CLIST *CLIST_next_node(CLIST *node) +{ + CLIST *next; + + if (CLIST_is_empty(node)) + return NULL; + + next = node->next; + /* Erroneously more root nodes in the list? It should not be + * possible but catch it with that loop nevertheless. */ + while (CLIST_is_root(next)) { + next = next->next; + if (next == node) + return NULL; + } + return next; +} + +/* I prefer storing a pointer to this struct in GB.GetEnum() */ +struct enum_state { + CLIST *first, *next; /* Be able to Unlink() in For Each */ +}; + +/* + * We can either enumerate a list of embedded list nodes which have no root + * node or a list containing a root node which is then skipped. + * In both cases, we can enter the enumeration at any node in the list and + * all nodes in the list are enumerated. + */ + +BEGIN_METHOD_VOID(List_next) + + struct enum_state **statep = GB.GetEnum(), *state; + CLIST *cur; + + state = *statep; + if (!state) { /* Beginning */ + GB.Alloc((void **) statep, sizeof(*state)); + state = *statep; + /* Catch the 'root' case and skip the node */ + if (CLIST_is_root(THIS)) + cur = CLIST_next_node(THIS); + else + cur = THIS; + if (!cur) + goto stop_enum; + state->first = cur; + goto done; + } + + cur = state->next; + if (!cur || cur == state->first) + goto stop_enum; + +done: + state->next = CLIST_next_node(cur); + GB.ReturnObject(cur->data); + return; + +stop_enum: + GB.Free((void **) statep); + GB.StopEnum(); + return; + +END_METHOD + +/* + * There are no particular 'nodes' when adding because each node is a fully + * capable list itself. When we pass a @new node, we always add the entire + * list it is currently linked to. In particular this is a yet unlinked list + * containing only one node in most cases but it is possible to create + * sub-lists individually and add some sub-lists to a global root later. + */ + +static void CLIST_add_before(CLIST *list, CLIST *new) +{ + CLIST *new_end = new->prev; + + list->prev->next = new; + new->prev = list->prev; + new_end->next = list; + list->prev = new_end; +} + +static void CLIST_add_after(CLIST *list, CLIST *new) +{ + CLIST *new_end = new->prev; + + new_end->next = list->next; + list->next->prev = new_end; + new->prev = list; + list->next = new; +} + +static void CLIST_ref_once(CLIST *node) +{ + if (!CLIST_is_linked(node)) { + node->has_link_ref = 1; + /* ListRoots do not receive ref. This makes almost automatic + * cleanup possible. The list may be fully linked but when + * the root loses its last ref, the list is cleared. */ + if (CLIST_is_root(node)) + return; + GB.Ref(node); + /* It is time now, at the latest, to Ref() the object of an + * embedded node because all other refs could get lost */ + if (node->embedded) + GB.Ref(node->data); + } +} + +static void CLIST_unref_once(CLIST **node) +{ + if (CLIST_is_linked(*node)) { + (*node)->has_link_ref = 0; + if (CLIST_is_root(*node)) + return; + /* Take the ref off from data of embedded node again */ + if ((*node)->embedded) + GB.Unref(&(*node)->data); + GB.Unref((void **) node); + } +} + +enum { + CLIST_BEFORE, + CLIST_AFTER +}; + +static void CLIST_add_and_ref(CLIST *node, CLIST *new, int mode) +{ + if (mode == CLIST_BEFORE) + CLIST_add_before(node, new); + else /* This function is save from passing invalid modes */ + CLIST_add_after(node, new); + /* Each node gets Ref()'d once when in a list. */ + CLIST_ref_once(node); + CLIST_ref_once(new); +} + +/* @node and @buf should be variables */ +#define CHECK_ADD_ROOT(node, new, buf) \ + do { \ + CLIST *_new = (new); \ + clist_for_each_first((node), _new, (buf)) { \ + if (CLIST_is_root((node))) { \ + GB.Error("Attempt to Add a root node."); \ + return; \ + } \ + } \ + } while (0) + +BEGIN_METHOD(List_AddPrev, GB_OBJECT new) + + CLIST *new = (CLIST *) VARG(new), *node; + int buf; + + CHECK_ADD_ROOT(node, new, buf); + CLIST_add_and_ref(THIS, new, CLIST_BEFORE); + +END_METHOD + +BEGIN_METHOD(List_AddNext, GB_OBJECT new) + + CLIST *new = (CLIST *) VARG(new), *node; + int buf; + + CHECK_ADD_ROOT(node, new, buf); + CLIST_add_and_ref(THIS, new, CLIST_AFTER); + +END_METHOD + +/* + * This operates on the exact node. + */ + +static void CLIST_unlink(CLIST *node) +{ + node->prev->next = node->next; + node->next->prev = node->prev; + /* Link to itself again to form a valid empty list */ + node->prev = node->next = node; +} + +static void CLIST_unlink_and_unref(CLIST *node) +{ + CLIST *list; + + /* list is only meaningful if the list gets empty after this + * Unlink() so it doesn't matter if THIS->prev or THIS->next + * is used. */ + list = node->prev; + CLIST_unlink(node); + CLIST_unref_once(&node); + + if (CLIST_is_empty(list)) + CLIST_unref_once(&list); +} + +#define CHECK_NOT_LINKED(node) \ + do { \ + if (!CLIST_is_linked(node)) { \ + GB.Error("List node not linked"); \ + return; \ + } \ + } while (0) + +BEGIN_METHOD_VOID(List_Unlink) + + CHECK_NOT_LINKED(THIS); + CLIST_unlink_and_unref(THIS); + +END_METHOD + +/* + * Extract a sub-list from a list. The @start gets returned if successful. + */ + +static CLIST *CLIST_extract(CLIST *start, int count) +{ + int i = count, buf; + CLIST *last; + + if (!count) + return NULL; + + clist_for_each_first(last, start, buf) { + if (!--i) + break; + } + /* Too few nodes in the entire list? */ + if (i) + return NULL; + + /* Unlink new list */ + start->prev->next = last->next; + last->next->prev = start->prev; + /* Relink new list circularly to itself */ + start->prev = last; + last->next = start; + return start; +} + +BEGIN_METHOD(List_Extract, GB_INTEGER count) + + int count = VARG(count); + CLIST *node; + CLIST *start; + + if (!count) { + GB.Error(GB_ERR_ARG); + return; + } + + CHECK_NOT_LINKED(THIS); + + if (count == 1) { /* Is actually Unlink()? */ + GB.ReturnObject(THIS); /* Prevent from vanish */ + CLIST_unlink_and_unref(THIS); + } else { /* Real Extract() */ + node = THIS->prev; + start = CLIST_extract(THIS, count); + if (!start) { + GB.Error(GB_ERR_BOUND); + return; + } + GB.ReturnObject(start); + /* Made old list empty? */ + if (CLIST_is_empty(node)) + CLIST_unref_once(&node); + } + +END_METHOD + +static void CLIST_unlink_and_unref_all(CLIST *list) +{ + if (!CLIST_is_linked(list)) + return; + + while (!CLIST_is_empty(list)) + CLIST_unlink_and_unref(list->next); + /* We get automatically Unref()'d by CLIST_unlink_and_unref() */ +} + +BEGIN_METHOD_VOID(List_Clear) + + /* + * This must be called to prevent circular references at program + * termination. It is tricky to avoid circular references on + * circular linked lists. Therefore, alas, this function must be + * called explicitly or all containing nodes must be removed another + * way (see ListRoot_free). + */ + CLIST_unlink_and_unref_all(THIS); + +END_METHOD + +BEGIN_PROPERTY(List_Next) + + GB.ReturnObject(THIS->next); + +END_PROPERTY + +BEGIN_PROPERTY(List_Previous) + + GB.ReturnObject(THIS->prev); + +END_PROPERTY + +BEGIN_PROPERTY(List_IsLinked) + + GB.ReturnBoolean(CLIST_is_linked(THIS)); + +END_PROPERTY + +BEGIN_PROPERTY(List_IsEmbedded) + + GB.ReturnBoolean(THIS->embedded); + +END_PROPERTY + +BEGIN_PROPERTY(List_Data) + + if (READ_PROPERTY) { + GB.ReturnObject(THIS->data); + return; + } + if (THIS->embedded) { + GB.Error("Attempt to change Data on embedded node"); + return; + } + GB.Unref((void **) &THIS->data); + THIS->data = VPROP(GB_OBJECT); + GB.Ref(THIS->data); + +END_PROPERTY + +GB_DESC CListDesc[] = { + GB_DECLARE("List", sizeof(CLIST)), + + GB_CONSTANT("Embedded", "b", 1), + + GB_METHOD("_new", NULL, List_new, "(Obj)o[(Embedded)b]"), + GB_METHOD("_free", NULL, List_free, NULL), + GB_METHOD("_next", "o", List_next, NULL), + + GB_METHOD("AddPrev", NULL, List_AddPrev, "(Node)List;"), + GB_METHOD("AddNext", NULL, List_AddNext, "(Node)List;"), + GB_METHOD("Unlink", NULL, List_Unlink, NULL), + GB_METHOD("Extract", "List", List_Extract, "(Count)i"), + GB_METHOD("Clear", NULL, List_Clear, NULL), + + GB_PROPERTY_READ("Next", "List", List_Next), + GB_PROPERTY_READ("Previous", "List", List_Previous), + GB_PROPERTY_READ("Prev", "List", List_Previous), + GB_PROPERTY_READ("IsLinked", "b", List_IsLinked), + GB_PROPERTY_READ("IsEmbedded", "b", List_IsEmbedded), + + GB_PROPERTY("Data", "o", List_Data), + + GB_END_DECLARE +}; + +BEGIN_METHOD_VOID(ListRoot_new) + + CLIST_init_root(THIS); + THIS->embedded = 0; + THIS->has_link_ref = 0; + +END_METHOD + +BEGIN_METHOD_VOID(ListRoot_free) + + CLIST_unlink_and_unref_all(THIS); + +END_METHOD + +BEGIN_PROPERTY(ListRoot_IsEmpty) + + GB.ReturnBoolean(CLIST_is_empty(THIS)); + +END_PROPERTY + +GB_DESC CListRootDesc[] = { + GB_DECLARE("ListRoot", sizeof(CLIST)), + + GB_METHOD("_new", NULL, ListRoot_new, NULL), + GB_METHOD("_free", NULL, ListRoot_free, NULL), + GB_METHOD("_next", "o", List_next, NULL), + + GB_METHOD("AddEnd", NULL, List_AddPrev, "(Node)List;"), + GB_METHOD("AddStart", NULL, List_AddNext, "(Node)List;"), + GB_METHOD("Unlink", NULL, List_Unlink, NULL), + GB_METHOD("Extract", "List", List_Extract, "(Count)i"), + GB_METHOD("Clear", NULL, List_Clear, NULL), + + GB_PROPERTY_READ("First", "List", List_Next), + GB_PROPERTY_READ("Last", "List", List_Previous), + GB_PROPERTY_READ("IsEmpty", "b", ListRoot_IsEmpty), + + GB_END_DECLARE +}; + +CLIST_INTF List = { + .New = CLIST_new, + .Destroy = CLIST_destroy, + .NewRoot = CLIST_new_root, + .DestroyRoot = CLIST_destroy_root, + .IsRoot = CLIST_is_root, + .IsEmpty = CLIST_is_empty, + .AddBefore = CLIST_add_before, + .AddAfter = CLIST_add_after, + .Unlink = CLIST_unlink, + .Extract = CLIST_extract +}; diff --git a/gb.adt/src/c_list.h b/gb.adt/src/c_list.h new file mode 100644 index 000000000..9879e198a --- /dev/null +++ b/gb.adt/src/c_list.h @@ -0,0 +1,92 @@ +/* + * c_list.h + * + * Copyright (C) 2012 Tobias Boege + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#ifndef __C_LIST_H +#define __C_LIST_H + +#include "../gambas.h" + +extern GB_INTERFACE GB; + +typedef struct clist { + union { + GB_BASE ob; /* C functions maintain the memory themselves */ + intptr_t uptr; /* They get a private data pointer instead */ + }; + struct clist *prev, *next; + void *data; + int embedded : 1; + int has_link_ref : 1; +} CLIST; + +typedef struct { + CLIST *(*New)(void *); +#define DECLARE_CLIST(name, obj) \ + CLIST name = { \ + .uptr = (intptr_t) NULL, \ + .prev = &name, \ + .next = &name, \ + .data = obj, \ + .embedded = 0, \ + .has_link_ref = 0\ + } + + void *(*Destroy)(CLIST *); + CLIST *(*NewRoot)(void); +#define DECLARE_CLIST_ROOT(name) \ + CLIST name = { \ + .uptr = (intptr_t) NULL, \ + .prev = &name, \ + .next = &name, \ + .data = &name, \ + .embedded = 0, \ + .has_link_ref = 0 \ + } + + void (*DestroyRoot)(CLIST *); + int (*IsRoot)(CLIST *); + int (*IsEmpty)(CLIST *); + void (*AddBefore)(CLIST *, CLIST *); + void (*AddAfter)(CLIST *, CLIST *); + void (*Unlink)(CLIST *); + CLIST *(*Extract)(CLIST *, int); +} CLIST_INTF; + +#define clist_for_each(node, list) \ + for (node = (list)->next; node != (list); node = node->next) + +#define clist_for_each_first(node, list, c) \ + for (node = (list), c = 1; node != (list) || c--; node = node->next) + +#define clist_for_each_safe(node, list, next) \ + for (node = (list)->next, next = node->next; node != (list); \ + node = next, next = node->next) + + +#ifndef __C_LIST_C +extern GB_DESC CListDesc[]; +extern GB_DESC CListRootDesc[]; +extern CLIST_INTF List; + +extern void CLIST_exit(void); +#endif + +#endif /* !__C_LIST_H */ diff --git a/gb.adt/src/gb.adt.component b/gb.adt/src/gb.adt.component new file mode 100644 index 000000000..65cb69692 --- /dev/null +++ b/gb.adt/src/gb.adt.component @@ -0,0 +1,4 @@ +[Component] +Author=Tobias Boege +State=Unstable + diff --git a/gb.adt/src/main.c b/gb.adt/src/main.c new file mode 100644 index 000000000..8855856c4 --- /dev/null +++ b/gb.adt/src/main.c @@ -0,0 +1,54 @@ +/* + * main.c - gb.adt glue + * + * Copyright (C) 2012 Tobias Boege + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#define __MAIN_C + +#include "c_list.h" +#include "c_deque.h" +#include "c_circular.h" +#include "main.h" + +GB_INTERFACE GB EXPORT; + +GB_DESC *GB_CLASSES[] EXPORT = { + CListDesc, + CListRootDesc, + + CDequeDesc, + CStackDesc, + CQueueDesc, + CPrioQueueDesc, + + CCircularDesc, + + NULL +}; + +int EXPORT GB_INIT() +{ + return 0; +} + + +void EXPORT GB_EXIT() +{ + CLIST_exit(); +} diff --git a/gb.adt/src/main.h b/gb.adt/src/main.h new file mode 100644 index 000000000..7030a197e --- /dev/null +++ b/gb.adt/src/main.h @@ -0,0 +1,11 @@ +#ifndef __MAIN_H +#define __MAIN_H + +#include "gb_common.h" +#include "gambas.h" + +#ifndef __MAIN_C +extern GB_INTERFACE GB; +#endif + +#endif /* !__MAIN_H */