OLD | NEW |
1 =pod | 1 =pod |
2 | 2 |
3 =head1 NAME | 3 =head1 NAME |
4 | 4 |
5 lh_new, lh_free, lh_insert, lh_delete, lh_retrieve, lh_doall, lh_doall_arg, lh_e
rror - dynamic hash table | 5 lh_new, lh_free, lh_insert, lh_delete, lh_retrieve, lh_doall, lh_doall_arg, lh_e
rror - dynamic hash table |
6 | 6 |
7 =head1 SYNOPSIS | 7 =head1 SYNOPSIS |
8 | 8 |
9 #include <openssl/lhash.h> | 9 #include <openssl/lhash.h> |
10 | 10 |
11 LHASH *lh_new(LHASH_HASH_FN_TYPE hash, LHASH_COMP_FN_TYPE compare); | 11 DECLARE_LHASH_OF(<type>); |
12 void lh_free(LHASH *table); | |
13 | 12 |
14 void *lh_insert(LHASH *table, void *data); | 13 LHASH *lh_<type>_new(); |
15 void *lh_delete(LHASH *table, void *data); | 14 void lh_<type>_free(LHASH_OF(<type> *table); |
16 void *lh_retrieve(LHASH *table, void *data); | |
17 | 15 |
18 void lh_doall(LHASH *table, LHASH_DOALL_FN_TYPE func); | 16 <type> *lh_<type>_insert(LHASH_OF(<type> *table, <type> *data); |
19 void lh_doall_arg(LHASH *table, LHASH_DOALL_ARG_FN_TYPE func, | 17 <type> *lh_<type>_delete(LHASH_OF(<type> *table, <type> *data); |
20 void *arg); | 18 <type> *lh_retrieve(LHASH_OF<type> *table, <type> *data); |
21 | 19 |
22 int lh_error(LHASH *table); | 20 void lh_<type>_doall(LHASH_OF(<type> *table, LHASH_DOALL_FN_TYPE func); |
| 21 void lh_<type>_doall_arg(LHASH_OF(<type> *table, LHASH_DOALL_ARG_FN_TYPE func, |
| 22 <type2>, <type2> *arg); |
| 23 |
| 24 int lh_<type>_error(LHASH_OF(<type> *table); |
23 | 25 |
24 typedef int (*LHASH_COMP_FN_TYPE)(const void *, const void *); | 26 typedef int (*LHASH_COMP_FN_TYPE)(const void *, const void *); |
25 typedef unsigned long (*LHASH_HASH_FN_TYPE)(const void *); | 27 typedef unsigned long (*LHASH_HASH_FN_TYPE)(const void *); |
26 typedef void (*LHASH_DOALL_FN_TYPE)(const void *); | 28 typedef void (*LHASH_DOALL_FN_TYPE)(const void *); |
27 typedef void (*LHASH_DOALL_ARG_FN_TYPE)(const void *, const void *); | 29 typedef void (*LHASH_DOALL_ARG_FN_TYPE)(const void *, const void *); |
28 | 30 |
29 =head1 DESCRIPTION | 31 =head1 DESCRIPTION |
30 | 32 |
31 This library implements dynamic hash tables. The hash table entries | 33 This library implements type-checked dynamic hash tables. The hash |
32 can be arbitrary structures. Usually they consist of key and value | 34 table entries can be arbitrary structures. Usually they consist of key |
33 fields. | 35 and value fields. |
34 | 36 |
35 lh_new() creates a new B<LHASH> structure to store arbitrary data | 37 lh_<type>_new() creates a new B<LHASH_OF(<type>> structure to store |
36 entries, and provides the 'hash' and 'compare' callbacks to be used in | 38 arbitrary data entries, and provides the 'hash' and 'compare' |
37 organising the table's entries. The B<hash> callback takes a pointer | 39 callbacks to be used in organising the table's entries. The B<hash> |
38 to a table entry as its argument and returns an unsigned long hash | 40 callback takes a pointer to a table entry as its argument and returns |
39 value for its key field. The hash value is normally truncated to a | 41 an unsigned long hash value for its key field. The hash value is |
40 power of 2, so make sure that your hash function returns well mixed | 42 normally truncated to a power of 2, so make sure that your hash |
41 low order bits. The B<compare> callback takes two arguments (pointers | 43 function returns well mixed low order bits. The B<compare> callback |
42 to two hash table entries), and returns 0 if their keys are equal, | 44 takes two arguments (pointers to two hash table entries), and returns |
43 non-zero otherwise. If your hash table will contain items of some | 45 0 if their keys are equal, non-zero otherwise. If your hash table |
44 particular type and the B<hash> and B<compare> callbacks hash/compare | 46 will contain items of some particular type and the B<hash> and |
45 these types, then the B<DECLARE_LHASH_HASH_FN> and | 47 B<compare> callbacks hash/compare these types, then the |
46 B<IMPLEMENT_LHASH_COMP_FN> macros can be used to create callback | 48 B<DECLARE_LHASH_HASH_FN> and B<IMPLEMENT_LHASH_COMP_FN> macros can be |
47 wrappers of the prototypes required by lh_new(). These provide | 49 used to create callback wrappers of the prototypes required by |
48 per-variable casts before calling the type-specific callbacks written | 50 lh_<type>_new(). These provide per-variable casts before calling the |
49 by the application author. These macros, as well as those used for | 51 type-specific callbacks written by the application author. These |
50 the "doall" callbacks, are defined as; | 52 macros, as well as those used for the "doall" callbacks, are defined |
| 53 as; |
51 | 54 |
52 #define DECLARE_LHASH_HASH_FN(f_name,o_type) \ | 55 #define DECLARE_LHASH_HASH_FN(name, o_type) \ |
53 unsigned long f_name##_LHASH_HASH(const void *); | 56 » unsigned long name##_LHASH_HASH(const void *); |
54 #define IMPLEMENT_LHASH_HASH_FN(f_name,o_type) \ | 57 #define IMPLEMENT_LHASH_HASH_FN(name, o_type) \ |
55 unsigned long f_name##_LHASH_HASH(const void *arg) { \ | 58 » unsigned long name##_LHASH_HASH(const void *arg) { \ |
56 o_type a = (o_type)arg; \ | 59 » » const o_type *a = arg; \ |
57 return f_name(a); } | 60 » » return name##_hash(a); } |
58 #define LHASH_HASH_FN(f_name) f_name##_LHASH_HASH | 61 #define LHASH_HASH_FN(name) name##_LHASH_HASH |
59 | 62 |
60 #define DECLARE_LHASH_COMP_FN(f_name,o_type) \ | 63 #define DECLARE_LHASH_COMP_FN(name, o_type) \ |
61 int f_name##_LHASH_COMP(const void *, const void *); | 64 » int name##_LHASH_COMP(const void *, const void *); |
62 #define IMPLEMENT_LHASH_COMP_FN(f_name,o_type) \ | 65 #define IMPLEMENT_LHASH_COMP_FN(name, o_type) \ |
63 int f_name##_LHASH_COMP(const void *arg1, const void *arg2) { \ | 66 » int name##_LHASH_COMP(const void *arg1, const void *arg2) { \ |
64 o_type a = (o_type)arg1; \ | 67 » » const o_type *a = arg1;» » \ |
65 o_type b = (o_type)arg2; \ | 68 » » const o_type *b = arg2; \ |
66 return f_name(a,b); } | 69 » » return name##_cmp(a,b); } |
67 #define LHASH_COMP_FN(f_name) f_name##_LHASH_COMP | 70 #define LHASH_COMP_FN(name) name##_LHASH_COMP |
68 | 71 |
69 #define DECLARE_LHASH_DOALL_FN(f_name,o_type) \ | 72 #define DECLARE_LHASH_DOALL_FN(name, o_type) \ |
70 void f_name##_LHASH_DOALL(const void *); | 73 » void name##_LHASH_DOALL(void *); |
71 #define IMPLEMENT_LHASH_DOALL_FN(f_name,o_type) \ | 74 #define IMPLEMENT_LHASH_DOALL_FN(name, o_type) \ |
72 void f_name##_LHASH_DOALL(const void *arg) { \ | 75 » void name##_LHASH_DOALL(void *arg) { \ |
73 o_type a = (o_type)arg; \ | 76 » » o_type *a = arg; \ |
74 f_name(a); } | 77 » » name##_doall(a); } |
75 #define LHASH_DOALL_FN(f_name) f_name##_LHASH_DOALL | 78 #define LHASH_DOALL_FN(name) name##_LHASH_DOALL |
76 | 79 |
77 #define DECLARE_LHASH_DOALL_ARG_FN(f_name,o_type,a_type) \ | 80 #define DECLARE_LHASH_DOALL_ARG_FN(name, o_type, a_type) \ |
78 void f_name##_LHASH_DOALL_ARG(const void *, const void *); | 81 » void name##_LHASH_DOALL_ARG(void *, void *); |
79 #define IMPLEMENT_LHASH_DOALL_ARG_FN(f_name,o_type,a_type) \ | 82 #define IMPLEMENT_LHASH_DOALL_ARG_FN(name, o_type, a_type) \ |
80 void f_name##_LHASH_DOALL_ARG(const void *arg1, const void *arg2) { \ | 83 » void name##_LHASH_DOALL_ARG(void *arg1, void *arg2) { \ |
81 o_type a = (o_type)arg1; \ | 84 » » o_type *a = arg1; \ |
82 a_type b = (a_type)arg2; \ | 85 » » a_type *b = arg2; \ |
83 f_name(a,b); } | 86 » » name##_doall_arg(a, b); } |
84 #define LHASH_DOALL_ARG_FN(f_name) f_name##_LHASH_DOALL_ARG | 87 #define LHASH_DOALL_ARG_FN(name) name##_LHASH_DOALL_ARG |
85 | 88 |
86 An example of a hash table storing (pointers to) structures of type 'STUFF' | 89 An example of a hash table storing (pointers to) structures of type 'STUFF' |
87 could be defined as follows; | 90 could be defined as follows; |
88 | 91 |
89 /* Calculates the hash value of 'tohash' (implemented elsewhere) */ | 92 /* Calculates the hash value of 'tohash' (implemented elsewhere) */ |
90 unsigned long STUFF_hash(const STUFF *tohash); | 93 unsigned long STUFF_hash(const STUFF *tohash); |
91 /* Orders 'arg1' and 'arg2' (implemented elsewhere) */ | 94 /* Orders 'arg1' and 'arg2' (implemented elsewhere) */ |
92 int STUFF_cmp(const STUFF *arg1, const STUFF *arg2); | 95 int stuff_cmp(const STUFF *arg1, const STUFF *arg2); |
93 /* Create the type-safe wrapper functions for use in the LHASH internals */ | 96 /* Create the type-safe wrapper functions for use in the LHASH internals */ |
94 static IMPLEMENT_LHASH_HASH_FN(STUFF_hash, const STUFF *) | 97 static IMPLEMENT_LHASH_HASH_FN(stuff, STUFF); |
95 static IMPLEMENT_LHASH_COMP_FN(STUFF_cmp, const STUFF *); | 98 static IMPLEMENT_LHASH_COMP_FN(stuff, STUFF); |
96 /* ... */ | 99 /* ... */ |
97 int main(int argc, char *argv[]) { | 100 int main(int argc, char *argv[]) { |
98 /* Create the new hash table using the hash/compare wrappers */ | 101 /* Create the new hash table using the hash/compare wrappers */ |
99 LHASH *hashtable = lh_new(LHASH_HASH_FN(STUFF_hash), | 102 LHASH_OF(STUFF) *hashtable = lh_STUFF_new(LHASH_HASH_FN(STUFF_hash), |
100 LHASH_COMP_FN(STUFF_cmp)); | 103 LHASH_COMP_FN(STUFF_cmp)); |
101 /* ... */ | 104 /* ... */ |
102 } | 105 } |
103 | 106 |
104 lh_free() frees the B<LHASH> structure B<table>. Allocated hash table | 107 lh_<type>_free() frees the B<LHASH_OF(<type>> structure |
105 entries will not be freed; consider using lh_doall() to deallocate any | 108 B<table>. Allocated hash table entries will not be freed; consider |
106 remaining entries in the hash table (see below). | 109 using lh_<type>_doall() to deallocate any remaining entries in the |
| 110 hash table (see below). |
107 | 111 |
108 lh_insert() inserts the structure pointed to by B<data> into B<table>. | 112 lh_<type>_insert() inserts the structure pointed to by B<data> into |
109 If there already is an entry with the same key, the old value is | 113 B<table>. If there already is an entry with the same key, the old |
110 replaced. Note that lh_insert() stores pointers, the data are not | 114 value is replaced. Note that lh_<type>_insert() stores pointers, the |
111 copied. | 115 data are not copied. |
112 | 116 |
113 lh_delete() deletes an entry from B<table>. | 117 lh_<type>_delete() deletes an entry from B<table>. |
114 | 118 |
115 lh_retrieve() looks up an entry in B<table>. Normally, B<data> is | 119 lh_<type>_retrieve() looks up an entry in B<table>. Normally, B<data> |
116 a structure with the key field(s) set; the function will return a | 120 is a structure with the key field(s) set; the function will return a |
117 pointer to a fully populated structure. | 121 pointer to a fully populated structure. |
118 | 122 |
119 lh_doall() will, for every entry in the hash table, call B<func> with | 123 lh_<type>_doall() will, for every entry in the hash table, call |
120 the data item as its parameter. For lh_doall() and lh_doall_arg(), | 124 B<func> with the data item as its parameter. For lh_<type>_doall() |
121 function pointer casting should be avoided in the callbacks (see | 125 and lh_<type>_doall_arg(), function pointer casting should be avoided |
122 B<NOTE>) - instead, either declare the callbacks to match the | 126 in the callbacks (see B<NOTE>) - instead use the declare/implement |
123 prototype required in lh_new() or use the declare/implement macros to | 127 macros to create type-checked wrappers that cast variables prior to |
124 create type-safe wrappers that cast variables prior to calling your | 128 calling your type-specific callbacks. An example of this is |
125 type-specific callbacks. An example of this is illustrated here where | 129 illustrated here where the callback is used to cleanup resources for |
126 the callback is used to cleanup resources for items in the hash table | 130 items in the hash table prior to the hashtable itself being |
127 prior to the hashtable itself being deallocated: | 131 deallocated: |
128 | 132 |
129 /* Cleans up resources belonging to 'a' (this is implemented elsewhere) */ | 133 /* Cleans up resources belonging to 'a' (this is implemented elsewhere) */ |
130 void STUFF_cleanup(STUFF *a); | 134 void STUFF_cleanup_doall(STUFF *a); |
131 /* Implement a prototype-compatible wrapper for "STUFF_cleanup" */ | 135 /* Implement a prototype-compatible wrapper for "STUFF_cleanup" */ |
132 IMPLEMENT_LHASH_DOALL_FN(STUFF_cleanup, STUFF *) | 136 IMPLEMENT_LHASH_DOALL_FN(STUFF_cleanup, STUFF) |
133 /* ... then later in the code ... */ | 137 /* ... then later in the code ... */ |
134 /* So to run "STUFF_cleanup" against all items in a hash table ... */ | 138 /* So to run "STUFF_cleanup" against all items in a hash table ... */ |
135 lh_doall(hashtable, LHASH_DOALL_FN(STUFF_cleanup)); | 139 lh_STUFF_doall(hashtable, LHASH_DOALL_FN(STUFF_cleanup)); |
136 /* Then the hash table itself can be deallocated */ | 140 /* Then the hash table itself can be deallocated */ |
137 lh_free(hashtable); | 141 lh_STUFF_free(hashtable); |
138 | 142 |
139 When doing this, be careful if you delete entries from the hash table | 143 When doing this, be careful if you delete entries from the hash table |
140 in your callbacks: the table may decrease in size, moving the item | 144 in your callbacks: the table may decrease in size, moving the item |
141 that you are currently on down lower in the hash table - this could | 145 that you are currently on down lower in the hash table - this could |
142 cause some entries to be skipped during the iteration. The second | 146 cause some entries to be skipped during the iteration. The second |
143 best solution to this problem is to set hash-E<gt>down_load=0 before | 147 best solution to this problem is to set hash-E<gt>down_load=0 before |
144 you start (which will stop the hash table ever decreasing in size). | 148 you start (which will stop the hash table ever decreasing in size). |
145 The best solution is probably to avoid deleting items from the hash | 149 The best solution is probably to avoid deleting items from the hash |
146 table inside a "doall" callback! | 150 table inside a "doall" callback! |
147 | 151 |
148 lh_doall_arg() is the same as lh_doall() except that B<func> will be | 152 lh_<type>_doall_arg() is the same as lh_<type>_doall() except that |
149 called with B<arg> as the second argument and B<func> should be of | 153 B<func> will be called with B<arg> as the second argument and B<func> |
150 type B<LHASH_DOALL_ARG_FN_TYPE> (a callback prototype that is passed | 154 should be of type B<LHASH_DOALL_ARG_FN_TYPE> (a callback prototype |
151 both the table entry and an extra argument). As with lh_doall(), you | 155 that is passed both the table entry and an extra argument). As with |
152 can instead choose to declare your callback with a prototype matching | 156 lh_doall(), you can instead choose to declare your callback with a |
153 the types you are dealing with and use the declare/implement macros to | 157 prototype matching the types you are dealing with and use the |
154 create compatible wrappers that cast variables before calling your | 158 declare/implement macros to create compatible wrappers that cast |
155 type-specific callbacks. An example of this is demonstrated here | 159 variables before calling your type-specific callbacks. An example of |
156 (printing all hash table entries to a BIO that is provided by the | 160 this is demonstrated here (printing all hash table entries to a BIO |
157 caller): | 161 that is provided by the caller): |
158 | 162 |
159 /* Prints item 'a' to 'output_bio' (this is implemented elsewhere) */ | 163 /* Prints item 'a' to 'output_bio' (this is implemented elsewhere) */ |
160 void STUFF_print(const STUFF *a, BIO *output_bio); | 164 void STUFF_print_doall_arg(const STUFF *a, BIO *output_bio); |
161 /* Implement a prototype-compatible wrapper for "STUFF_print" */ | 165 /* Implement a prototype-compatible wrapper for "STUFF_print" */ |
162 static IMPLEMENT_LHASH_DOALL_ARG_FN(STUFF_print, const STUFF *, BIO *) | 166 static IMPLEMENT_LHASH_DOALL_ARG_FN(STUFF, const STUFF, BIO) |
163 /* ... then later in the code ... */ | 167 /* ... then later in the code ... */ |
164 /* Print out the entire hashtable to a particular BIO */ | 168 /* Print out the entire hashtable to a particular BIO */ |
165 lh_doall_arg(hashtable, LHASH_DOALL_ARG_FN(STUFF_print), logging_bio); | 169 lh_STUFF_doall_arg(hashtable, LHASH_DOALL_ARG_FN(STUFF_print), BIO, |
| 170 logging_bio); |
166 | 171 |
167 lh_error() can be used to determine if an error occurred in the last | 172 lh_<type>_error() can be used to determine if an error occurred in the last |
168 operation. lh_error() is a macro. | 173 operation. lh_<type>_error() is a macro. |
169 | 174 |
170 =head1 RETURN VALUES | 175 =head1 RETURN VALUES |
171 | 176 |
172 lh_new() returns B<NULL> on error, otherwise a pointer to the new | 177 lh_<type>_new() returns B<NULL> on error, otherwise a pointer to the new |
173 B<LHASH> structure. | 178 B<LHASH> structure. |
174 | 179 |
175 When a hash table entry is replaced, lh_insert() returns the value | 180 When a hash table entry is replaced, lh_<type>_insert() returns the value |
176 being replaced. B<NULL> is returned on normal operation and on error. | 181 being replaced. B<NULL> is returned on normal operation and on error. |
177 | 182 |
178 lh_delete() returns the entry being deleted. B<NULL> is returned if | 183 lh_<type>_delete() returns the entry being deleted. B<NULL> is returned if |
179 there is no such value in the hash table. | 184 there is no such value in the hash table. |
180 | 185 |
181 lh_retrieve() returns the hash table entry if it has been found, | 186 lh_<type>_retrieve() returns the hash table entry if it has been found, |
182 B<NULL> otherwise. | 187 B<NULL> otherwise. |
183 | 188 |
184 lh_error() returns 1 if an error occurred in the last operation, 0 | 189 lh_<type>_error() returns 1 if an error occurred in the last operation, 0 |
185 otherwise. | 190 otherwise. |
186 | 191 |
187 lh_free(), lh_doall() and lh_doall_arg() return no values. | 192 lh_<type>_free(), lh_<type>_doall() and lh_<type>_doall_arg() return no values. |
188 | 193 |
189 =head1 NOTE | 194 =head1 NOTE |
190 | 195 |
191 The various LHASH macros and callback types exist to make it possible | 196 The various LHASH macros and callback types exist to make it possible |
192 to write type-safe code without resorting to function-prototype | 197 to write type-checked code without resorting to function-prototype |
193 casting - an evil that makes application code much harder to | 198 casting - an evil that makes application code much harder to |
194 audit/verify and also opens the window of opportunity for stack | 199 audit/verify and also opens the window of opportunity for stack |
195 corruption and other hard-to-find bugs. It also, apparently, violates | 200 corruption and other hard-to-find bugs. It also, apparently, violates |
196 ANSI-C. | 201 ANSI-C. |
197 | 202 |
198 The LHASH code regards table entries as constant data. As such, it | 203 The LHASH code regards table entries as constant data. As such, it |
199 internally represents lh_insert()'d items with a "const void *" | 204 internally represents lh_insert()'d items with a "const void *" |
200 pointer type. This is why callbacks such as those used by lh_doall() | 205 pointer type. This is why callbacks such as those used by lh_doall() |
201 and lh_doall_arg() declare their prototypes with "const", even for the | 206 and lh_doall_arg() declare their prototypes with "const", even for the |
202 parameters that pass back the table items' data pointers - for | 207 parameters that pass back the table items' data pointers - for |
(...skipping 17 matching lines...) Expand all Loading... |
220 Callers that only have "const" access to data they're indexing in a | 225 Callers that only have "const" access to data they're indexing in a |
221 table, yet declare callbacks without constant types (or cast the | 226 table, yet declare callbacks without constant types (or cast the |
222 "const" away themselves), are therefore creating their own risks/bugs | 227 "const" away themselves), are therefore creating their own risks/bugs |
223 without being encouraged to do so by the API. On a related note, | 228 without being encouraged to do so by the API. On a related note, |
224 those auditing code should pay special attention to any instances of | 229 those auditing code should pay special attention to any instances of |
225 DECLARE/IMPLEMENT_LHASH_DOALL_[ARG_]_FN macros that provide types | 230 DECLARE/IMPLEMENT_LHASH_DOALL_[ARG_]_FN macros that provide types |
226 without any "const" qualifiers. | 231 without any "const" qualifiers. |
227 | 232 |
228 =head1 BUGS | 233 =head1 BUGS |
229 | 234 |
230 lh_insert() returns B<NULL> both for success and error. | 235 lh_<type>_insert() returns B<NULL> both for success and error. |
231 | 236 |
232 =head1 INTERNALS | 237 =head1 INTERNALS |
233 | 238 |
234 The following description is based on the SSLeay documentation: | 239 The following description is based on the SSLeay documentation: |
235 | 240 |
236 The B<lhash> library implements a hash table described in the | 241 The B<lhash> library implements a hash table described in the |
237 I<Communications of the ACM> in 1991. What makes this hash table | 242 I<Communications of the ACM> in 1991. What makes this hash table |
238 different is that as the table fills, the hash table is increased (or | 243 different is that as the table fills, the hash table is increased (or |
239 decreased) in size via OPENSSL_realloc(). When a 'resize' is done, instead of | 244 decreased) in size via OPENSSL_realloc(). When a 'resize' is done, instead of |
240 all hashes being redistributed over twice as many 'buckets', one | 245 all hashes being redistributed over twice as many 'buckets', one |
(...skipping 24 matching lines...) Expand all Loading... |
265 probably worth changing your hash function if this is the case because | 270 probably worth changing your hash function if this is the case because |
266 even if your hash table has 10 items in a 'bucket', it can be searched | 271 even if your hash table has 10 items in a 'bucket', it can be searched |
267 with 10 B<unsigned long> compares and 10 linked list traverses. This | 272 with 10 B<unsigned long> compares and 10 linked list traverses. This |
268 will be much less expensive that 10 calls to your compare function. | 273 will be much less expensive that 10 calls to your compare function. |
269 | 274 |
270 lh_strhash() is a demo string hashing function: | 275 lh_strhash() is a demo string hashing function: |
271 | 276 |
272 unsigned long lh_strhash(const char *c); | 277 unsigned long lh_strhash(const char *c); |
273 | 278 |
274 Since the B<LHASH> routines would normally be passed structures, this | 279 Since the B<LHASH> routines would normally be passed structures, this |
275 routine would not normally be passed to lh_new(), rather it would be | 280 routine would not normally be passed to lh_<type>_new(), rather it would be |
276 used in the function passed to lh_new(). | 281 used in the function passed to lh_<type>_new(). |
277 | 282 |
278 =head1 SEE ALSO | 283 =head1 SEE ALSO |
279 | 284 |
280 L<lh_stats(3)|lh_stats(3)> | 285 L<lh_stats(3)|lh_stats(3)> |
281 | 286 |
282 =head1 HISTORY | 287 =head1 HISTORY |
283 | 288 |
284 The B<lhash> library is available in all versions of SSLeay and OpenSSL. | 289 The B<lhash> library is available in all versions of SSLeay and OpenSSL. |
285 lh_error() was added in SSLeay 0.9.1b. | 290 lh_error() was added in SSLeay 0.9.1b. |
286 | 291 |
287 This manpage is derived from the SSLeay documentation. | 292 This manpage is derived from the SSLeay documentation. |
288 | 293 |
289 In OpenSSL 0.9.7, all lhash functions that were passed function pointers | 294 In OpenSSL 0.9.7, all lhash functions that were passed function pointers |
290 were changed for better type safety, and the function types LHASH_COMP_FN_TYPE, | 295 were changed for better type safety, and the function types LHASH_COMP_FN_TYPE, |
291 LHASH_HASH_FN_TYPE, LHASH_DOALL_FN_TYPE and LHASH_DOALL_ARG_FN_TYPE | 296 LHASH_HASH_FN_TYPE, LHASH_DOALL_FN_TYPE and LHASH_DOALL_ARG_FN_TYPE |
292 became available. | 297 became available. |
293 | 298 |
| 299 In OpenSSL 1.0.0, the lhash interface was revamped for even better |
| 300 type checking. |
| 301 |
294 =cut | 302 =cut |
OLD | NEW |