Juan Cespedes | cac15c3 | 2003-01-31 18:58:58 +0100 | [diff] [blame] | 1 | /* |
Petr Machata | a11cbed | 2012-05-05 00:07:38 +0200 | [diff] [blame] | 2 | * This file is part of ltrace. |
Petr Machata | 98ff309 | 2013-03-08 22:11:36 +0100 | [diff] [blame] | 3 | * Copyright (C) 2012, 2013 Petr Machata, Red Hat Inc. |
Petr Machata | a11cbed | 2012-05-05 00:07:38 +0200 | [diff] [blame] | 4 | * |
| 5 | * This program is free software; you can redistribute it and/or |
| 6 | * modify it under the terms of the GNU General Public License as |
| 7 | * published by the Free Software Foundation; either version 2 of the |
| 8 | * License, or (at your option) any later version. |
| 9 | * |
| 10 | * This program is distributed in the hope that it will be useful, but |
| 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of |
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 13 | * General Public License for more details. |
| 14 | * |
| 15 | * You should have received a copy of the GNU General Public License |
| 16 | * along with this program; if not, write to the Free Software |
| 17 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA |
| 18 | * 02110-1301 USA |
| 19 | */ |
| 20 | |
| 21 | #ifndef _DICT_H_ |
| 22 | #define _DICT_H_ |
| 23 | |
Petr Machata | d7e4ca8 | 2012-11-28 03:38:47 +0100 | [diff] [blame] | 24 | #include <stddef.h> |
| 25 | #include <assert.h> |
| 26 | #include "vect.h" |
Juan Cespedes | cac15c3 | 2003-01-31 18:58:58 +0100 | [diff] [blame] | 27 | |
Petr Machata | d7e4ca8 | 2012-11-28 03:38:47 +0100 | [diff] [blame] | 28 | struct dict { |
| 29 | /* The invariant is that KEYS, VALUES and STATUS are of the |
| 30 | * same size. */ |
| 31 | struct vect keys; |
| 32 | struct vect values; |
| 33 | struct vect status; |
| 34 | size_t size; |
Juan Cespedes | cac15c3 | 2003-01-31 18:58:58 +0100 | [diff] [blame] | 35 | |
Petr Machata | d7e4ca8 | 2012-11-28 03:38:47 +0100 | [diff] [blame] | 36 | size_t (*hash1)(const void *); |
| 37 | int (*eq)(const void *, const void *); |
| 38 | size_t (*hash2)(size_t); |
| 39 | }; |
Juan Cespedes | cac15c3 | 2003-01-31 18:58:58 +0100 | [diff] [blame] | 40 | |
Petr Machata | d7e4ca8 | 2012-11-28 03:38:47 +0100 | [diff] [blame] | 41 | /* Initialize a dictionary DICT. The dictionary will hold keys of the |
| 42 | * size KEY_SIZE and values of the size VALUE_SIZE. HASH1 and HASH2 |
| 43 | * are, respectively, primary and secondary hashing functions. The |
| 44 | * latter may be NULL, in which case a default internal hash is used. |
| 45 | * EQ is a callback for comparing two keys. */ |
| 46 | void dict_init(struct dict *dict, |
| 47 | size_t key_size, size_t value_size, |
| 48 | size_t (*hash1)(const void *), |
| 49 | int (*eq)(const void *, const void *), |
| 50 | size_t (*hash2)(size_t)); |
Petr Machata | 345c9b5 | 2012-02-10 13:10:03 +0100 | [diff] [blame] | 51 | |
Petr Machata | d7e4ca8 | 2012-11-28 03:38:47 +0100 | [diff] [blame] | 52 | /* Wrapper around dict_init. Initializes a dictionary DITCP which |
| 53 | * will hold keys of type KEY_TYPE and values of type VALUE_TYPE. |
| 54 | * Other arguments as above. */ |
| 55 | #define DICT_INIT(DICTP, KEY_TYPE, VALUE_TYPE, HASH1, EQ, HASH2) \ |
| 56 | ({ \ |
| 57 | /* Check that callbacks are typed properly. */ \ |
| 58 | size_t (*_hash1_callback)(const KEY_TYPE *) = HASH1; \ |
| 59 | int (*_eq_callback)(const KEY_TYPE *, const KEY_TYPE *) = EQ; \ |
| 60 | dict_init(DICTP, sizeof(KEY_TYPE), sizeof(VALUE_TYPE), \ |
| 61 | (size_t (*)(const void *))_hash1_callback, \ |
| 62 | (int (*)(const void *, const void *))_eq_callback, \ |
| 63 | HASH2); \ |
| 64 | }) |
Petr Machata | 345c9b5 | 2012-02-10 13:10:03 +0100 | [diff] [blame] | 65 | |
Petr Machata | d7e4ca8 | 2012-11-28 03:38:47 +0100 | [diff] [blame] | 66 | /* Clone SOURCE to TARGET. For cloning slots, CLONE_KEY and |
| 67 | * CLONE_VALUE are called. These callbacks return 0 on success or a |
| 68 | * negative value on failure. If any of the callbacks is NULL, the |
| 69 | * default action is simple memmove. Returns 0 on success. If the |
| 70 | * cloning fails for any reason, already-cloned keys and values are |
| 71 | * destroyed again by DTOR_KEY and DTOR_VALUE callbacks (if non-NULL), |
| 72 | * and the function returns a negative value. DATA is passed to all |
| 73 | * callbacks verbatim. */ |
| 74 | int dict_clone(struct dict *target, const struct dict *source, |
| 75 | int (*clone_key)(void *tgt, const void *src, void *data), |
| 76 | void (*dtor_key)(void *tgt, void *data), |
| 77 | int (*clone_value)(void *tgt, const void *src, void *data), |
| 78 | void (*dtor_value)(void *tgt, void *data), |
| 79 | void *data); |
| 80 | |
| 81 | /* Clone SRC_DICTP, which holds KEY_TYPE-VALUE_TYPE pairs, into |
| 82 | * TGT_DICTP. Other arguments and return codes as above. */ |
| 83 | #define DICT_CLONE(TGT_DICTP, SRC_DICTP, KEY_TYPE, VALUE_TYPE, \ |
| 84 | CLONE_KEY, DTOR_KEY, CLONE_VALUE, DTOR_VALUE, DATA) \ |
| 85 | /* xxx GCC-ism necessary to get in the safety latches. */ \ |
| 86 | ({ \ |
| 87 | const struct dict *_source_d = (SRC_DICTP); \ |
| 88 | assert(_source_d->keys.elt_size == sizeof(KEY_TYPE)); \ |
| 89 | assert(_source_d->values.elt_size == sizeof(VALUE_TYPE)); \ |
| 90 | /* Check that callbacks are typed properly. */ \ |
| 91 | void (*_key_dtor_cb)(KEY_TYPE *, void *) = DTOR_KEY; \ |
| 92 | int (*_key_clone_cb)(KEY_TYPE *, const KEY_TYPE *, \ |
| 93 | void *) = CLONE_KEY; \ |
| 94 | void (*_value_dtor_cb)(VALUE_TYPE *, void *) = DTOR_VALUE; \ |
| 95 | int (*_value_clone_cb)(VALUE_TYPE *, const VALUE_TYPE *, \ |
| 96 | void *) = CLONE_VALUE; \ |
| 97 | dict_clone((TGT_DICTP), _source_d, \ |
| 98 | (int (*)(void *, const void *, \ |
| 99 | void *))_key_clone_cb, \ |
| 100 | (void (*)(void *, void *))_key_dtor_cb, \ |
| 101 | (int (*)(void *, const void *, \ |
| 102 | void *))_value_clone_cb, \ |
| 103 | (void (*)(void *, void *))_value_dtor_cb, \ |
| 104 | (DATA)); \ |
| 105 | }) |
| 106 | |
| 107 | /* Return number of key-value pairs stored in DICT. */ |
| 108 | size_t dict_size(const struct dict *dict); |
| 109 | |
| 110 | /* Emptiness predicate. */ |
| 111 | int dict_empty(const struct dict *dict); |
| 112 | |
| 113 | /* Insert into DICT a pair of KEY and VALUE. Returns 0 if insertion |
| 114 | * was successful, a negative value on error, or a positive value if |
| 115 | * this key is already present in the table. */ |
| 116 | int dict_insert(struct dict *dict, void *key, void *value); |
| 117 | |
| 118 | /* Insert into DICT a pair of KEY and VALUE. See dict_insert for |
| 119 | * details. In addition, make a check whether DICTP holds elements of |
| 120 | * the right size. */ |
| 121 | #define DICT_INSERT(DICTP, KEYP, VALUEP) \ |
| 122 | (assert((DICTP)->keys.elt_size == sizeof(*(KEYP))), \ |
| 123 | assert((DICTP)->values.elt_size == sizeof(*(VALUEP))), \ |
| 124 | dict_insert((DICTP), (KEYP), (VALUEP))) |
| 125 | |
| 126 | /* Find in DICT a value corresponding to KEY and return a pointer to |
| 127 | * it. Returns NULL if the key was not found. */ |
| 128 | void *dict_find(struct dict *dict, const void *key); |
| 129 | |
Petr Machata | 3d532ac | 2013-03-08 23:57:30 +0100 | [diff] [blame] | 130 | /* Look into DICTP for a key *KEYP. Return a boolean indicating |
| 131 | * whether the key was found. */ |
Petr Machata | 98ff309 | 2013-03-08 22:11:36 +0100 | [diff] [blame] | 132 | #define DICT_HAS_KEY(DICTP, KEYP) \ |
| 133 | (assert((DICTP)->keys.elt_size == sizeof(*(KEYP))), \ |
| 134 | dict_find((DICTP), (KEYP)) != NULL) |
| 135 | |
Petr Machata | d7e4ca8 | 2012-11-28 03:38:47 +0100 | [diff] [blame] | 136 | /* Find in DICTP a value of type VALUE_TYPE corresponding to KEYP and |
| 137 | * return a pointer (VALUE_TYPE *) to it. Returns NULL if the key was |
| 138 | * not found. */ |
Petr Machata | 98ff309 | 2013-03-08 22:11:36 +0100 | [diff] [blame] | 139 | #define DICT_FIND_REF(DICTP, KEYP, VALUE_TYPE) \ |
Petr Machata | d7e4ca8 | 2012-11-28 03:38:47 +0100 | [diff] [blame] | 140 | (assert((DICTP)->keys.elt_size == sizeof(*(KEYP))), \ |
| 141 | (VALUE_TYPE *)dict_find((DICTP), (KEYP))) |
| 142 | |
Petr Machata | 98ff309 | 2013-03-08 22:11:36 +0100 | [diff] [blame] | 143 | /* Find in DICTP a value of type VALUE_TYPE corresponding to KEYP and |
| 144 | * copy it to the memory pointed-to by VAR. Returns 0 on success, or |
| 145 | * a negative value if the key was not found. */ |
| 146 | #define DICT_FIND_VAL(DICTP, KEYP, VAR) \ |
| 147 | ({ \ |
| 148 | assert((DICTP)->keys.elt_size == sizeof(*(KEYP))); \ |
| 149 | assert((DICTP)->values.elt_size == sizeof((VAR))); \ |
| 150 | void *_ptr = dict_find((DICTP), (KEYP)); \ |
| 151 | if (_ptr != NULL) \ |
| 152 | memcpy((VAR), _ptr, (DICTP)->values.elt_size); \ |
| 153 | _ptr != NULL ? 0 : -1; \ |
| 154 | }) |
| 155 | |
Petr Machata | d7e4ca8 | 2012-11-28 03:38:47 +0100 | [diff] [blame] | 156 | /* Erase from DICT the entry corresponding to KEY. Returns a negative |
| 157 | * value if the key was not found, or 0 on success. DTOR_KEY and |
| 158 | * DTOR_VALUE, if non-NULL, are called to destroy the erased |
| 159 | * value. */ |
| 160 | int dict_erase(struct dict *dict, const void *key, |
| 161 | void (*dtor_key)(void *tgt, void *data), |
| 162 | void (*dtor_value)(void *tgt, void *data), |
| 163 | void *data); |
| 164 | |
| 165 | /* Erase from DICTP a value of type VALUE_TYPE corresponding to |
| 166 | * KEYP. */ |
| 167 | #define DICT_ERASE(DICTP, KEYP, VALUE_TYPE, DTOR_KEY, DTOR_VALUE, DATA) \ |
| 168 | ({ \ |
| 169 | struct dict *_d = (DICTP); \ |
| 170 | assert(_d->keys.elt_size == sizeof(*KEYP)); \ |
| 171 | assert(_d->values.elt_size == sizeof(VALUE_TYPE)); \ |
| 172 | /* Check that callbacks are typed properly. */ \ |
| 173 | void (*_value_dtor_cb)(VALUE_TYPE *, void *) = DTOR_VALUE; \ |
| 174 | dict_erase(_d, (KEYP), (DTOR_KEY), \ |
| 175 | (void (*)(void *, void *))_value_dtor_cb, \ |
| 176 | (DATA)); \ |
| 177 | }) |
| 178 | |
| 179 | /* Destroy DICT. If KEY_DTOR is non-NULL, then it's called on each |
| 180 | * key stored in DICT. Similarly for VALUE_DTOR. DATA is passed to |
| 181 | * DTOR's verbatim. The memory pointed-to by DICT is not freed. */ |
| 182 | void dict_destroy(struct dict *dict, |
| 183 | void (*dtor_key)(void *tgt, void *data), |
| 184 | void (*dtor_value)(void *tgt, void *data), |
| 185 | void *data); |
| 186 | |
| 187 | /* Destroy DICTP, which holds keys of type KEY_TYPE and values of type |
| 188 | * VALUE_TYPE, using DTOR. */ |
| 189 | #define DICT_DESTROY(DICTP, KEY_TYPE, VALUE_TYPE, DTOR_KEY, DTOR_VALUE, DATA) \ |
| 190 | do { \ |
| 191 | struct dict *_d = (DICTP); \ |
| 192 | assert(_d->keys.elt_size == sizeof(KEY_TYPE)); \ |
| 193 | assert(_d->values.elt_size == sizeof(VALUE_TYPE)); \ |
| 194 | /* Check that callbacks are typed properly. */ \ |
| 195 | void (*_key_dtor_cb)(KEY_TYPE *, void *) = DTOR_KEY; \ |
| 196 | void (*_value_dtor_cb)(VALUE_TYPE *, void *) = DTOR_VALUE; \ |
| 197 | dict_destroy(_d, (void (*)(void *, void *))_key_dtor_cb, \ |
| 198 | (void (*)(void *, void *))_value_dtor_cb, \ |
| 199 | (DATA)); \ |
| 200 | } while (0) |
| 201 | |
| 202 | /* Iterate through DICT. See callback.h for notes on iteration |
| 203 | * interfaces. Callback arguments are key, value, DATA. Note that |
| 204 | * the iteration over DICT is more expensive than in other containers: |
| 205 | * while CB is only called for items present in the table, and is |
| 206 | * therefore O(number of elements), the iterator needs to go through |
| 207 | * all the table, which is proportional to O(size of table). |
| 208 | * START_AFTER and the returned iterator are key where the iteration |
| 209 | * stopped. */ |
| 210 | void *dict_each(struct dict *dict, void *start_after, |
| 211 | enum callback_status (*cb)(void *, void *, void *), void *data); |
| 212 | |
| 213 | #define DICT_EACH(DICTP, KEY_TYPE, VALUE_TYPE, START_AFTER, CB, DATA) \ |
| 214 | /* xxx GCC-ism necessary to get in the safety latches. */ \ |
| 215 | ({ \ |
| 216 | assert((DICTP)->keys.elt_size == sizeof(KEY_TYPE)); \ |
| 217 | assert((DICTP)->values.elt_size == sizeof(VALUE_TYPE)); \ |
| 218 | /* Check that CB is typed properly. */ \ |
| 219 | enum callback_status (*_cb)(KEY_TYPE *, VALUE_TYPE *, \ |
| 220 | void *) = CB; \ |
Petr Machata | 38bcdbe | 2012-12-04 17:56:10 +0100 | [diff] [blame] | 221 | KEY_TYPE *_start_after = (START_AFTER); \ |
| 222 | (KEY_TYPE *)dict_each((DICTP), _start_after, \ |
Petr Machata | d7e4ca8 | 2012-11-28 03:38:47 +0100 | [diff] [blame] | 223 | (enum callback_status \ |
| 224 | (*)(void *, void *, void *))_cb, \ |
| 225 | (DATA)); \ |
| 226 | }) |
| 227 | |
| 228 | /* A callback for hashing integers. */ |
| 229 | size_t dict_hash_int(const int *key); |
| 230 | |
| 231 | /* An equality predicate callback for integers. */ |
| 232 | int dict_eq_int(const int *key1, const int *key2); |
| 233 | |
| 234 | /* A callback for hashing NULL-terminated strings. */ |
| 235 | size_t dict_hash_string(const char **key); |
| 236 | |
| 237 | /* An equality predicate callback for strings. */ |
| 238 | int dict_eq_string(const char **key1, const char **key2); |
Petr Machata | a11cbed | 2012-05-05 00:07:38 +0200 | [diff] [blame] | 239 | |
Petr Machata | 3e86576 | 2012-11-28 22:06:17 +0100 | [diff] [blame] | 240 | /* A dtor which calls 'free' on keys in a table. */ |
| 241 | void dict_dtor_string(const char **key, void *data); |
| 242 | |
| 243 | /* A cloner that calls 'strdup' on keys in a table. */ |
| 244 | int dict_clone_string(const char **tgt, const char **src, void *data); |
| 245 | |
Petr Machata | a11cbed | 2012-05-05 00:07:38 +0200 | [diff] [blame] | 246 | #endif /* _DICT_H_ */ |