uint-table.c (5603B)
1 /*************************************************************************** 2 * _ _ ____ _ 3 * Project ___| | | | _ \| | 4 * / __| | | | |_) | | 5 * | (__| |_| | _ <| |___ 6 * \___|\___/|_| \_\_____| 7 * 8 * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al. 9 * 10 * This software is licensed as described in the file COPYING, which 11 * you should have received as part of this distribution. The terms 12 * are also available at https://curl.se/docs/copyright.html. 13 * 14 * You may opt to use, copy, modify, merge, publish, distribute and/or sell 15 * copies of the Software, and permit persons to whom the Software is 16 * furnished to do so, under the terms of the COPYING file. 17 * 18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 19 * KIND, either express or implied. 20 * 21 * SPDX-License-Identifier: curl 22 * 23 ***************************************************************************/ 24 25 #include "curl_setup.h" 26 #include "uint-table.h" 27 28 /* The last 3 #include files should be in this order */ 29 #include "curl_printf.h" 30 #include "curl_memory.h" 31 #include "memdebug.h" 32 33 #ifdef DEBUGBUILD 34 #define CURL_UINT_TBL_MAGIC 0x62757473 35 #endif 36 37 /* Clear the table, making it empty. */ 38 UNITTEST void Curl_uint_tbl_clear(struct uint_tbl *tbl); 39 40 void Curl_uint_tbl_init(struct uint_tbl *tbl, 41 Curl_uint_tbl_entry_dtor *entry_dtor) 42 { 43 memset(tbl, 0, sizeof(*tbl)); 44 tbl->entry_dtor = entry_dtor; 45 tbl->last_key_added = UINT_MAX; 46 #ifdef DEBUGBUILD 47 tbl->init = CURL_UINT_TBL_MAGIC; 48 #endif 49 } 50 51 52 static void uint_tbl_clear_rows(struct uint_tbl *tbl, 53 unsigned int from, 54 unsigned int upto_excluding) 55 { 56 unsigned int i, end; 57 58 end = CURLMIN(upto_excluding, tbl->nrows); 59 for(i = from; i < end; ++i) { 60 if(tbl->rows[i]) { 61 if(tbl->entry_dtor) 62 tbl->entry_dtor(i, tbl->rows[i]); 63 tbl->rows[i] = NULL; 64 tbl->nentries--; 65 } 66 } 67 } 68 69 70 CURLcode Curl_uint_tbl_resize(struct uint_tbl *tbl, unsigned int nrows) 71 { 72 /* we use `tbl->nrows + 1` during iteration, want that to work */ 73 DEBUGASSERT(tbl->init == CURL_UINT_TBL_MAGIC); 74 if(!nrows) 75 return CURLE_BAD_FUNCTION_ARGUMENT; 76 if(nrows != tbl->nrows) { 77 void **rows = calloc(nrows, sizeof(void *)); 78 if(!rows) 79 return CURLE_OUT_OF_MEMORY; 80 if(tbl->rows) { 81 memcpy(rows, tbl->rows, (CURLMIN(nrows, tbl->nrows) * sizeof(void *))); 82 if(nrows < tbl->nrows) 83 uint_tbl_clear_rows(tbl, nrows, tbl->nrows); 84 free(tbl->rows); 85 } 86 tbl->rows = rows; 87 tbl->nrows = nrows; 88 } 89 return CURLE_OK; 90 } 91 92 93 void Curl_uint_tbl_destroy(struct uint_tbl *tbl) 94 { 95 DEBUGASSERT(tbl->init == CURL_UINT_TBL_MAGIC); 96 Curl_uint_tbl_clear(tbl); 97 free(tbl->rows); 98 memset(tbl, 0, sizeof(*tbl)); 99 } 100 101 UNITTEST void Curl_uint_tbl_clear(struct uint_tbl *tbl) 102 { 103 DEBUGASSERT(tbl->init == CURL_UINT_TBL_MAGIC); 104 uint_tbl_clear_rows(tbl, 0, tbl->nrows); 105 DEBUGASSERT(!tbl->nentries); 106 tbl->last_key_added = UINT_MAX; 107 } 108 109 110 unsigned int Curl_uint_tbl_capacity(struct uint_tbl *tbl) 111 { 112 return tbl->nrows; 113 } 114 115 116 unsigned int Curl_uint_tbl_count(struct uint_tbl *tbl) 117 { 118 return tbl->nentries; 119 } 120 121 122 void *Curl_uint_tbl_get(struct uint_tbl *tbl, unsigned int key) 123 { 124 return (key < tbl->nrows) ? tbl->rows[key] : NULL; 125 } 126 127 128 bool Curl_uint_tbl_add(struct uint_tbl *tbl, void *entry, unsigned int *pkey) 129 { 130 unsigned int key, start_pos; 131 132 DEBUGASSERT(tbl->init == CURL_UINT_TBL_MAGIC); 133 if(!entry || !pkey) 134 return FALSE; 135 *pkey = UINT_MAX; 136 if(tbl->nentries == tbl->nrows) /* full */ 137 return FALSE; 138 139 start_pos = CURLMIN(tbl->last_key_added, tbl->nrows) + 1; 140 for(key = start_pos; key < tbl->nrows; ++key) { 141 if(!tbl->rows[key]) { 142 tbl->rows[key] = entry; 143 tbl->nentries++; 144 tbl->last_key_added = key; 145 *pkey = key; 146 return TRUE; 147 } 148 } 149 /* no free entry at or above tbl->maybe_next_key, wrap around */ 150 for(key = 0; key < start_pos; ++key) { 151 if(!tbl->rows[key]) { 152 tbl->rows[key] = entry; 153 tbl->nentries++; 154 tbl->last_key_added = key; 155 *pkey = key; 156 return TRUE; 157 } 158 } 159 /* Did not find any free row? Should not happen */ 160 DEBUGASSERT(0); 161 return FALSE; 162 } 163 164 165 void Curl_uint_tbl_remove(struct uint_tbl *tbl, unsigned int key) 166 { 167 uint_tbl_clear_rows(tbl, key, key + 1); 168 } 169 170 171 bool Curl_uint_tbl_contains(struct uint_tbl *tbl, unsigned int key) 172 { 173 return (key < tbl->nrows) ? !!tbl->rows[key] : FALSE; 174 } 175 176 177 static bool uint_tbl_next_at(struct uint_tbl *tbl, unsigned int key, 178 unsigned int *pkey, void **pentry) 179 { 180 for(; key < tbl->nrows; ++key) { 181 if(tbl->rows[key]) { 182 *pkey = key; 183 *pentry = tbl->rows[key]; 184 return TRUE; 185 } 186 } 187 *pkey = UINT_MAX; /* always invalid */ 188 *pentry = NULL; 189 return FALSE; 190 } 191 192 bool Curl_uint_tbl_first(struct uint_tbl *tbl, 193 unsigned int *pkey, void **pentry) 194 { 195 if(!pkey || !pentry) 196 return FALSE; 197 if(tbl->nentries && uint_tbl_next_at(tbl, 0, pkey, pentry)) 198 return TRUE; 199 DEBUGASSERT(!tbl->nentries); 200 *pkey = UINT_MAX; /* always invalid */ 201 *pentry = NULL; 202 return FALSE; 203 } 204 205 206 bool Curl_uint_tbl_next(struct uint_tbl *tbl, unsigned int last_key, 207 unsigned int *pkey, void **pentry) 208 { 209 if(!pkey || !pentry) 210 return FALSE; 211 if(uint_tbl_next_at(tbl, last_key + 1, pkey, pentry)) 212 return TRUE; 213 *pkey = UINT_MAX; /* always invalid */ 214 *pentry = NULL; 215 return FALSE; 216 }