dict.h revision 38bcdbe5d04749403e2197cca0d56397cb2da7c7
1/* 2 * This file is part of ltrace. 3 * Copyright (C) 2012 Petr Machata, Red Hat Inc. 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 24#include <stddef.h> 25#include <assert.h> 26#include "vect.h" 27 28struct 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; 35 36 size_t (*hash1)(const void *); 37 int (*eq)(const void *, const void *); 38 size_t (*hash2)(size_t); 39}; 40 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. */ 46void 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)); 51 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 }) 65 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. */ 74int 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. */ 108size_t dict_size(const struct dict *dict); 109 110/* Emptiness predicate. */ 111int 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. */ 116int 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. */ 128void *dict_find(struct dict *dict, const void *key); 129 130/* Find in DICTP a value of type VALUE_TYPE corresponding to KEYP and 131 * return a pointer (VALUE_TYPE *) to it. Returns NULL if the key was 132 * not found. */ 133#define DICT_FIND(DICTP, KEYP, VALUE_TYPE) \ 134 (assert((DICTP)->keys.elt_size == sizeof(*(KEYP))), \ 135 (VALUE_TYPE *)dict_find((DICTP), (KEYP))) 136 137/* Erase from DICT the entry corresponding to KEY. Returns a negative 138 * value if the key was not found, or 0 on success. DTOR_KEY and 139 * DTOR_VALUE, if non-NULL, are called to destroy the erased 140 * value. */ 141int dict_erase(struct dict *dict, const void *key, 142 void (*dtor_key)(void *tgt, void *data), 143 void (*dtor_value)(void *tgt, void *data), 144 void *data); 145 146/* Erase from DICTP a value of type VALUE_TYPE corresponding to 147 * KEYP. */ 148#define DICT_ERASE(DICTP, KEYP, VALUE_TYPE, DTOR_KEY, DTOR_VALUE, DATA) \ 149 ({ \ 150 struct dict *_d = (DICTP); \ 151 assert(_d->keys.elt_size == sizeof(*KEYP)); \ 152 assert(_d->values.elt_size == sizeof(VALUE_TYPE)); \ 153 /* Check that callbacks are typed properly. */ \ 154 void (*_value_dtor_cb)(VALUE_TYPE *, void *) = DTOR_VALUE; \ 155 dict_erase(_d, (KEYP), (DTOR_KEY), \ 156 (void (*)(void *, void *))_value_dtor_cb, \ 157 (DATA)); \ 158 }) 159 160/* Destroy DICT. If KEY_DTOR is non-NULL, then it's called on each 161 * key stored in DICT. Similarly for VALUE_DTOR. DATA is passed to 162 * DTOR's verbatim. The memory pointed-to by DICT is not freed. */ 163void dict_destroy(struct dict *dict, 164 void (*dtor_key)(void *tgt, void *data), 165 void (*dtor_value)(void *tgt, void *data), 166 void *data); 167 168/* Destroy DICTP, which holds keys of type KEY_TYPE and values of type 169 * VALUE_TYPE, using DTOR. */ 170#define DICT_DESTROY(DICTP, KEY_TYPE, VALUE_TYPE, DTOR_KEY, DTOR_VALUE, DATA) \ 171 do { \ 172 struct dict *_d = (DICTP); \ 173 assert(_d->keys.elt_size == sizeof(KEY_TYPE)); \ 174 assert(_d->values.elt_size == sizeof(VALUE_TYPE)); \ 175 /* Check that callbacks are typed properly. */ \ 176 void (*_key_dtor_cb)(KEY_TYPE *, void *) = DTOR_KEY; \ 177 void (*_value_dtor_cb)(VALUE_TYPE *, void *) = DTOR_VALUE; \ 178 dict_destroy(_d, (void (*)(void *, void *))_key_dtor_cb, \ 179 (void (*)(void *, void *))_value_dtor_cb, \ 180 (DATA)); \ 181 } while (0) 182 183/* Iterate through DICT. See callback.h for notes on iteration 184 * interfaces. Callback arguments are key, value, DATA. Note that 185 * the iteration over DICT is more expensive than in other containers: 186 * while CB is only called for items present in the table, and is 187 * therefore O(number of elements), the iterator needs to go through 188 * all the table, which is proportional to O(size of table). 189 * START_AFTER and the returned iterator are key where the iteration 190 * stopped. */ 191void *dict_each(struct dict *dict, void *start_after, 192 enum callback_status (*cb)(void *, void *, void *), void *data); 193 194#define DICT_EACH(DICTP, KEY_TYPE, VALUE_TYPE, START_AFTER, CB, DATA) \ 195 /* xxx GCC-ism necessary to get in the safety latches. */ \ 196 ({ \ 197 assert((DICTP)->keys.elt_size == sizeof(KEY_TYPE)); \ 198 assert((DICTP)->values.elt_size == sizeof(VALUE_TYPE)); \ 199 /* Check that CB is typed properly. */ \ 200 enum callback_status (*_cb)(KEY_TYPE *, VALUE_TYPE *, \ 201 void *) = CB; \ 202 KEY_TYPE *_start_after = (START_AFTER); \ 203 (KEY_TYPE *)dict_each((DICTP), _start_after, \ 204 (enum callback_status \ 205 (*)(void *, void *, void *))_cb, \ 206 (DATA)); \ 207 }) 208 209/* A callback for hashing integers. */ 210size_t dict_hash_int(const int *key); 211 212/* An equality predicate callback for integers. */ 213int dict_eq_int(const int *key1, const int *key2); 214 215/* A callback for hashing NULL-terminated strings. */ 216size_t dict_hash_string(const char **key); 217 218/* An equality predicate callback for strings. */ 219int dict_eq_string(const char **key1, const char **key2); 220 221/* A dtor which calls 'free' on keys in a table. */ 222void dict_dtor_string(const char **key, void *data); 223 224/* A cloner that calls 'strdup' on keys in a table. */ 225int dict_clone_string(const char **tgt, const char **src, void *data); 226 227#endif /* _DICT_H_ */ 228