396 lines
14 KiB
C
Executable File
396 lines
14 KiB
C
Executable File
/* Abstract ordered map data type.
|
|
Copyright (C) 2006-2007, 2009-2024 Free Software Foundation, Inc.
|
|
Written by Bruno Haible <bruno@clisp.org>, 2018.
|
|
|
|
This file is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU Lesser General Public License as
|
|
published by the Free Software Foundation; either version 2.1 of the
|
|
License, or (at your option) any later version.
|
|
|
|
This file 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 Lesser General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Lesser General Public License
|
|
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
|
|
|
#ifndef _GL_OMAP_H
|
|
#define _GL_OMAP_H
|
|
|
|
/* This file uses _GL_INLINE_HEADER_BEGIN, _GL_INLINE,
|
|
_GL_ATTRIBUTE_NODISCARD. */
|
|
#if !_GL_CONFIG_H_INCLUDED
|
|
#error "Please include config.h first."
|
|
#endif
|
|
|
|
#include <stddef.h>
|
|
|
|
_GL_INLINE_HEADER_BEGIN
|
|
#ifndef GL_OMAP_INLINE
|
|
# define GL_OMAP_INLINE _GL_INLINE
|
|
#endif
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
|
|
/* gl_omap is an abstract ordered map data type. It can contain any number
|
|
of (key, value) pairs, where
|
|
- keys and values are objects ('void *' or 'const void *' pointers),
|
|
- The (key, value) pairs are ordered by the key, in the order of a given
|
|
comparator function.
|
|
- There are no (key, value1) and (key, value2) pairs with the same key
|
|
(in the sense of the comparator function).
|
|
|
|
There are several implementations of this ordered map datatype, optimized
|
|
for different operations or for memory. You can start using the simplest
|
|
ordered map implementation, GL_ARRAY_OMAP, 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_omap_create call.
|
|
|
|
The implementations are:
|
|
GL_ARRAY_OMAP a growable array
|
|
GL_AVLTREE_OMAP a binary tree (AVL tree)
|
|
GL_RBTREE_OMAP a binary tree (red-black tree)
|
|
|
|
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 pair, GL_ARRAY_OMAP is the most compact representation, and
|
|
GL_AVLTREE_OMAP, GL_RBTREE_OMAP need more memory.
|
|
|
|
The guaranteed average performance of the operations is, for a map of
|
|
n pairs:
|
|
|
|
Operation ARRAY TREE
|
|
|
|
gl_omap_size O(1) O(1)
|
|
gl_omap_get O(log n) O(log n)
|
|
gl_omap_put O(n) O(log n)
|
|
gl_omap_remove O(n) O(log n)
|
|
gl_omap_search O(log n) O(log n)
|
|
gl_omap_search_atleast O(log n) O(log n)
|
|
gl_omap_iterator O(1) O(log n)
|
|
gl_omap_iterator_next O(1) O(log n)
|
|
*/
|
|
|
|
/* -------------------------- gl_omap_t Data Type -------------------------- */
|
|
|
|
/* Type of function used to compare two keys. Same as for qsort().
|
|
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);
|
|
|
|
/* 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
|
|
|
|
/* Type of function used to compare a key with a threshold.
|
|
Returns true if the key is greater or equal than the threshold. */
|
|
typedef bool (*gl_mapkey_threshold_fn) (const void *key, const void *threshold);
|
|
|
|
struct gl_omap_impl;
|
|
/* Type representing an entire ordered map. */
|
|
typedef struct gl_omap_impl * gl_omap_t;
|
|
|
|
struct gl_omap_implementation;
|
|
/* Type representing a ordered map datatype implementation. */
|
|
typedef const struct gl_omap_implementation * gl_omap_implementation_t;
|
|
|
|
#if 0 /* Unless otherwise specified, these are defined inline below. */
|
|
|
|
/* Creates an empty map.
|
|
IMPLEMENTATION is one of GL_ARRAY_OMAP, GL_AVLTREE_OMAP, GL_RBTREE_OMAP.
|
|
COMPAR_FN is a key comparison function or NULL.
|
|
KDISPOSE_FN is a key disposal function or NULL.
|
|
VDISPOSE_FN is a value disposal function or NULL. */
|
|
/* declared in gl_xomap.h */
|
|
extern gl_omap_t gl_omap_create_empty (gl_omap_implementation_t implementation,
|
|
gl_mapkey_compar_fn compar_fn,
|
|
gl_mapkey_dispose_fn kdispose_fn,
|
|
gl_mapvalue_dispose_fn vdispose_fn)
|
|
/*_GL_ATTRIBUTE_DEALLOC (gl_omap_free, 1)*/
|
|
_GL_ATTRIBUTE_RETURNS_NONNULL;
|
|
/* Likewise. Returns NULL upon out-of-memory. */
|
|
extern gl_omap_t gl_omap_nx_create_empty (gl_omap_implementation_t implementation,
|
|
gl_mapkey_compar_fn compar_fn,
|
|
gl_mapkey_dispose_fn kdispose_fn,
|
|
gl_mapvalue_dispose_fn vdispose_fn)
|
|
/*_GL_ATTRIBUTE_DEALLOC (gl_omap_free, 1)*/;
|
|
|
|
/* Returns the current number of pairs in an ordered map. */
|
|
extern size_t gl_omap_size (gl_omap_t map);
|
|
|
|
/* Searches whether a pair with the given key is already in the ordered map.
|
|
Returns the value if found, or NULL if not present in the map. */
|
|
extern const void * gl_omap_get (gl_omap_t map, const void *key);
|
|
|
|
/* Searches whether a pair with the given key is already in the ordered map.
|
|
Returns true and sets *VALUEP to the value if found.
|
|
Returns false if not present in the map. */
|
|
extern bool gl_omap_search (gl_omap_t map, const void *key,
|
|
const void **valuep);
|
|
|
|
/* Searches the pair with the least key in the ordered map that compares
|
|
greater or equal to the given THRESHOLD. The representation of the
|
|
THRESHOLD is defined by the THRESHOLD_FN.
|
|
Returns true and stores the found pair in *KEYP and *VALUEP if found.
|
|
Otherwise returns false. */
|
|
extern bool gl_omap_search_atleast (gl_omap_t map,
|
|
gl_mapkey_threshold_fn threshold_fn,
|
|
const void *threshold,
|
|
const void **keyp, const void **valuep);
|
|
|
|
/* Adds a pair to an ordered map.
|
|
Returns true if a pair with the given key was not already in the map and so
|
|
this pair was added.
|
|
Returns false if a pair with the given key was already in the map and only
|
|
its value was replaced. */
|
|
/* declared in gl_xomap.h */
|
|
extern bool gl_omap_put (gl_omap_t map, const void *key, const void *value);
|
|
/* Likewise. Returns -1 upon out-of-memory. */
|
|
_GL_ATTRIBUTE_NODISCARD
|
|
extern int gl_omap_nx_put (gl_omap_t map, const void *key, const void *value);
|
|
|
|
/* Adds a pair to an ordered map and retrieves the previous value.
|
|
Returns true if a pair with the given key was not already in the map and so
|
|
this pair was added.
|
|
Returns false and sets *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_xomap.h */
|
|
extern bool gl_omap_getput (gl_omap_t map, const void *key, const void *value,
|
|
const void **oldvaluep);
|
|
/* Likewise. Returns -1 upon out-of-memory. */
|
|
_GL_ATTRIBUTE_NODISCARD
|
|
extern int gl_omap_nx_getput (gl_omap_t map, const void *key, const void *value,
|
|
const void **oldvaluep);
|
|
|
|
/* Removes a pair from an ordered map.
|
|
Returns true if the key was found and its pair removed.
|
|
Returns false otherwise. */
|
|
extern bool gl_omap_remove (gl_omap_t map, const void *key);
|
|
|
|
/* Removes a pair from an ordered map and retrieves the previous value.
|
|
Returns true and sets *OLDVALUEP to the previous value, if the key was found
|
|
and its pair removed.
|
|
Returns false otherwise. */
|
|
extern bool gl_omap_getremove (gl_omap_t map, const void *key,
|
|
const void **oldvaluep);
|
|
|
|
/* Frees an entire ordered 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_omap_free (gl_omap_t map);
|
|
|
|
#endif /* End of inline and gl_xomap.h-defined functions. */
|
|
|
|
/* ---------------------- gl_omap_iterator_t Data Type ---------------------- */
|
|
|
|
/* Functions for iterating through an ordered map. */
|
|
|
|
/* Type of an iterator that traverses an ordered 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_omap_iterator_next. */
|
|
const struct gl_omap_implementation *vtable;
|
|
/* For detecting whether the last returned pair was removed. */
|
|
gl_omap_t map;
|
|
size_t count;
|
|
/* Other, implementation-private fields. */
|
|
void *p; void *q;
|
|
size_t i; size_t j;
|
|
} gl_omap_iterator_t;
|
|
|
|
#if 0 /* These are defined inline below. */
|
|
|
|
/* Creates an iterator traversing an ordered 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_omap_iterator_t gl_omap_iterator (gl_omap_t map);
|
|
|
|
/* If there is a next pair, stores the next pair in *KEYP and *VALUEP, advances
|
|
the iterator, and returns true. Otherwise, returns false. */
|
|
extern bool gl_omap_iterator_next (gl_omap_iterator_t *iterator,
|
|
const void **keyp, const void **valuep);
|
|
|
|
/* Frees an iterator. */
|
|
extern void gl_omap_iterator_free (gl_omap_iterator_t *iterator);
|
|
|
|
#endif /* End of inline functions. */
|
|
|
|
/* ------------------------- Implementation Details ------------------------- */
|
|
|
|
struct gl_omap_implementation
|
|
{
|
|
/* gl_omap_t functions. */
|
|
gl_omap_t (*nx_create_empty) (gl_omap_implementation_t implementation,
|
|
gl_mapkey_compar_fn compar_fn,
|
|
gl_mapkey_dispose_fn kdispose_fn,
|
|
gl_mapvalue_dispose_fn vdispose_fn);
|
|
size_t (*size) (gl_omap_t map);
|
|
bool (*search) (gl_omap_t map, const void *key, const void **valuep);
|
|
bool (*search_atleast) (gl_omap_t map,
|
|
gl_mapkey_threshold_fn threshold_fn,
|
|
const void *threshold,
|
|
const void **keyp, const void **valuep);
|
|
int (*nx_getput) (gl_omap_t map, const void *key, const void *value,
|
|
const void **oldvaluep);
|
|
bool (*getremove) (gl_omap_t map, const void *key, const void **oldvaluep);
|
|
void (*omap_free) (gl_omap_t map);
|
|
/* gl_omap_iterator_t functions. */
|
|
gl_omap_iterator_t (*iterator) (gl_omap_t map);
|
|
bool (*iterator_next) (gl_omap_iterator_t *iterator,
|
|
const void **keyp, const void **valuep);
|
|
void (*iterator_free) (gl_omap_iterator_t *iterator);
|
|
};
|
|
|
|
struct gl_omap_impl_base
|
|
{
|
|
const struct gl_omap_implementation *vtable;
|
|
gl_mapkey_compar_fn compar_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_omap_implementation. */
|
|
|
|
GL_OMAP_INLINE
|
|
/*_GL_ATTRIBUTE_DEALLOC (gl_omap_free, 1)*/
|
|
gl_omap_t
|
|
gl_omap_nx_create_empty (gl_omap_implementation_t implementation,
|
|
gl_mapkey_compar_fn compar_fn,
|
|
gl_mapkey_dispose_fn kdispose_fn,
|
|
gl_mapvalue_dispose_fn vdispose_fn)
|
|
{
|
|
return implementation->nx_create_empty (implementation, compar_fn,
|
|
kdispose_fn, vdispose_fn);
|
|
}
|
|
|
|
GL_OMAP_INLINE size_t
|
|
gl_omap_size (gl_omap_t map)
|
|
{
|
|
return ((const struct gl_omap_impl_base *) map)->vtable->size (map);
|
|
}
|
|
|
|
GL_OMAP_INLINE bool
|
|
gl_omap_search (gl_omap_t map, const void *key, const void **valuep)
|
|
{
|
|
return ((const struct gl_omap_impl_base *) map)->vtable
|
|
->search (map, key, valuep);
|
|
}
|
|
|
|
GL_OMAP_INLINE bool
|
|
gl_omap_search_atleast (gl_omap_t map,
|
|
gl_mapkey_threshold_fn threshold_fn,
|
|
const void *threshold,
|
|
const void **keyp, const void **valuep)
|
|
{
|
|
return ((const struct gl_omap_impl_base *) map)->vtable
|
|
->search_atleast (map, threshold_fn, threshold, keyp, valuep);
|
|
}
|
|
|
|
_GL_ATTRIBUTE_NODISCARD GL_OMAP_INLINE int
|
|
gl_omap_nx_getput (gl_omap_t map, const void *key, const void *value,
|
|
const void **oldvaluep)
|
|
{
|
|
return ((const struct gl_omap_impl_base *) map)->vtable
|
|
->nx_getput (map, key, value, oldvaluep);
|
|
}
|
|
|
|
GL_OMAP_INLINE bool
|
|
gl_omap_getremove (gl_omap_t map, const void *key, const void **oldvaluep)
|
|
{
|
|
return ((const struct gl_omap_impl_base *) map)->vtable
|
|
->getremove (map, key, oldvaluep);
|
|
}
|
|
|
|
GL_OMAP_INLINE void
|
|
gl_omap_free (gl_omap_t map)
|
|
{
|
|
((const struct gl_omap_impl_base *) map)->vtable->omap_free (map);
|
|
}
|
|
|
|
GL_OMAP_INLINE gl_omap_iterator_t
|
|
gl_omap_iterator (gl_omap_t map)
|
|
{
|
|
return ((const struct gl_omap_impl_base *) map)->vtable->iterator (map);
|
|
}
|
|
|
|
GL_OMAP_INLINE bool
|
|
gl_omap_iterator_next (gl_omap_iterator_t *iterator,
|
|
const void **keyp, const void **valuep)
|
|
{
|
|
return iterator->vtable->iterator_next (iterator, keyp, valuep);
|
|
}
|
|
|
|
GL_OMAP_INLINE void
|
|
gl_omap_iterator_free (gl_omap_iterator_t *iterator)
|
|
{
|
|
iterator->vtable->iterator_free (iterator);
|
|
}
|
|
|
|
/* Define the convenience functions, that is, the functions that are independent
|
|
of the implementation. */
|
|
|
|
GL_OMAP_INLINE const void *
|
|
gl_omap_get (gl_omap_t map, const void *key)
|
|
{
|
|
const void *value = NULL;
|
|
gl_omap_search (map, key, &value);
|
|
return value;
|
|
}
|
|
|
|
_GL_ATTRIBUTE_NODISCARD GL_OMAP_INLINE int
|
|
gl_omap_nx_put (gl_omap_t map, const void *key, const void *value)
|
|
{
|
|
const void *oldvalue;
|
|
int result = gl_omap_nx_getput (map, key, value, &oldvalue);
|
|
if (result == 0)
|
|
{
|
|
gl_mapvalue_dispose_fn vdispose_fn =
|
|
((const struct gl_omap_impl_base *) map)->vdispose_fn;
|
|
if (vdispose_fn != NULL)
|
|
vdispose_fn (oldvalue);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
GL_OMAP_INLINE bool
|
|
gl_omap_remove (gl_omap_t map, const void *key)
|
|
{
|
|
const void *oldvalue;
|
|
bool result = gl_omap_getremove (map, key, &oldvalue);
|
|
if (result)
|
|
{
|
|
gl_mapvalue_dispose_fn vdispose_fn =
|
|
((const struct gl_omap_impl_base *) map)->vdispose_fn;
|
|
if (vdispose_fn != NULL)
|
|
vdispose_fn (oldvalue);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
|
|
_GL_INLINE_HEADER_END
|
|
|
|
#endif /* _GL_OMAP_H */
|