>From b34b0da5f82eb6b0c163820ad9aa0e4e5bfe7590 Mon Sep 17 00:00:00 2001 From: Bruno Haible Date: Tue, 4 Dec 2018 00:41:24 +0100 Subject: [PATCH 1/8] set: New module. * lib/gl_set.h: New file. * lib/gl_set.c: New file. * lib/gl_oset.h (gl_setelement_dispose_fn): Avoid conflict with gl_set.h. * modules/set: New file. --- ChangeLog | 9 ++ lib/gl_oset.h | 5 +- lib/gl_set.c | 3 + lib/gl_set.h | 280 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ modules/set | 24 +++++ 5 files changed, 320 insertions(+), 1 deletion(-) create mode 100644 lib/gl_set.c create mode 100644 lib/gl_set.h create mode 100644 modules/set diff --git a/ChangeLog b/ChangeLog index 76d6966..1761c1d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +2018-12-03 Bruno Haible + + set: New module. + * lib/gl_set.h: New file. + * lib/gl_set.c: New file. + * lib/gl_oset.h (gl_setelement_dispose_fn): Avoid conflict with + gl_set.h. + * modules/set: New file. + 2018-12-01 Bruno Haible gnupload: Document short options. diff --git a/lib/gl_oset.h b/lib/gl_oset.h index 5cad161..abe3eb4 100644 --- a/lib/gl_oset.h +++ b/lib/gl_oset.h @@ -77,9 +77,12 @@ extern "C" { NULL denotes pointer comparison. */ typedef int (*gl_setelement_compar_fn) (const void *elt1, const void *elt2); +#ifndef _GL_SETELEMENT_DISPOSE_FN_DEFINED /* Type of function used to dispose an element once it's removed from a set. NULL denotes a no-op. */ typedef void (*gl_setelement_dispose_fn) (const void *elt); +# define _GL_SETELEMENT_DISPOSE_FN_DEFINED 1 +#endif /* Type of function used to compare an element with a threshold. Return true if the element is greater or equal than the threshold. */ @@ -144,7 +147,7 @@ extern bool gl_oset_remove (gl_oset_t set, const void *elt); (But this call does not free the elements of the set.) */ extern void gl_oset_free (gl_oset_t set); -#endif /* End of inline and gl_xlist.h-defined functions. */ +#endif /* End of inline and gl_xoset.h-defined functions. */ /* --------------------- gl_oset_iterator_t Data Type --------------------- */ diff --git a/lib/gl_set.c b/lib/gl_set.c new file mode 100644 index 0000000..e00d202 --- /dev/null +++ b/lib/gl_set.c @@ -0,0 +1,3 @@ +#include +#define GL_SET_INLINE _GL_EXTERN_INLINE +#include "gl_set.h" diff --git a/lib/gl_set.h b/lib/gl_set.h new file mode 100644 index 0000000..bc615c3 --- /dev/null +++ b/lib/gl_set.h @@ -0,0 +1,280 @@ +/* Abstract set data type. + Copyright (C) 2006-2007, 2009-2018 Free Software Foundation, Inc. + Written by Bruno Haible , 2018. + + 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 3 of the License, 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, see . */ + +#ifndef _GL_SET_H +#define _GL_SET_H + +#include +#include + +#ifndef _GL_INLINE_HEADER_BEGIN + #error "Please include config.h first." +#endif +_GL_INLINE_HEADER_BEGIN +#ifndef GL_SET_INLINE +# define GL_SET_INLINE _GL_INLINE +#endif + +#ifdef __cplusplus +extern "C" { +#endif + + +/* gl_set is an abstract set data type. It can contain any number of objects + ('void *' or 'const void *' pointers); the order does not matter. + Duplicates (in the sense of the comparator) are forbidden. + + There are several implementations of this set datatype, optimized for + different operations or for memory. You can start using the simplest set + implementation, GL_ARRAY_SET, and switch to a different implementation + later, when you realize which operations are performed the most frequently. + The API of the different implementations is exactly the same; when switching + to a different implementation, you only have to change the gl_set_create + call. + + The implementations are: + GL_ARRAY_SET a growable array + GL_LINKEDHASH_SET a hash table with a linked list + GL_HASH_SET a hash table + + The memory consumption is asymptotically the same: O(1) for every object + in the set. When looking more closely at the average memory consumed + for an object, GL_ARRAY_SET is the most compact representation, then comes + GL_HASH_SET, and GL_LINKEDHASH_SET needs the most memory. + + The guaranteed average performance of the operations is, for a set of + n elements: + + Operation ARRAY LINKEDHASH + HASH + + gl_set_size O(1) O(1) + gl_set_add O(n) O(1) + gl_set_remove O(n) O(1) + gl_set_search O(n) O(1) + gl_set_iterator O(1) O(1) + gl_set_iterator_next O(1) O(1) + */ + +/* --------------------------- gl_set_t Data Type --------------------------- */ + +/* Type of function used to compare two elements. + NULL denotes pointer comparison. */ +typedef bool (*gl_setelement_equals_fn) (const void *elt1, const void *elt2); + +/* Type of function used to compute a hash code. + NULL denotes a function that depends only on the pointer itself. */ +typedef size_t (*gl_setelement_hashcode_fn) (const void *elt); + +#ifndef _GL_SETELEMENT_DISPOSE_FN_DEFINED +/* Type of function used to dispose an element once it's removed from a set. + NULL denotes a no-op. */ +typedef void (*gl_setelement_dispose_fn) (const void *elt); +# define _GL_SETELEMENT_DISPOSE_FN_DEFINED 1 +#endif + +struct gl_set_impl; +/* Type representing an entire set. */ +typedef struct gl_set_impl * gl_set_t; + +struct gl_set_implementation; +/* Type representing a set datatype implementation. */ +typedef const struct gl_set_implementation * gl_set_implementation_t; + +#if 0 /* Unless otherwise specified, these are defined inline below. */ + +/* Create an empty set. + IMPLEMENTATION is one of GL_ARRAY_SET, GL_LINKEDHASH_SET, GL_HASH_SET. + EQUALS_FN is an element comparison function or NULL. + HASHCODE_FN is an element hash code function or NULL. + DISPOSE_FN is an element disposal function or NULL. */ +/* declared in gl_xset.h */ +extern gl_set_t gl_set_create_empty (gl_set_implementation_t implementation, + gl_setelement_equals_fn equals_fn, + gl_setelement_hashcode_fn hashcode_fn, + gl_setelement_dispose_fn dispose_fn); +/* Likewise. Return NULL upon out-of-memory. */ +extern gl_set_t gl_set_nx_create_empty (gl_set_implementation_t implementation, + gl_setelement_equals_fn equals_fn, + gl_setelement_hashcode_fn hashcode_fn, + gl_setelement_dispose_fn dispose_fn); + +/* Return the current number of elements in a set. */ +extern size_t gl_set_size (gl_set_t set); + +/* Search whether an element is already in the set. + Return true if found, or false if not present in the set. */ +extern bool gl_set_search (gl_set_t set, const void *elt); + +/* Add an element to a set. + Return true if it was not already in the set and added, false otherwise. */ +/* declared in gl_xset.h */ +extern bool gl_set_add (gl_set_t set, const void *elt); +/* Likewise. Return -1 upon out-of-memory. */ +extern int gl_set_nx_add (gl_set_t set, const void *elt) +#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) + __attribute__ ((__warn_unused_result__)) +#endif + ; + +/* Remove an element from a set. + Return true if it was found and removed. */ +extern bool gl_set_remove (gl_set_t set, const void *elt); + +/* Free an entire set. + (But this call does not free the elements of the set.) */ +extern void gl_set_free (gl_set_t set); + +#endif /* End of inline and gl_xset.h-defined functions. */ + +/* ---------------------- gl_set_iterator_t Data Type ---------------------- */ + +/* Functions for iterating through a set. + Note: Iterating through a set of type GL_HASH_SET returns the elements in an + unpredictable order. If you need a predictable order, use GL_LINKEDHASH_SET + instead of GL_HASH_SET. */ + +/* Type of an iterator that traverses a set. + This is a fixed-size struct, so that creation of an iterator doesn't need + memory allocation on the heap. */ +typedef struct +{ + /* For fast dispatch of gl_set_iterator_next. */ + const struct gl_set_implementation *vtable; + /* For detecting whether the last returned element was removed. */ + gl_set_t set; + size_t count; + /* Other, implementation-private fields. */ + void *p; void *q; + size_t i; size_t j; +} gl_set_iterator_t; + +#if 0 /* These are defined inline below. */ + +/* Create an iterator traversing a set. + The set's contents must not be modified while the iterator is in use, + except for removing the last returned element. */ +extern gl_set_iterator_t gl_set_iterator (gl_set_t set); + +/* If there is a next element, store the next element in *ELTP, advance the + iterator and return true. Otherwise, return false. */ +extern bool gl_set_iterator_next (gl_set_iterator_t *iterator, + const void **eltp); + +/* Free an iterator. */ +extern void gl_set_iterator_free (gl_set_iterator_t *iterator); + +#endif /* End of inline functions. */ + +/* ------------------------ Implementation Details ------------------------ */ + +struct gl_set_implementation +{ + /* gl_set_t functions. */ + gl_set_t (*nx_create_empty) (gl_set_implementation_t implementation, + gl_setelement_equals_fn equals_fn, + gl_setelement_hashcode_fn hashcode_fn, + gl_setelement_dispose_fn dispose_fn); + size_t (*size) (gl_set_t set); + bool (*search) (gl_set_t set, const void *elt); + int (*nx_add) (gl_set_t set, const void *elt); + bool (*remove_elt) (gl_set_t set, const void *elt); + void (*set_free) (gl_set_t set); + /* gl_set_iterator_t functions. */ + gl_set_iterator_t (*iterator) (gl_set_t set); + bool (*iterator_next) (gl_set_iterator_t *iterator, const void **eltp); + void (*iterator_free) (gl_set_iterator_t *iterator); +}; + +struct gl_set_impl_base +{ + const struct gl_set_implementation *vtable; + gl_setelement_equals_fn equals_fn; + gl_setelement_dispose_fn dispose_fn; +}; + +/* Define all functions of this file as accesses to the + struct gl_set_implementation. */ + +GL_SET_INLINE gl_set_t +gl_set_nx_create_empty (gl_set_implementation_t implementation, + gl_setelement_equals_fn equals_fn, + gl_setelement_hashcode_fn hashcode_fn, + gl_setelement_dispose_fn dispose_fn) +{ + return implementation->nx_create_empty (implementation, equals_fn, + hashcode_fn, dispose_fn); +} + +GL_SET_INLINE size_t +gl_set_size (gl_set_t set) +{ + return ((const struct gl_set_impl_base *) set)->vtable->size (set); +} + +GL_SET_INLINE bool +gl_set_search (gl_set_t set, const void *elt) +{ + return ((const struct gl_set_impl_base *) set)->vtable->search (set, elt); +} + +GL_SET_INLINE int +#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) + __attribute__ ((__warn_unused_result__)) +#endif +gl_set_nx_add (gl_set_t set, const void *elt) +{ + return ((const struct gl_set_impl_base *) set)->vtable->nx_add (set, elt); +} + +GL_SET_INLINE bool +gl_set_remove (gl_set_t set, const void *elt) +{ + return ((const struct gl_set_impl_base *) set)->vtable->remove_elt (set, elt); +} + +GL_SET_INLINE void +gl_set_free (gl_set_t set) +{ + ((const struct gl_set_impl_base *) set)->vtable->set_free (set); +} + +GL_SET_INLINE gl_set_iterator_t +gl_set_iterator (gl_set_t set) +{ + return ((const struct gl_set_impl_base *) set)->vtable->iterator (set); +} + +GL_SET_INLINE bool +gl_set_iterator_next (gl_set_iterator_t *iterator, const void **eltp) +{ + return iterator->vtable->iterator_next (iterator, eltp); +} + +GL_SET_INLINE void +gl_set_iterator_free (gl_set_iterator_t *iterator) +{ + iterator->vtable->iterator_free (iterator); +} + +#ifdef __cplusplus +} +#endif + +_GL_INLINE_HEADER_END + +#endif /* _GL_SET_H */ diff --git a/modules/set b/modules/set new file mode 100644 index 0000000..29cec74 --- /dev/null +++ b/modules/set @@ -0,0 +1,24 @@ +Description: +Abstract set data type. + +Files: +lib/gl_set.h +lib/gl_set.c + +Depends-on: +extern-inline +stdbool + +configure.ac: + +Makefile.am: +lib_SOURCES += gl_set.h gl_set.c + +Include: +"gl_set.h" + +License: +GPL + +Maintainer: +all -- 2.7.4