![David Howells](/assets/img/avatar_default.png)
Add a generic associative array implementation that can be used as the container for keyrings, thereby massively increasing the capacity available whilst also speeding up searching in keyrings that contain a lot of keys. This may also be useful in FS-Cache for tracking cookies. Documentation is added into Documentation/associative_array.txt Some of the properties of the implementation are: (1) Objects are opaque pointers. The implementation does not care where they point (if anywhere) or what they point to (if anything). [!] NOTE: Pointers to objects _must_ be zero in the two least significant bits. (2) Objects do not need to contain linkage blocks for use by the array. This permits an object to be located in multiple arrays simultaneously. Rather, the array is made up of metadata blocks that point to objects. (3) Objects are labelled as being one of two types (the type is a bool value). This information is stored in the array, but has no consequence to the array itself or its algorithms. (4) Objects require index keys to locate them within the array. (5) Index keys must be unique. Inserting an object with the same key as one already in the array will replace the old object. (6) Index keys can be of any length and can be of different lengths. (7) Index keys should encode the length early on, before any variation due to length is seen. (8) Index keys can include a hash to scatter objects throughout the array. (9) The array can iterated over. The objects will not necessarily come out in key order. (10) The array can be iterated whilst it is being modified, provided the RCU readlock is being held by the iterator. Note, however, under these circumstances, some objects may be seen more than once. If this is a problem, the iterator should lock against modification. Objects will not be missed, however, unless deleted. (11) Objects in the array can be looked up by means of their index key. (12) Objects can be looked up whilst the array is being modified, provided the RCU readlock is being held by the thread doing the look up. The implementation uses a tree of 16-pointer nodes internally that are indexed on each level by nibbles from the index key. To improve memory efficiency, shortcuts can be emplaced to skip over what would otherwise be a series of single-occupancy nodes. Further, nodes pack leaf object pointers into spare space in the node rather than making an extra branch until as such time an object needs to be added to a full node. Signed-off-by: David Howells <dhowells@redhat.com>
93 lines
3 KiB
C
93 lines
3 KiB
C
/* Generic associative array implementation.
|
|
*
|
|
* See Documentation/assoc_array.txt for information.
|
|
*
|
|
* Copyright (C) 2013 Red Hat, Inc. All Rights Reserved.
|
|
* Written by David Howells (dhowells@redhat.com)
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public Licence
|
|
* as published by the Free Software Foundation; either version
|
|
* 2 of the Licence, or (at your option) any later version.
|
|
*/
|
|
|
|
#ifndef _LINUX_ASSOC_ARRAY_H
|
|
#define _LINUX_ASSOC_ARRAY_H
|
|
|
|
#ifdef CONFIG_ASSOCIATIVE_ARRAY
|
|
|
|
#include <linux/types.h>
|
|
|
|
#define ASSOC_ARRAY_KEY_CHUNK_SIZE BITS_PER_LONG /* Key data retrieved in chunks of this size */
|
|
|
|
/*
|
|
* Generic associative array.
|
|
*/
|
|
struct assoc_array {
|
|
struct assoc_array_ptr *root; /* The node at the root of the tree */
|
|
unsigned long nr_leaves_on_tree;
|
|
};
|
|
|
|
/*
|
|
* Operations on objects and index keys for use by array manipulation routines.
|
|
*/
|
|
struct assoc_array_ops {
|
|
/* Method to get a chunk of an index key from caller-supplied data */
|
|
unsigned long (*get_key_chunk)(const void *index_key, int level);
|
|
|
|
/* Method to get a piece of an object's index key */
|
|
unsigned long (*get_object_key_chunk)(const void *object, int level);
|
|
|
|
/* Is this the object we're looking for? */
|
|
bool (*compare_object)(const void *object, const void *index_key);
|
|
|
|
/* How different are two objects, to a bit position in their keys? (or
|
|
* -1 if they're the same)
|
|
*/
|
|
int (*diff_objects)(const void *a, const void *b);
|
|
|
|
/* Method to free an object. */
|
|
void (*free_object)(void *object);
|
|
};
|
|
|
|
/*
|
|
* Access and manipulation functions.
|
|
*/
|
|
struct assoc_array_edit;
|
|
|
|
static inline void assoc_array_init(struct assoc_array *array)
|
|
{
|
|
array->root = NULL;
|
|
array->nr_leaves_on_tree = 0;
|
|
}
|
|
|
|
extern int assoc_array_iterate(const struct assoc_array *array,
|
|
int (*iterator)(const void *object,
|
|
void *iterator_data),
|
|
void *iterator_data);
|
|
extern void *assoc_array_find(const struct assoc_array *array,
|
|
const struct assoc_array_ops *ops,
|
|
const void *index_key);
|
|
extern void assoc_array_destroy(struct assoc_array *array,
|
|
const struct assoc_array_ops *ops);
|
|
extern struct assoc_array_edit *assoc_array_insert(struct assoc_array *array,
|
|
const struct assoc_array_ops *ops,
|
|
const void *index_key,
|
|
void *object);
|
|
extern void assoc_array_insert_set_object(struct assoc_array_edit *edit,
|
|
void *object);
|
|
extern struct assoc_array_edit *assoc_array_delete(struct assoc_array *array,
|
|
const struct assoc_array_ops *ops,
|
|
const void *index_key);
|
|
extern struct assoc_array_edit *assoc_array_clear(struct assoc_array *array,
|
|
const struct assoc_array_ops *ops);
|
|
extern void assoc_array_apply_edit(struct assoc_array_edit *edit);
|
|
extern void assoc_array_cancel_edit(struct assoc_array_edit *edit);
|
|
extern int assoc_array_gc(struct assoc_array *array,
|
|
const struct assoc_array_ops *ops,
|
|
bool (*iterator)(void *object, void *iterator_data),
|
|
void *iterator_data);
|
|
|
|
#endif /* CONFIG_ASSOCIATIVE_ARRAY */
|
|
#endif /* _LINUX_ASSOC_ARRAY_H */
|