summaryrefslogtreecommitdiffstats
path: root/doc/crypto/OPENSSL_LH_COMPFUNC.pod
diff options
context:
space:
mode:
Diffstat (limited to 'doc/crypto/OPENSSL_LH_COMPFUNC.pod')
-rw-r--r--doc/crypto/OPENSSL_LH_COMPFUNC.pod135
1 files changed, 55 insertions, 80 deletions
diff --git a/doc/crypto/OPENSSL_LH_COMPFUNC.pod b/doc/crypto/OPENSSL_LH_COMPFUNC.pod
index 372f0d952c..e760ae3be7 100644
--- a/doc/crypto/OPENSSL_LH_COMPFUNC.pod
+++ b/doc/crypto/OPENSSL_LH_COMPFUNC.pod
@@ -5,6 +5,7 @@
DECLARE_LHASH_OF,
OPENSSL_LH_COMPFUNC, OPENSSL_LH_HASHFUNC, OPENSSL_LH_DOALL_FUNC,
LHASH_DOALL_ARG_FN_TYPE,
+IMPLEMENT_LHASH_HASH_FN, IMPLEMENT_LHASH_COMP_FN,
lh_TYPE_new, lh_TYPE_free,
lh_TYPE_insert, lh_TYPE_delete, lh_TYPE_retrieve,
lh_TYPE_doall, lh_TYPE_doall_arg, lh_TYPE_error - dynamic hash table
@@ -43,75 +44,52 @@ and value fields. In the description here, I<TYPE> is used a placeholder
for any of the OpenSSL datatypes, such as I<SSL_SESSION>.
lh_TYPE_new() creates a new B<LHASH_OF(TYPE)> structure to store
-arbitrary data entries, and provides the 'hash' and 'compare'
+arbitrary data entries, and specifies the 'hash' and 'compare'
callbacks to be used in organising the table's entries. The B<hash>
callback takes a pointer to a table entry as its argument and returns
an unsigned long hash value for its key field. The hash value is
normally truncated to a power of 2, so make sure that your hash
function returns well mixed low order bits. The B<compare> callback
takes two arguments (pointers to two hash table entries), and returns
-0 if their keys are equal, non-zero otherwise. If your hash table
+0 if their keys are equal, non-zero otherwise.
+
+If your hash table
will contain items of some particular type and the B<hash> and
B<compare> callbacks hash/compare these types, then the
-B<DECLARE_LHASH_HASH_FN> and B<IMPLEMENT_LHASH_COMP_FN> macros can be
+B<IMPLEMENT_LHASH_HASH_FN> and B<IMPLEMENT_LHASH_COMP_FN> macros can be
used to create callback wrappers of the prototypes required by
-lh_TYPE_new(). These provide per-variable casts before calling the
-type-specific callbacks written by the application author. These
-macros, as well as those used for the "doall" callbacks, are defined
-as;
-
- #define DECLARE_LHASH_HASH_FN(name, o_type) \
- unsigned long name##_LHASH_HASH(const void *);
- #define IMPLEMENT_LHASH_HASH_FN(name, o_type) \
- unsigned long name##_LHASH_HASH(const void *arg) { \
- const o_type *a = arg; \
- return name##_hash(a); }
- #define LHASH_HASH_FN(name) name##_LHASH_HASH
-
- #define DECLARE_LHASH_COMP_FN(name, o_type) \
- int name##_LHASH_COMP(const void *, const void *);
- #define IMPLEMENT_LHASH_COMP_FN(name, o_type) \
- int name##_LHASH_COMP(const void *arg1, const void *arg2) { \
- const o_type *a = arg1; \
- const o_type *b = arg2; \
- return name##_cmp(a,b); }
- #define LHASH_COMP_FN(name) name##_LHASH_COMP
-
- #define DECLARE_LHASH_DOALL_FN(name, o_type) \
- void name##_LHASH_DOALL(void *);
- #define IMPLEMENT_LHASH_DOALL_FN(name, o_type) \
- void name##_LHASH_DOALL(void *arg) { \
- o_type *a = arg; \
- name##_doall(a); }
- #define LHASH_DOALL_FN(name) name##_LHASH_DOALL
-
- #define DECLARE_LHASH_DOALL_ARG_FN(name, o_type, a_type) \
- void name##_LHASH_DOALL_ARG(void *, void *);
- #define IMPLEMENT_LHASH_DOALL_ARG_FN(name, o_type, a_type) \
- void name##_LHASH_DOALL_ARG(void *arg1, void *arg2) { \
- o_type *a = arg1; \
- a_type *b = arg2; \
- name##_doall_arg(a, b); }
- #define LHASH_DOALL_ARG_FN(name) name##_LHASH_DOALL_ARG
-
- An example of a hash table storing (pointers to) structures of type 'STUFF'
- could be defined as follows;
-
- /* Calculates the hash value of 'tohash' (implemented elsewhere) */
- unsigned long STUFF_hash(const STUFF *tohash);
- /* Orders 'arg1' and 'arg2' (implemented elsewhere) */
- int stuff_cmp(const STUFF *arg1, const STUFF *arg2);
- /* Create the type-safe wrapper functions for use in the LHASH internals */
- static IMPLEMENT_LHASH_HASH_FN(stuff, STUFF);
- static IMPLEMENT_LHASH_COMP_FN(stuff, STUFF);
- /* ... */
- int main(int argc, char *argv[]) {
- /* Create the new hash table using the hash/compare wrappers */
- LHASH_OF(STUFF) *hashtable = lh_STUFF_new(LHASH_HASH_FN(STUFF_hash),
- LHASH_COMP_FN(STUFF_cmp));
- /* ... */
+lh_TYPE_new() as shown in this example:
+
+ /*
+ * Implement the hash and compare functions; "stuff" can be any word.
+ */
+ static unsigned long stuff_hash(const TYPE *a)
+ {
+ ...
+ }
+ static int stuff_cmp(const TYPE *a, const TYPE *b)
+ {
+ ...
}
+ /*
+ * Implement the wrapper functions.
+ */
+ static IMPLEMENT_LHASH_HASH_FN(stuff, TYPE)
+ static IMPLEMENT_LHASH_COMP_FN(stuff, TYPE)
+
+If the type is going to be used in several places, the following macros
+can be used in a common header file to declare the function wrappers:
+
+ DECLARE_LHASH_HASH_FN(stuff, TYPE)
+ DECLARE_LHASH_COMP_FN(stuff, TYPE)
+
+Then a hash table of TYPE objects can be created using this:
+
+ LHASH_OF(TYPE) *htable;
+
+ htable = lh_TYPE_new(LHASH_HASH_FN(stuff), LHASH_COMP_FN(stuff));
+
lh_TYPE_free() frees the B<LHASH_OF(TYPE)> structure
B<table>. Allocated hash table entries will not be freed; consider
using lh_TYPE_doall() to deallocate any remaining entries in the
@@ -129,24 +107,20 @@ is a structure with the key field(s) set; the function will return a
pointer to a fully populated structure.
lh_TYPE_doall() will, for every entry in the hash table, call
-B<func> with the data item as its parameter. For lh_TYPE_doall()
-and lh_TYPE_doall_arg(), function pointer casting should be avoided
-in the callbacks (see B<NOTE>) - instead use the declare/implement
-macros to create type-checked wrappers that cast variables prior to
-calling your type-specific callbacks. An example of this is
-illustrated here where the callback is used to cleanup resources for
-items in the hash table prior to the hashtable itself being
-deallocated:
+B<func> with the data item as its parameter.
+For example:
/* Cleans up resources belonging to 'a' (this is implemented elsewhere) */
- void STUFF_cleanup_doall(STUFF *a);
- /* Implement a prototype-compatible wrapper for "STUFF_cleanup" */
- IMPLEMENT_LHASH_DOALL_FN(STUFF_cleanup, STUFF)
- /* ... then later in the code ... */
- /* So to run "STUFF_cleanup" against all items in a hash table ... */
- lh_STUFF_doall(hashtable, LHASH_DOALL_FN(STUFF_cleanup));
+ void TYPE_cleanup_doall(TYPE *a);
+
+ /* Implement a prototype-compatible wrapper for "TYPE_cleanup" */
+ IMPLEMENT_LHASH_DOALL_FN(TYPE_cleanup, TYPE)
+
+ /* Call "TYPE_cleanup" against all items in a hash table. */
+ lh_TYPE_doall(hashtable, LHASH_DOALL_FN(TYPE_cleanup));
+
/* Then the hash table itself can be deallocated */
- lh_STUFF_free(hashtable);
+ lh_TYPE_free(hashtable);
When doing this, be careful if you delete entries from the hash table
in your callbacks: the table may decrease in size, moving the item
@@ -169,13 +143,14 @@ this is demonstrated here (printing all hash table entries to a BIO
that is provided by the caller):
/* Prints item 'a' to 'output_bio' (this is implemented elsewhere) */
- void STUFF_print_doall_arg(const STUFF *a, BIO *output_bio);
- /* Implement a prototype-compatible wrapper for "STUFF_print" */
- static IMPLEMENT_LHASH_DOALL_ARG_FN(STUFF, const STUFF, BIO)
- /* ... then later in the code ... */
+ void TYPE_print_doall_arg(const TYPE *a, BIO *output_bio);
+
+ /* Implement a prototype-compatible wrapper for "TYPE_print" */
+ static IMPLEMENT_LHASH_DOALL_ARG_FN(TYPE, const TYPE, BIO)
+
/* Print out the entire hashtable to a particular BIO */
- lh_STUFF_doall_arg(hashtable, LHASH_DOALL_ARG_FN(STUFF_print), BIO,
- logging_bio);
+ lh_TYPE_doall_arg(hashtable, LHASH_DOALL_ARG_FN(TYPE_print), BIO,
+ logging_bio);
lh_TYPE_error() can be used to determine if an error occurred in the last
@@ -226,7 +201,7 @@ elsewhere in their code) - in this case the LHASH prototypes are
appropriate as-is. Conversely, if the caller is responsible for the
life-time of the data in question, then they may well wish to make
modifications to table item passed back in the lh_doall() or
-lh_doall_arg() callbacks (see the "STUFF_cleanup" example above). If
+lh_doall_arg() callbacks (see the "TYPE_cleanup" example above). If
so, the caller can either cast the "const" away (if they're providing
the raw callbacks themselves) or use the macros to declare/implement
the wrapper functions without "const" types.