>From 4d1dabf15bf9a3b5652872340ef85711b877c074 Mon Sep 17 00:00:00 2001 From: Bruno Haible Date: Wed, 12 Dec 2018 01:23:21 +0100 Subject: [PATCH 1/8] map: New module. * lib/gl_map.h: New file. * lib/gl_map.c: New file. * lib/gl_omap.h (gl_mapkey_dispose_fn, gl_mapvalue_dispose_fn): Avoid conflict with gl_map.h. * modules/map: New file. --- ChangeLog | 9 ++ lib/gl_map.c | 3 + lib/gl_map.h | 382 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ lib/gl_omap.h | 5 + modules/map | 24 ++++ 5 files changed, 423 insertions(+) create mode 100644 lib/gl_map.c create mode 100644 lib/gl_map.h create mode 100644 modules/map diff --git a/ChangeLog b/ChangeLog index 69a62b5..a49412b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,14 @@ 2018-12-11 Bruno Haible + map: New module. + * lib/gl_map.h: New file. + * lib/gl_map.c: New file. + * lib/gl_omap.h (gl_mapkey_dispose_fn, gl_mapvalue_dispose_fn): Avoid + conflict with gl_map.h. + * modules/map: New file. + +2018-12-11 Bruno Haible + omap: Don't dispose the old value when the function returns it. * lib/gl_array_omap.c (gl_array_remove_at): Don't invoke the vdispose_fn here. diff --git a/lib/gl_map.c b/lib/gl_map.c new file mode 100644 index 0000000..758a65f --- /dev/null +++ b/lib/gl_map.c @@ -0,0 +1,3 @@ +#include +#define GL_MAP_INLINE _GL_EXTERN_INLINE +#include "gl_map.h" diff --git a/lib/gl_map.h b/lib/gl_map.h new file mode 100644 index 0000000..e14dd65 --- /dev/null +++ b/lib/gl_map.h @@ -0,0 +1,382 @@ +/* Abstract map 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_MAP_H +#define _GL_MAP_H + +#include +#include + +#ifndef _GL_INLINE_HEADER_BEGIN + #error "Please include config.h first." +#endif +_GL_INLINE_HEADER_BEGIN +#ifndef GL_MAP_INLINE +# define GL_MAP_INLINE _GL_INLINE +#endif + +#ifdef __cplusplus +extern "C" { +#endif + + +/* gl_map is an abstract map data type. It can contain any number of + (key, value) pairs, where + - keys and values are objects ('void *' or 'const void *' pointers), + - There are no (key, value1) and (key, value2) pairs with the same key + (in the sense of a given comparator function). + + There are several implementations of this map datatype, optimized for + different operations or for memory. You can start using the simplest map + implementation, GL_ARRAY_MAP, 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_map_create + call. + + The implementations are: + GL_ARRAY_MAP a growable array + GL_LINKEDHASH_MAP a hash table with a linked list + GL_HASH_MAP a hash table + + The memory consumption is asymptotically the same: O(1) for every pair + in the map. When looking more closely at the average memory consumed + for an object, GL_ARRAY_MAP is the most compact representation, then comes + GL_HASH_MAP, and GL_LINKEDHASH_MAP needs the most memory. + + The guaranteed average performance of the operations is, for a map of + n pairs: + + Operation ARRAY LINKEDHASH + HASH + + gl_map_size O(1) O(1) + gl_map_get O(n) O(1) + gl_map_put O(n) O(1) + gl_map_remove O(n) O(1) + gl_map_search O(n) O(1) + gl_map_iterator O(1) O(1) + gl_map_iterator_next O(1) O(1) + */ + +/* --------------------------- gl_map_t Data Type --------------------------- */ + +/* Type of function used to compare two keys. + NULL denotes pointer comparison. */ +typedef bool (*gl_mapkey_equals_fn) (const void *key1, const void *key2); + +/* Type of function used to compute a hash code. + NULL denotes a function that depends only on the pointer itself. */ +typedef size_t (*gl_mapkey_hashcode_fn) (const void *key); + +#ifndef _GL_MAP_DISPOSE_FNS_DEFINED + +/* Type of function used to dispose a key once a (key, value) pair is removed + from a map. NULL denotes a no-op. */ +typedef void (*gl_mapkey_dispose_fn) (const void *key); + +/* Type of function used to dispose a value once a (key, value) pair is removed + from a map. NULL denotes a no-op. */ +typedef void (*gl_mapvalue_dispose_fn) (const void *value); + +# define _GL_MAP_DISPOSE_FNS_DEFINED 1 +#endif + +struct gl_map_impl; +/* Type representing an entire map. */ +typedef struct gl_map_impl * gl_map_t; + +struct gl_map_implementation; +/* Type representing a map datatype implementation. */ +typedef const struct gl_map_implementation * gl_map_implementation_t; + +#if 0 /* Unless otherwise specified, these are defined inline below. */ + +/* Create an empty map. + IMPLEMENTATION is one of GL_ARRAY_MAP, GL_LINKEDHASH_MAP, GL_HASH_MAP. + EQUALS_FN is a key comparison function or NULL. + HASHCODE_FN is a key hash code function or NULL. + KDISPOSE_FN is a key disposal function or NULL. + VDISPOSE_FN is a value disposal function or NULL. */ +/* declared in gl_xmap.h */ +extern gl_map_t gl_map_create_empty (gl_map_implementation_t implementation, + gl_mapkey_equals_fn equals_fn, + gl_mapkey_hashcode_fn hashcode_fn, + gl_mapkey_dispose_fn kdispose_fn, + gl_mapvalue_dispose_fn vdispose_fn); +/* Likewise. Return NULL upon out-of-memory. */ +extern gl_map_t gl_map_nx_create_empty (gl_map_implementation_t implementation, + gl_mapkey_equals_fn equals_fn, + gl_mapkey_hashcode_fn hashcode_fn, + gl_mapkey_dispose_fn kdispose_fn, + gl_mapvalue_dispose_fn vdispose_fn); + +/* Return the current number of pairs in a map. */ +extern size_t gl_map_size (gl_map_t map); + +/* Search whether a pair with the given key is already in the map. + Return the value if found, or NULL if not present in the map. */ +extern const void * gl_map_get (gl_map_t map, const void *key); + +/* Search whether a pair with the given key is already in the map. + Return true and set *VALUEP to the value if found. + Return false if not present in the map. */ +extern bool gl_map_search (gl_map_t map, const void *key, const void **valuep); + +/* Add a pair to a map. + Return true if a pair with the given key was not already in the map and so + this pair was added. + Return false if a pair with the given key was already in the map and only + its value was replaced. */ +/* declared in gl_xmap.h */ +extern bool gl_map_put (gl_map_t map, const void *key, const void *value); +/* Likewise. Return -1 upon out-of-memory. */ +extern int gl_map_nx_put (gl_map_t map, const void *key, const void *value) +#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) + __attribute__ ((__warn_unused_result__)) +#endif + ; + +/* Add a pair to a map and retrieve the previous value. + Return true if a pair with the given key was not already in the map and so + this pair was added. + Return false and set *OLDVALUEP to the previous value, if a pair with the + given key was already in the map and only its value was replaced. */ +/* declared in gl_xmap.h */ +extern bool gl_map_getput (gl_map_t map, const void *key, const void *value, + const void **oldvaluep); +/* Likewise. Return -1 upon out-of-memory. */ +extern int gl_map_nx_getput (gl_map_t map, const void *key, const void *value, + const void **oldvaluep) +#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) + __attribute__ ((__warn_unused_result__)) +#endif + ; + +/* Remove a pair from a map. + Return true if the key was found and its pair removed. + Return false otherwise. */ +extern bool gl_map_remove (gl_map_t map, const void *key); + +/* Remove a pair from a map and retrieve the previous value. + Return true and set *OLDVALUEP to the previous value, if the key was found + and its pair removed. + Return false otherwise. */ +extern bool gl_map_getremove (gl_map_t map, const void *key, + const void **oldvaluep); + +/* Free an entire map. + (But this call does not free the keys and values of the pairs in the map. + It only invokes the KDISPOSE_FN on each key and the VDISPOSE_FN on each value + of the pairs in the map.) */ +extern void gl_map_free (gl_map_t map); + +#endif /* End of inline and gl_xmap.h-defined functions. */ + +/* ---------------------- gl_map_iterator_t Data Type ---------------------- */ + +/* Functions for iterating through a map. + Note: Iterating through a map of type GL_HASH_MAP returns the pairs in an + unpredictable order. If you need a predictable order, use GL_LINKEDHASH_MAP + instead of GL_HASH_MAP. */ + +/* Type of an iterator that traverses a map. + 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_map_iterator_next. */ + const struct gl_map_implementation *vtable; + /* For detecting whether the last returned pair was removed. */ + gl_map_t map; + size_t count; + /* Other, implementation-private fields. */ + void *p; void *q; + size_t i; size_t j; +} gl_map_iterator_t; + +#if 0 /* These are defined inline below. */ + +/* Create an iterator traversing a map. + The map's contents must not be modified while the iterator is in use, + except for modifying the value of the last returned key or removing the + last returned pair. */ +extern gl_map_iterator_t gl_map_iterator (gl_map_t map); + +/* If there is a next pair, store the next pair in *KEYP and *VALUEP, advance + the iterator, and return true. Otherwise, return false. */ +extern bool gl_map_iterator_next (gl_map_iterator_t *iterator, + const void **keyp, const void **valuep); + +/* Free an iterator. */ +extern void gl_map_iterator_free (gl_map_iterator_t *iterator); + +#endif /* End of inline functions. */ + +/* ------------------------- Implementation Details ------------------------- */ + +struct gl_map_implementation +{ + /* gl_map_t functions. */ + gl_map_t (*nx_create_empty) (gl_map_implementation_t implementation, + gl_mapkey_equals_fn equals_fn, + gl_mapkey_hashcode_fn hashcode_fn, + gl_mapkey_dispose_fn kdispose_fn, + gl_mapvalue_dispose_fn vdispose_fn); + size_t (*size) (gl_map_t map); + bool (*search) (gl_map_t map, const void *key, const void **valuep); + int (*nx_getput) (gl_map_t map, const void *key, const void *value, + const void **oldvaluep); + bool (*getremove) (gl_map_t map, const void *key, const void **oldvaluep); + void (*map_free) (gl_map_t map); + /* gl_map_iterator_t functions. */ + gl_map_iterator_t (*iterator) (gl_map_t map); + bool (*iterator_next) (gl_map_iterator_t *iterator, + const void **keyp, const void **valuep); + void (*iterator_free) (gl_map_iterator_t *iterator); +}; + +struct gl_map_impl_base +{ + const struct gl_map_implementation *vtable; + gl_mapkey_equals_fn equals_fn; + gl_mapkey_dispose_fn kdispose_fn; + gl_mapvalue_dispose_fn vdispose_fn; +}; + +/* Define most functions of this file as accesses to the + struct gl_map_implementation. */ + +GL_MAP_INLINE gl_map_t +gl_map_nx_create_empty (gl_map_implementation_t implementation, + gl_mapkey_equals_fn equals_fn, + gl_mapkey_hashcode_fn hashcode_fn, + gl_mapkey_dispose_fn kdispose_fn, + gl_mapvalue_dispose_fn vdispose_fn) +{ + return implementation->nx_create_empty (implementation, + equals_fn, hashcode_fn, + kdispose_fn, vdispose_fn); +} + +GL_MAP_INLINE size_t +gl_map_size (gl_map_t map) +{ + return ((const struct gl_map_impl_base *) map)->vtable->size (map); +} + +GL_MAP_INLINE bool +gl_map_search (gl_map_t map, const void *key, const void **valuep) +{ + return ((const struct gl_map_impl_base *) map)->vtable + ->search (map, key, valuep); +} + +GL_MAP_INLINE int +#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) + __attribute__ ((__warn_unused_result__)) +#endif +gl_map_nx_getput (gl_map_t map, const void *key, const void *value, + const void **oldvaluep) +{ + return ((const struct gl_map_impl_base *) map)->vtable + ->nx_getput (map, key, value, oldvaluep); +} + +GL_MAP_INLINE bool +gl_map_getremove (gl_map_t map, const void *key, const void **oldvaluep) +{ + return ((const struct gl_map_impl_base *) map)->vtable + ->getremove (map, key, oldvaluep); +} + +GL_MAP_INLINE void +gl_map_free (gl_map_t map) +{ + ((const struct gl_map_impl_base *) map)->vtable->map_free (map); +} + +GL_MAP_INLINE gl_map_iterator_t +gl_map_iterator (gl_map_t map) +{ + return ((const struct gl_map_impl_base *) map)->vtable->iterator (map); +} + +GL_MAP_INLINE bool +gl_map_iterator_next (gl_map_iterator_t *iterator, + const void **keyp, const void **valuep) +{ + return iterator->vtable->iterator_next (iterator, keyp, valuep); +} + +GL_MAP_INLINE void +gl_map_iterator_free (gl_map_iterator_t *iterator) +{ + iterator->vtable->iterator_free (iterator); +} + +/* Define the convenience functions, that is, the functions that are independent + of the implementation. */ + +GL_MAP_INLINE const void * +gl_map_get (gl_map_t map, const void *key) +{ + const void *value = NULL; + gl_map_search (map, key, &value); + return value; +} + +GL_MAP_INLINE int +#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) + __attribute__ ((__warn_unused_result__)) +#endif +gl_map_nx_put (gl_map_t map, const void *key, const void *value) +{ + const void *oldvalue; + int result = gl_map_nx_getput (map, key, value, &oldvalue); + if (result == 0) + { + gl_mapvalue_dispose_fn vdispose_fn = + ((const struct gl_map_impl_base *) map)->vdispose_fn; + if (vdispose_fn != NULL) + vdispose_fn (oldvalue); + } + return result; +} + +GL_MAP_INLINE bool +gl_map_remove (gl_map_t map, const void *key) +{ + const void *oldvalue; + bool result = gl_map_getremove (map, key, &oldvalue); + if (result) + { + gl_mapvalue_dispose_fn vdispose_fn = + ((const struct gl_map_impl_base *) map)->vdispose_fn; + if (vdispose_fn != NULL) + vdispose_fn (oldvalue); + } + return result; +} + +#ifdef __cplusplus +} +#endif + +_GL_INLINE_HEADER_END + +#endif /* _GL_MAP_H */ diff --git a/lib/gl_omap.h b/lib/gl_omap.h index aa82e33..da41bc4 100644 --- a/lib/gl_omap.h +++ b/lib/gl_omap.h @@ -81,6 +81,8 @@ extern "C" { NULL denotes pointer comparison. */ typedef int (*gl_mapkey_compar_fn) (const void *key1, const void *key2); +#ifndef _GL_MAP_DISPOSE_FNS_DEFINED + /* Type of function used to dispose a key once a (key, value) pair is removed from a map. NULL denotes a no-op. */ typedef void (*gl_mapkey_dispose_fn) (const void *key); @@ -89,6 +91,9 @@ typedef void (*gl_mapkey_dispose_fn) (const void *key); from a map. NULL denotes a no-op. */ typedef void (*gl_mapvalue_dispose_fn) (const void *value); +# define _GL_MAP_DISPOSE_FNS_DEFINED 1 +#endif + /* Type of function used to compare a key with a threshold. Return true if the key is greater or equal than the threshold. */ typedef bool (*gl_mapkey_threshold_fn) (const void *key, const void *threshold); diff --git a/modules/map b/modules/map new file mode 100644 index 0000000..0b611ed --- /dev/null +++ b/modules/map @@ -0,0 +1,24 @@ +Description: +Abstract map data type. + +Files: +lib/gl_map.h +lib/gl_map.c + +Depends-on: +extern-inline +stdbool + +configure.ac: + +Makefile.am: +lib_SOURCES += gl_map.h gl_map.c + +Include: +"gl_map.h" + +License: +GPL + +Maintainer: +all -- 2.7.4