changeset 40017:fb1ee0d2d690

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.
author Bruno Haible <bruno@clisp.org>
date Fri, 14 Dec 2018 23:07:39 +0100
parents 9edd1d1403bb
children 5ff5ae1da245
files ChangeLog lib/gl_map.c lib/gl_map.h lib/gl_omap.h modules/map
diffstat 5 files changed, 423 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Thu Dec 13 22:17:50 2018 +0100
+++ b/ChangeLog	Fri Dec 14 23:07:39 2018 +0100
@@ -1,3 +1,12 @@
+2018-12-14  Bruno Haible  <bruno@clisp.org>
+
+	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-13  Bruno Haible  <bruno@clisp.org>
 
 	select tests: Avoid test failure on Cygwin.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/gl_map.c	Fri Dec 14 23:07:39 2018 +0100
@@ -0,0 +1,3 @@
+#include <config.h>
+#define GL_MAP_INLINE _GL_EXTERN_INLINE
+#include "gl_map.h"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/gl_map.h	Fri Dec 14 23:07:39 2018 +0100
@@ -0,0 +1,382 @@
+/* Abstract map data type.
+   Copyright (C) 2006-2007, 2009-2018 Free Software Foundation, Inc.
+   Written by Bruno Haible <bruno@clisp.org>, 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 <https://www.gnu.org/licenses/>.  */
+
+#ifndef _GL_MAP_H
+#define _GL_MAP_H
+
+#include <stdbool.h>
+#include <stddef.h>
+
+#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 */
--- a/lib/gl_omap.h	Thu Dec 13 22:17:50 2018 +0100
+++ b/lib/gl_omap.h	Fri Dec 14 23:07:39 2018 +0100
@@ -81,6 +81,8 @@
    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 @@
    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);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/map	Fri Dec 14 23:07:39 2018 +0100
@@ -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