Coverage Report

Created: 2026-02-26 06:40

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/curl/lib/uint-table.c
Line
Count
Source
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
#include "curl_setup.h"
25
26
#include "uint-table.h"
27
28
#ifdef DEBUGBUILD
29
158k
#define CURL_UINT32_TBL_MAGIC  0x62757473
30
#endif
31
32
/* Clear the table, making it empty. */
33
UNITTEST void Curl_uint32_tbl_clear(struct uint32_tbl *tbl);
34
35
void Curl_uint32_tbl_init(struct uint32_tbl *tbl,
36
                          Curl_uint32_tbl_entry_dtor *entry_dtor)
37
158k
{
38
158k
  memset(tbl, 0, sizeof(*tbl));
39
158k
  tbl->entry_dtor = entry_dtor;
40
158k
  tbl->last_key_added = UINT32_MAX;
41
158k
#ifdef DEBUGBUILD
42
158k
  tbl->init = CURL_UINT32_TBL_MAGIC;
43
158k
#endif
44
158k
}
45
46
static void uint32_tbl_clear_rows(struct uint32_tbl *tbl,
47
                                  uint32_t from,
48
                                  uint32_t upto_excluding)
49
482k
{
50
482k
  uint32_t i, end;
51
52
482k
  end = CURLMIN(upto_excluding, tbl->nrows);
53
81.7M
  for(i = from; i < end; ++i) {
54
81.2M
    if(tbl->rows[i]) {
55
324k
      if(tbl->entry_dtor)
56
0
        tbl->entry_dtor(i, tbl->rows[i]);
57
324k
      tbl->rows[i] = NULL;
58
324k
      tbl->nentries--;
59
324k
    }
60
81.2M
  }
61
482k
}
62
63
CURLcode Curl_uint32_tbl_resize(struct uint32_tbl *tbl, uint32_t nrows)
64
158k
{
65
  /* we use `tbl->nrows + 1` during iteration, want that to work */
66
158k
  DEBUGASSERT(tbl->init == CURL_UINT32_TBL_MAGIC);
67
158k
  if(!nrows)
68
0
    return CURLE_BAD_FUNCTION_ARGUMENT;
69
158k
  if(nrows != tbl->nrows) {
70
158k
    void **rows = curlx_calloc(nrows, sizeof(void *));
71
158k
    if(!rows)
72
0
      return CURLE_OUT_OF_MEMORY;
73
158k
    if(tbl->rows) {
74
0
      memcpy(rows, tbl->rows, (CURLMIN(nrows, tbl->nrows) * sizeof(void *)));
75
0
      if(nrows < tbl->nrows)
76
0
        uint32_tbl_clear_rows(tbl, nrows, tbl->nrows);
77
0
      curlx_free(tbl->rows);
78
0
    }
79
158k
    tbl->rows = rows;
80
158k
    tbl->nrows = nrows;
81
158k
  }
82
158k
  return CURLE_OK;
83
158k
}
84
85
void Curl_uint32_tbl_destroy(struct uint32_tbl *tbl)
86
158k
{
87
158k
  DEBUGASSERT(tbl->init == CURL_UINT32_TBL_MAGIC);
88
158k
  Curl_uint32_tbl_clear(tbl);
89
158k
  curlx_free(tbl->rows);
90
158k
  memset(tbl, 0, sizeof(*tbl));
91
158k
}
92
93
UNITTEST void Curl_uint32_tbl_clear(struct uint32_tbl *tbl)
94
158k
{
95
158k
  DEBUGASSERT(tbl->init == CURL_UINT32_TBL_MAGIC);
96
158k
  uint32_tbl_clear_rows(tbl, 0, tbl->nrows);
97
158k
  DEBUGASSERT(!tbl->nentries);
98
158k
  tbl->last_key_added = UINT32_MAX;
99
158k
}
100
101
uint32_t Curl_uint32_tbl_capacity(struct uint32_tbl *tbl)
102
166k
{
103
166k
  return tbl->nrows;
104
166k
}
105
106
uint32_t Curl_uint32_tbl_count(struct uint32_tbl *tbl)
107
324k
{
108
324k
  return tbl->nentries;
109
324k
}
110
111
void *Curl_uint32_tbl_get(struct uint32_tbl *tbl, uint32_t key)
112
166M
{
113
166M
  return (key < tbl->nrows) ? tbl->rows[key] : NULL;
114
166M
}
115
116
bool Curl_uint32_tbl_add(struct uint32_tbl *tbl, void *entry, uint32_t *pkey)
117
324k
{
118
324k
  uint32_t key, start_pos;
119
120
324k
  DEBUGASSERT(tbl->init == CURL_UINT32_TBL_MAGIC);
121
324k
  if(!entry || !pkey)
122
0
    return FALSE;
123
324k
  *pkey = UINT32_MAX;
124
324k
  if(tbl->nentries == tbl->nrows)  /* full */
125
0
    return FALSE;
126
127
324k
  start_pos = CURLMIN(tbl->last_key_added, tbl->nrows) + 1;
128
324k
  for(key = start_pos; key < tbl->nrows; ++key) {
129
166k
    if(!tbl->rows[key]) {
130
166k
      tbl->rows[key] = entry;
131
166k
      tbl->nentries++;
132
166k
      tbl->last_key_added = key;
133
166k
      *pkey = key;
134
166k
      return TRUE;
135
166k
    }
136
166k
  }
137
  /* no free entry at or above tbl->maybe_next_key, wrap around */
138
158k
  for(key = 0; key < start_pos; ++key) {
139
158k
    if(!tbl->rows[key]) {
140
158k
      tbl->rows[key] = entry;
141
158k
      tbl->nentries++;
142
158k
      tbl->last_key_added = key;
143
158k
      *pkey = key;
144
158k
      return TRUE;
145
158k
    }
146
158k
  }
147
  /* Did not find any free row? Should not happen */
148
0
  DEBUGASSERT(0);
149
0
  return FALSE;
150
0
}
151
152
void Curl_uint32_tbl_remove(struct uint32_tbl *tbl, uint32_t key)
153
324k
{
154
324k
  uint32_tbl_clear_rows(tbl, key, key + 1);
155
324k
}
156
157
bool Curl_uint32_tbl_contains(struct uint32_tbl *tbl, uint32_t key)
158
166k
{
159
166k
  return (key < tbl->nrows) ? !!tbl->rows[key] : FALSE;
160
166k
}
161
162
static bool uint32_tbl_next_at(struct uint32_tbl *tbl, uint32_t key,
163
                               uint32_t *pkey, void **pentry)
164
316k
{
165
81.1M
  for(; key < tbl->nrows; ++key) {
166
80.9M
    if(tbl->rows[key]) {
167
158k
      *pkey = key;
168
158k
      *pentry = tbl->rows[key];
169
158k
      return TRUE;
170
158k
    }
171
80.9M
  }
172
158k
  *pkey = UINT32_MAX;  /* always invalid */
173
158k
  *pentry = NULL;
174
158k
  return FALSE;
175
316k
}
176
177
bool Curl_uint32_tbl_first(struct uint32_tbl *tbl,
178
                           uint32_t *pkey, void **pentry)
179
158k
{
180
158k
  if(!pkey || !pentry)
181
0
    return FALSE;
182
158k
  if(tbl->nentries && uint32_tbl_next_at(tbl, 0, pkey, pentry))
183
158k
    return TRUE;
184
0
  DEBUGASSERT(!tbl->nentries);
185
0
  *pkey = UINT32_MAX;  /* always invalid */
186
0
  *pentry = NULL;
187
0
  return FALSE;
188
0
}
189
190
bool Curl_uint32_tbl_next(struct uint32_tbl *tbl, uint32_t last_key,
191
                          uint32_t *pkey, void **pentry)
192
158k
{
193
158k
  if(!pkey || !pentry)
194
0
    return FALSE;
195
158k
  if(uint32_tbl_next_at(tbl, last_key + 1, pkey, pentry))
196
0
    return TRUE;
197
158k
  *pkey = UINT32_MAX;  /* always invalid */
198
158k
  *pentry = NULL;
199
  return FALSE;
200
158k
}