u32_ptrset: a set of uint32_t + void* values
No binary (build failed)
—
(log yok)
| @@ -289,8 +289,8 @@ LIB_CFILES = \ | |
| thrdqueue.c \ | |
| transfer.c \ | |
| u8_strset.c \ | |
| + | u32_ptrset.c \ |
| uint-bset.c \ | |
| - | uint-hash.c \ |
| uint-spbset.c \ | |
| uint-table.c \ | |
| url.c \ | |
| @@ -421,8 +421,8 @@ LIB_HFILES = \ | |
| thrdqueue.h \ | |
| transfer.h \ | |
| u8_strset.h \ | |
| + | u32_ptrset.h \ |
| uint-bset.h \ | |
| - | uint-hash.h \ |
| uint-spbset.h \ | |
| uint-table.h \ | |
| url.h \ | |
| @@ -28,7 +28,7 @@ | |
| #include "urldata.h" | |
| #include "bufq.h" | |
| - | #include "uint-hash.h" |
| + | #include "u32_ptrset.h" |
| #include "http1.h" | |
| #include "http2.h" | |
| #include "http.h" | |
| @@ -97,7 +97,7 @@ struct cf_h2_ctx { | |
| struct bufc_pool stream_bufcp; /* spares for stream buffers */ | |
| struct dynbuf scratch; /* scratch buffer for temp use */ | |
| - | struct uint_hash streams; /* hash of `data->mid` to `h2_stream_ctx` */ |
| + | struct u32_ptrset streams; /* hash of `data->mid` to `h2_stream_ctx` */ |
| size_t drain_total; /* sum of all stream's UrlState drain */ | |
| uint32_t initial_win_size; /* current initial window size (settings) */ | |
| uint32_t max_concurrent_streams; | |
| @@ -165,7 +165,7 @@ static void h2_stream_ctx_free(struct h2_stream_ctx *stream) | |
| curlx_free(stream); | |
| } | |
| - | static void h2_stream_hash_free(unsigned int id, void *stream) |
| + | static void h2_stream_hash_free(uint32_t id, void *stream) |
| { | |
| (void)id; | |
| DEBUGASSERT(stream); | |
| @@ -178,7 +178,7 @@ static void cf_h2_ctx_init(struct cf_h2_ctx *ctx, bool via_h1_upgrade) | |
| Curl_bufq_initp(&ctx->inbufq, &ctx->stream_bufcp, H2_NW_RECV_CHUNKS, 0); | |
| Curl_bufq_initp(&ctx->outbufq, &ctx->stream_bufcp, H2_NW_SEND_CHUNKS, 0); | |
| curlx_dyn_init(&ctx->scratch, CURL_MAX_HTTP_HEADER); | |
| - | Curl_uint32_hash_init(&ctx->streams, 63, h2_stream_hash_free); |
| + | Curl_u32_ptrset_init(&ctx->streams, h2_stream_hash_free); |
| ctx->remote_max_sid = INT32_MAX; | |
| ctx->via_h1_upgrade = via_h1_upgrade; | |
| ctx->initialized = TRUE; | |
| @@ -193,7 +193,7 @@ static void cf_h2_ctx_free(struct cf_h2_ctx *ctx) | |
| Curl_bufq_free(&ctx->outbufq); | |
| Curl_bufcp_free(&ctx->stream_bufcp); | |
| curlx_dyn_free(&ctx->scratch); | |
| - | Curl_uint32_hash_destroy(&ctx->streams); |
| + | Curl_u32_ptrset_clear(&ctx->streams); |
| memset(ctx, 0, sizeof(*ctx)); | |
| } | |
| curlx_free(ctx); | |
| @@ -255,7 +255,7 @@ static CURLcode cf_h2_update_settings(struct cf_h2_ctx *ctx, | |
| #define H2_STREAM_CTX(ctx, data) \ | |
| ((struct h2_stream_ctx *)( \ | |
| - | (data) ? Curl_uint32_hash_get(&(ctx)->streams, (data)->mid) : NULL)) |
| + | (data) ? Curl_u32_ptrset_get(&(ctx)->streams, (data)->mid) : NULL)) |
| static struct h2_stream_ctx *h2_stream_ctx_create(struct cf_h2_ctx *ctx) | |
| { | |
| @@ -381,7 +381,7 @@ static CURLcode http2_data_setup(struct Curl_cfilter *cf, | |
| if(!stream) | |
| return CURLE_OUT_OF_MEMORY; | |
| - | if(!Curl_uint32_hash_set(&ctx->streams, data->mid, stream)) { |
| + | if(Curl_u32_ptrset_set(&ctx->streams, data->mid, stream)) { |
| h2_stream_ctx_free(stream); | |
| return CURLE_OUT_OF_MEMORY; | |
| } | |
| @@ -444,7 +444,7 @@ static void http2_data_done(struct Curl_cfilter *cf, struct Curl_easy *data) | |
| } | |
| } | |
| - | Curl_uint32_hash_remove(&ctx->streams, data->mid); |
| + | Curl_u32_ptrset_unset(&ctx->streams, data->mid); |
| } | |
| static int h2_client_new(struct Curl_cfilter *cf, | |
| @@ -0,0 +1,277 @@ | |
| + | /*************************************************************************** |
| + | * _ _ ____ _ |
| + | * Project ___| | | | _ \| | |
| + | * / __| | | | |_) | | |
| + | * | (__| |_| | _ <| |___ |
| + | * \___|\___/|_| \_\_____| |
| + | * |
| + | * Copyright (C) Daniel Stenberg, <[email protected]>, et al. |
| + | * |
| + | * This software is licensed as described in the file COPYING, which |
| + | * you should have received as part of this distribution. The terms |
| + | * are also available at https://curl.se/docs/copyright.html. |
| + | * |
| + | * You may opt to use, copy, modify, merge, publish, distribute and/or sell |
| + | * copies of the Software, and permit persons to whom the Software is |
| + | * furnished to do so, under the terms of the COPYING file. |
| + | * |
| + | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY |
| + | * KIND, either express or implied. |
| + | * |
| + | * SPDX-License-Identifier: curl |
| + | * |
| + | ***************************************************************************/ |
| + | #include "curl_setup.h" |
| + | |
| + | #include "u32_ptrset.h" |
| + | |
| + | /* random patterns for API verification */ |
| + | #ifdef DEBUGBUILD |
| + | #define CURL_U32_PTRSET_MAGIC 0x75703272 |
| + | #endif |
| + | |
| + | #define CURL_U32_PTRSET_DEBUG 0 |
| + | |
| + | #ifndef CURL_SWAP |
| + | #define CURL_SWAP(a, b) (((a) ^= (b)), ((b) ^= (a)), ((a) ^= (b))) |
| + | #endif |
| + | |
| + | #define CURL_U32_SLOT_CNT(bits) ((bits) ? (1U << (bits)) : 0) |
| + | #define CURL_U32_PTRSET_SLOT_CNT(s) CURL_U32_SLOT_CNT((s)->slotbits) |
| + | #define CURL_U32_PTRSET_SLOT_IDX(s, i) (uint32_t)((i) & (s)->slotmask) |
| + | |
| + | /* A hashset for tuples (id, ptr) using Robin Hood Hashing. |
| + | * <https://www.cs.cornell.edu/courses/JavaAndDS/files/hashing_RobinHood.pdf> |
| + | * The basic idea here to handle collisions by robbing "rich" entries and |
| + | * giving to the "poor": |
| + | * - We have an array: (id, ptr) are ideally placed at index "id % size". |
| + | * - If slot at index is already occupied, we have a collision. |
| + | * - A simple collision strategy would look at the next index, and the |
| + | * next until finding an empty slot. |
| + | * - The drawback is that this may lead to many checks on lookups, as it |
| + | * will need to also look at subsequent slots until it finds the match. |
| + | * The amount of lookups is the "probe sequence length" (psl) and this |
| + | * may vary greatly between entries. |
| + | * - Robin Hood Hashing balances the 'psl's of all entries more evenly: |
| + | * - psl == 0 means an entry is in exactly the right slot |
| + | * - psl == 1 means it is in the slot right after. psl == 2 is the slot |
| + | * after that, etc. |
| + | * - when inserting a new entry, track its psl. Finding a slot where |
| + | * the existing entry has a lower psl makes a swap. Put the new entry |
| + | * and its psl there, take the previous entry and its psl and find |
| + | * the next best slot for the previous entry. */ |
| + | void Curl_u32_ptrset_init(struct u32_ptrset *set, |
| + | Curl_u32_ptrset_dtor *dtor) |
| + | { |
| + | memset(set, 0, sizeof(*set)); |
| + | set->dtor = dtor; |
| + | #ifdef DEBUGBUILD |
| + | set->init = CURL_U32_PTRSET_MAGIC; |
| + | #endif |
| + | } |
| + | |
| + | void Curl_u32_ptrset_clear(struct u32_ptrset *set) |
| + | { |
| + | uint32_t i; |
| + | DEBUGASSERT(set->init == CURL_U32_PTRSET_MAGIC); |
| + | if(set->dtor) |
| + | for(i = 0; i < CURL_U32_PTRSET_SLOT_CNT(set); ++i) |
| + | if(set->data[i]) |
| + | set->dtor(set->ids[i], set->data[i]); |
| + | |
| + | curlx_safefree(set->data); |
| + | Curl_u32_ptrset_init(set, set->dtor); |
| + | } |
| + | |
| + | static void u32_ptrset_add(struct u32_ptrset *set, uint32_t id, void *ptr) |
| + | { |
| + | uint32_t i = CURL_U32_PTRSET_SLOT_IDX(set, id); |
| + | uint32_t psl = 0; |
| + | while(set->data[i]) { |
| + | if(psl > set->psl[i]) { /* SWAP */ |
| + | void *tmpdata; |
| + | #if CURL_U32_PTRSET_DEBUG |
| + | curl_mfprintf(stderr, "u32_ptrset_add %u=%p to idx=%u\n", id, ptr, i); |
| + | #endif |
| + | tmpdata = set->data[i]; |
| + | set->data[i] = ptr; |
| + | ptr = tmpdata; |
| + | CURL_SWAP(set->psl[i], psl); |
| + | CURL_SWAP(set->ids[i], id); |
| + | } |
| + | i = CURL_U32_PTRSET_SLOT_IDX(set, i + 1); |
| + | ++psl; |
| + | } |
| + | set->ids[i] = id; |
| + | set->data[i] = ptr; |
| + | set->psl[i] = psl; |
| + | ++set->count; |
| + | #if CURL_U32_PTRSET_DEBUG |
| + | curl_mfprintf(stderr, "u32_ptrset_add %u=%p to idx=%u\n", id, ptr, i); |
| + | #endif |
| + | } |
| + | |
| + | static bool u32_ptrset_grow(struct u32_ptrset *set) |
| + | { |
| + | uint32_t i, *prev_ids; |
| + | uint8_t nslotbits, pslotbits; |
| + | void **prev_data; |
| + | size_t nslots; |
| + | void *d; |
| + | |
| + | if(set->slotbits >= 32) |
| + | return FALSE; |
| + | nslotbits = set->slotbits ? (uint8_t)(set->slotbits + 1) : 5; |
| + | nslots = CURL_U32_SLOT_CNT(nslotbits); |
| + | #if CURL_U32_PTRSET_DEBUG |
| + | curl_mfprintf(stderr, "u32_ptrset_grow from bits=%d to %d, slots=%zu\n", |
| + | set->slotbits, nslotbits, nslots); |
| + | #endif |
| + | d = curlx_calloc(1, (nslots * sizeof(void *)) + |
| + | (2 * nslots * sizeof(uint32_t))); |
| + | if(!d) |
| + | return FALSE; |
| + | |
| + | prev_data = set->data; |
| + | prev_ids = set->ids; |
| + | pslotbits = set->slotbits; |
| + | #if defined(__GNUC__) && __GNUC__ >= 13 |
| + | #pragma GCC diagnostic push |
| + | #pragma GCC diagnostic ignored "-Wanalyzer-allocation-size" |
| + | #endif |
| + | set->data = d; |
| + | set->ids = (uint32_t *)(set->data + nslots); |
| + | set->psl = (uint32_t *)(set->ids + nslots); |
| + | #if defined(__GNUC__) && __GNUC__ >= 13 |
| + | #pragma GCC diagnostic pop |
| + | #endif |
| + | |
| + | set->slotbits = nslotbits; |
| + | set->slotmask = (uint32_t)((1U << set->slotbits) - 1); |
| + | set->count = 0; |
| + | /* re-add previous entries */ |
| + | for(i = 0; i < CURL_U32_SLOT_CNT(pslotbits); ++i) { |
| + | if(prev_data[i]) |
| + | u32_ptrset_add(set, prev_ids[i], prev_data[i]); |
| + | } |
| + | if(prev_data) |
| + | curlx_free(prev_data); |
| + | return TRUE; |
| + | } |
| + | |
| + | static bool u32_ptrset_get_index(struct u32_ptrset *set, |
| + | uint32_t id, uint32_t *pindex) |
| + | { |
| + | uint32_t i = CURL_U32_PTRSET_SLOT_IDX(set, id); |
| + | uint32_t psl = 0; |
| + | if(!set->data) |
| + | return FALSE; |
| + | while(set->data[i] && (psl <= set->psl[i])) { |
| + | if(set->ids[i] == id) { |
| + | *pindex = i; |
| + | #if CURL_U32_PTRSET_DEBUG |
| + | curl_mfprintf(stderr, "u32_ptrset_index %u=%p at idx=%u\n", |
| + | id, set->data[i], i); |
| + | #endif |
| + | return TRUE; |
| + | } |
| + | i = CURL_U32_PTRSET_SLOT_IDX(set, i + 1); |
| + | ++psl; |
| + | } |
| + | #if CURL_U32_PTRSET_DEBUG |
| + | curl_mfprintf(stderr, "u32_ptrset_index %u not found\n", id); |
| + | #endif |
| + | *pindex = 0; |
| + | return FALSE; |
| + | } |
| + | |
| + | uint32_t Curl_u32_ptrset_count(struct u32_ptrset *set) |
| + | { |
| + | return set->count; |
| + | } |
| + | |
| + | void *Curl_u32_ptrset_get(struct u32_ptrset *set, uint32_t id) |
| + | { |
| + | uint32_t i; |
| + | DEBUGASSERT(set->init == CURL_U32_PTRSET_MAGIC); |
| + | if(u32_ptrset_get_index(set, id, &i)) |
| + | return set->data[i]; |
| + | return NULL; |
| + | } |
| + | |
| + | CURLcode Curl_u32_ptrset_set(struct u32_ptrset *set, |
| + | uint32_t id, void *ptr) |
| + | { |
| + | uint32_t i; |
| + | |
| + | DEBUGASSERT(set->init == CURL_U32_PTRSET_MAGIC); |
| + | if(!ptr) { |
| + | Curl_u32_ptrset_unset(set, id); |
| + | return CURLE_OK; |
| + | } |
| + | |
| + | if(u32_ptrset_get_index(set, id, &i)) { |
| + | /* `id` is in set, replace value */ |
| + | if(set->dtor && (set->data[i] != ptr)) |
| + | set->dtor(set->ids[i], set->data[i]); |
| + | #if CURL_U32_PTRSET_DEBUG |
| + | curl_mfprintf(stderr, "u32_ptrset_set replace %u=%p at idx=%u\n", |
| + | id, ptr, i); |
| + | #endif |
| + | set->data[i] = ptr; |
| + | return CURLE_OK; |
| + | } |
| + | /* `id` not in set yet, grow if full */ |
| + | if((set->count >= CURL_U32_PTRSET_SLOT_CNT(set)) && |
| + | !u32_ptrset_grow(set)) { |
| + | return CURLE_OUT_OF_MEMORY; |
| + | } |
| + | |
| + | u32_ptrset_add(set, id, ptr); |
| + | return CURLE_OK; |
| + | } |
| + | |
| + | static void u32_ptrset_unset(struct u32_ptrset *set, uint32_t id) |
| + | { |
| + | uint32_t i, j; |
| + | |
| + | DEBUGASSERT(set->init == CURL_U32_PTRSET_MAGIC); |
| + | if(u32_ptrset_get_index(set, id, &i)) { |
| + | /* `id` is in set */ |
| + | #if CURL_U32_PTRSET_DEBUG |
| + | curl_mfprintf(stderr, "u32_ptrset_unset %u at idx=%u\n", id, i); |
| + | #endif |
| + | if(set->dtor) |
| + | set->dtor(set->ids[i], set->data[i]); |
| + | set->data[i] = NULL; |
| + | set->ids[i] = set->psl[i] = 0; |
| + | --set->count; |
| + | j = CURL_U32_PTRSET_SLOT_IDX(set, i + 1); |
| + | /* shift all entries with positive psl "down" */ |
| + | while(set->data[j] && set->psl[j]) { |
| + | set->data[i] = set->data[j]; |
| + | set->ids[i] = set->ids[j]; |
| + | set->psl[i] = set->psl[j] - 1; |
| + | set->data[j] = NULL; |
| + | set->ids[j] = set->psl[j] = 0; |
| + | i = j; |
| + | j = CURL_U32_PTRSET_SLOT_IDX(set, i + 1); |
| + | } |
| + | } |
| + | } |
| + | |
| + | void Curl_u32_ptrset_unset(struct u32_ptrset *set, uint32_t id) |
| + | { |
| + | u32_ptrset_unset(set, id); |
| + | } |
| + | |
| + | void Curl_u32_ptrset_visit(struct u32_ptrset *set, |
| + | Curl_u32_ptrset_visit_cb *cb, |
| + | void *user_data) |
| + | { |
| + | uint32_t i; |
| + | for(i = 0; i < CURL_U32_PTRSET_SLOT_CNT(set); ++i) { |
| + | if(set->data[i] && !cb(set->ids[i], set->data[i], user_data)) |
| + | break; |
| + | } |
| + | } |
| @@ -0,0 +1,70 @@ | |
| + | #ifndef HEADER_CURL_U32_PTRSET_H |
| + | #define HEADER_CURL_U32_PTRSET_H |
| + | /*************************************************************************** |
| + | * _ _ ____ _ |
| + | * Project ___| | | | _ \| | |
| + | * / __| | | | |_) | | |
| + | * | (__| |_| | _ <| |___ |
| + | * \___|\___/|_| \_\_____| |
| + | * |
| + | * Copyright (C) Daniel Stenberg, <[email protected]>, et al. |
| + | * |
| + | * This software is licensed as described in the file COPYING, which |
| + | * you should have received as part of this distribution. The terms |
| + | * are also available at https://curl.se/docs/copyright.html. |
| + | * |
| + | * You may opt to use, copy, modify, merge, publish, distribute and/or sell |
| + | * copies of the Software, and permit persons to whom the Software is |
| + | * furnished to do so, under the terms of the COPYING file. |
| + | * |
| + | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY |
| + | * KIND, either express or implied. |
| + | * |
| + | * SPDX-License-Identifier: curl |
| + | * |
| + | ***************************************************************************/ |
| + | #include "curl_setup.h" |
| + | |
| + | typedef void Curl_u32_ptrset_dtor(uint32_t id, void *ptr); |
| + | |
| + | /* A set that can hold up UINT32_MAX pointers identified by an `id'. |
| + | * Setting a pointer for an existing id replaces the previous one. |
| + | * Getting the pointer for an id not in the set returns NULL. |
| + | * Setting an id to NULL unsets the id. |
| + | */ |
| + | struct u32_ptrset { |
| + | void **data; /* #slots array of pointers */ |
| + | uint32_t *ids; /* #slots array of `id` values */ |
| + | uint32_t *psl; /* #slots array of "probe sequence length" values */ |
| + | uint32_t slotmask; |
| + | uint32_t count; |
| + | Curl_u32_ptrset_dtor *dtor; |
| + | uint8_t slotbits; |
| + | #ifdef DEBUGBUILD |
| + | int32_t init; |
| + | #endif |
| + | }; |
| + | |
| + | void Curl_u32_ptrset_init(struct u32_ptrset *set, |
| + | Curl_u32_ptrset_dtor *dtor); |
| + | void Curl_u32_ptrset_clear(struct u32_ptrset *set); |
| + | |
| + | uint32_t Curl_u32_ptrset_count(struct u32_ptrset *set); |
| + | |
| + | void *Curl_u32_ptrset_get(struct u32_ptrset *set, uint32_t id); |
| + | |
| + | /* Set pointer for id. */ |
| + | CURLcode Curl_u32_ptrset_set(struct u32_ptrset *set, |
| + | uint32_t id, void *ptr); |
| + | |
| + | void Curl_u32_ptrset_unset(struct u32_ptrset *set, uint32_t id); |
| + | |
| + | typedef bool Curl_u32_ptrset_visit_cb(uint32_t id, void *ptr, |
| + | void *user_data); |
| + | |
| + | /* Visit all entries in the set until the callback returns FALSE */ |
| + | void Curl_u32_ptrset_visit(struct u32_ptrset *set, |
| + | Curl_u32_ptrset_visit_cb *cb, |
| + | void *user_data); |
| + | |
| + | #endif /* HEADER_CURL_U32_PTRSET_H */ |
| @@ -1,235 +0,0 @@ | |
| - | /*************************************************************************** |
| - | * _ _ ____ _ |
| - | * Project ___| | | | _ \| | |
| - | * / __| | | | |_) | | |
| - | * | (__| |_| | _ <| |___ |
| - | * \___|\___/|_| \_\_____| |
| - | * |
| - | * Copyright (C) Daniel Stenberg, <[email protected]>, et al. |
| - | * |
| - | * This software is licensed as described in the file COPYING, which |
| - | * you should have received as part of this distribution. The terms |
| - | * are also available at https://curl.se/docs/copyright.html. |
| - | * |
| - | * You may opt to use, copy, modify, merge, publish, distribute and/or sell |
| - | * copies of the Software, and permit persons to whom the Software is |
| - | * furnished to do so, under the terms of the COPYING file. |
| - | * |
| - | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY |
| - | * KIND, either express or implied. |
| - | * |
| - | * SPDX-License-Identifier: curl |
| - | * |
| - | ***************************************************************************/ |
| - | #include "curl_setup.h" |
| - | |
| - | #include "uint-hash.h" |
| - | |
| - | /* random patterns for API verification */ |
| - | #ifdef DEBUGBUILD |
| - | #define CURL_UINT32_HASHINIT 0x7117e779 |
| - | #endif |
| - | |
| - | static uint32_t uint32_hash_hash(uint32_t id, uint32_t slots) |
| - | { |
| - | return (id % slots); |
| - | } |
| - | |
| - | struct uint_hash_entry { |
| - | struct uint_hash_entry *next; |
| - | void *value; |
| - | uint32_t id; |
| - | }; |
| - | |
| - | void Curl_uint32_hash_init(struct uint_hash *h, |
| - | uint32_t slots, |
| - | Curl_uint32_hash_dtor *dtor) |
| - | { |
| - | DEBUGASSERT(h); |
| - | DEBUGASSERT(slots); |
| - | |
| - | h->table = NULL; |
| - | h->dtor = dtor; |
| - | h->size = 0; |
| - | h->slots = slots; |
| - | #ifdef DEBUGBUILD |
| - | h->init = CURL_UINT32_HASHINIT; |
| - | #endif |
| - | } |
| - | |
| - | static struct uint_hash_entry *uint32_hash_mk_entry(uint32_t id, void *value) |
| - | { |
| - | struct uint_hash_entry *e; |
| - | |
| - | /* allocate the struct for the hash entry */ |
| - | e = curlx_malloc(sizeof(*e)); |
| - | if(e) { |
| - | e->id = id; |
| - | e->next = NULL; |
| - | e->value = value; |
| - | } |
| - | return e; |
| - | } |
| - | |
| - | static void uint32_hash_entry_clear(struct uint_hash *h, |
| - | struct uint_hash_entry *e) |
| - | { |
| - | DEBUGASSERT(h); |
| - | DEBUGASSERT(e); |
| - | if(e->value) { |
| - | if(h->dtor) |
| - | h->dtor(e->id, e->value); |
| - | e->value = NULL; |
| - | } |
| - | } |
| - | |
| - | static void uint32_hash_entry_destroy(struct uint_hash *h, |
| - | struct uint_hash_entry *e) |
| - | { |
| - | uint32_hash_entry_clear(h, e); |
| - | curlx_free(e); |
| - | } |
| - | |
| - | static void uint32_hash_entry_unlink(struct uint_hash *h, |
| - | struct uint_hash_entry **he_anchor, |
| - | struct uint_hash_entry *he) |
| - | { |
| - | *he_anchor = he->next; |
| - | --h->size; |
| - | } |
| - | |
| - | static void uint32_hash_elem_link(struct uint_hash *h, |
| - | struct uint_hash_entry **he_anchor, |
| - | struct uint_hash_entry *he) |
| - | { |
| - | he->next = *he_anchor; |
| - | *he_anchor = he; |
| - | ++h->size; |
| - | } |
| - | |
| - | #define CURL_UINT32_HASH_SLOT(h, id) h->table[uint32_hash_hash(id, (h)->slots)] |
| - | #define CURL_UINT32_HASH_SLOT_ADDR(h, id) &CURL_UINT32_HASH_SLOT(h, id) |
| - | |
| - | bool Curl_uint32_hash_set(struct uint_hash *h, uint32_t id, void *value) |
| - | { |
| - | struct uint_hash_entry *he, **slot; |
| - | |
| - | DEBUGASSERT(h); |
| - | DEBUGASSERT(h->slots); |
| - | DEBUGASSERT(h->init == CURL_UINT32_HASHINIT); |
| - | if(!h->table) { |
| - | h->table = curlx_calloc(h->slots, sizeof(*he)); |
| - | if(!h->table) |
| - | return FALSE; /* OOM */ |
| - | } |
| - | |
| - | slot = CURL_UINT32_HASH_SLOT_ADDR(h, id); |
| - | for(he = *slot; he; he = he->next) { |
| - | if(he->id == id) { |
| - | /* existing key entry, overwrite by clearing old pointer */ |
| - | uint32_hash_entry_clear(h, he); |
| - | he->value = value; |
| - | return TRUE; |
| - | } |
| - | } |
| - | |
| - | he = uint32_hash_mk_entry(id, value); |
| - | if(!he) |
| - | return FALSE; /* OOM */ |
| - | |
| - | uint32_hash_elem_link(h, slot, he); |
| - | return TRUE; |
| - | } |
| - | |
| - | bool Curl_uint32_hash_remove(struct uint_hash *h, uint32_t id) |
| - | { |
| - | DEBUGASSERT(h); |
| - | DEBUGASSERT(h->slots); |
| - | DEBUGASSERT(h->init == CURL_UINT32_HASHINIT); |
| - | if(h->table) { |
| - | struct uint_hash_entry *he, **he_anchor; |
| - | |
| - | he_anchor = CURL_UINT32_HASH_SLOT_ADDR(h, id); |
| - | while(*he_anchor) { |
| - | he = *he_anchor; |
| - | if(id == he->id) { |
| - | uint32_hash_entry_unlink(h, he_anchor, he); |
| - | uint32_hash_entry_destroy(h, he); |
| - | return TRUE; |
| - | } |
| - | he_anchor = &he->next; |
| - | } |
| - | } |
| - | return FALSE; |
| - | } |
| - | |
| - | void *Curl_uint32_hash_get(struct uint_hash *h, uint32_t id) |
| - | { |
| - | DEBUGASSERT(h); |
| - | DEBUGASSERT(h->init == CURL_UINT32_HASHINIT); |
| - | if(h->table) { |
| - | struct uint_hash_entry *he; |
| - | DEBUGASSERT(h->slots); |
| - | he = CURL_UINT32_HASH_SLOT(h, id); |
| - | while(he) { |
| - | if(id == he->id) { |
| - | return he->value; |
| - | } |
| - | he = he->next; |
| - | } |
| - | } |
| - | return NULL; |
| - | } |
| - | |
| - | /* @unittest 1616 */ |
| - | UNITTEST void uint_hash_clear(struct uint_hash *h); |
| - | UNITTEST void uint_hash_clear(struct uint_hash *h) |
| - | { |
| - | if(h && h->table) { |
| - | struct uint_hash_entry *he, **he_anchor; |
| - | size_t i; |
| - | DEBUGASSERT(h->init == CURL_UINT32_HASHINIT); |
| - | for(i = 0; i < h->slots; ++i) { |
| - | he_anchor = &h->table[i]; |
| - | while(*he_anchor) { |
| - | he = *he_anchor; |
| - | uint32_hash_entry_unlink(h, he_anchor, he); |
| - | uint32_hash_entry_destroy(h, he); |
| - | } |
| - | } |
| - | } |
| - | } |
| - | |
| - | void Curl_uint32_hash_destroy(struct uint_hash *h) |
| - | { |
| - | DEBUGASSERT(h->init == CURL_UINT32_HASHINIT); |
| - | if(h->table) { |
| - | uint_hash_clear(h); |
| - | curlx_safefree(h->table); |
| - | } |
| - | DEBUGASSERT(h->size == 0); |
| - | h->slots = 0; |
| - | } |
| - | |
| - | uint32_t Curl_uint32_hash_count(struct uint_hash *h) |
| - | { |
| - | DEBUGASSERT(h->init == CURL_UINT32_HASHINIT); |
| - | return h->size; |
| - | } |
| - | |
| - | void Curl_uint32_hash_visit(struct uint_hash *h, |
| - | Curl_uint32_hash_visit_cb *cb, |
| - | void *user_data) |
| - | { |
| - | if(h && h->table && cb) { |
| - | struct uint_hash_entry *he; |
| - | size_t i; |
| - | DEBUGASSERT(h->init == CURL_UINT32_HASHINIT); |
| - | for(i = 0; i < h->slots; ++i) { |
| - | for(he = h->table[i]; he; he = he->next) { |
| - | if(!cb(he->id, he->value, user_data)) |
| - | return; |
| - | } |
| - | } |
| - | } |
| - | } |
| @@ -1,59 +0,0 @@ | |
| - | #ifndef HEADER_CURL_UINT_HASH_H |
| - | #define HEADER_CURL_UINT_HASH_H |
| - | /*************************************************************************** |
| - | * _ _ ____ _ |
| - | * Project ___| | | | _ \| | |
| - | * / __| | | | |_) | | |
| - | * | (__| |_| | _ <| |___ |
| - | * \___|\___/|_| \_\_____| |
| - | * |
| - | * Copyright (C) Daniel Stenberg, <[email protected]>, et al. |
| - | * |
| - | * This software is licensed as described in the file COPYING, which |
| - | * you should have received as part of this distribution. The terms |
| - | * are also available at https://curl.se/docs/copyright.html. |
| - | * |
| - | * You may opt to use, copy, modify, merge, publish, distribute and/or sell |
| - | * copies of the Software, and permit persons to whom the Software is |
| - | * furnished to do so, under the terms of the COPYING file. |
| - | * |
| - | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY |
| - | * KIND, either express or implied. |
| - | * |
| - | * SPDX-License-Identifier: curl |
| - | * |
| - | ***************************************************************************/ |
| - | #include "curl_setup.h" |
| - | |
| - | /* A version with uint32_t as key */ |
| - | typedef void Curl_uint32_hash_dtor(uint32_t id, void *value); |
| - | struct uint_hash_entry; |
| - | |
| - | /* Hash for `uint32_t` as key */ |
| - | struct uint_hash { |
| - | struct uint_hash_entry **table; |
| - | Curl_uint32_hash_dtor *dtor; |
| - | uint32_t slots; |
| - | uint32_t size; |
| - | #ifdef DEBUGBUILD |
| - | int init; |
| - | #endif |
| - | }; |
| - | |
| - | void Curl_uint32_hash_init(struct uint_hash *h, |
| - | uint32_t slots, |
| - | Curl_uint32_hash_dtor *dtor); |
| - | void Curl_uint32_hash_destroy(struct uint_hash *h); |
| - | bool Curl_uint32_hash_set(struct uint_hash *h, uint32_t id, void *value); |
| - | bool Curl_uint32_hash_remove(struct uint_hash *h, uint32_t id); |
| - | void *Curl_uint32_hash_get(struct uint_hash *h, uint32_t id); |
| - | uint32_t Curl_uint32_hash_count(struct uint_hash *h); |
| - | |
| - | typedef bool Curl_uint32_hash_visit_cb(uint32_t id, void *value, |
| - | void *user_data); |
| - | |
| - | void Curl_uint32_hash_visit(struct uint_hash *h, |
| - | Curl_uint32_hash_visit_cb *cb, |
| - | void *user_data); |
| - | |
| - | #endif /* HEADER_CURL_UINT_HASH_H */ |
| @@ -49,7 +49,7 @@ | |
| #include "urldata.h" | |
| #include "url.h" | |
| - | #include "uint-hash.h" |
| + | #include "u32_ptrset.h" |
| #include "curl_trc.h" | |
| #include "rand.h" | |
| #include "multiif.h" | |
| @@ -90,7 +90,7 @@ void Curl_cf_ngtcp2_h3_stream_ctx_free(struct h3_stream_ctx *stream) | |
| curlx_free(stream); | |
| } | |
| - | static void h3_stream_hash_free(unsigned int id, void *stream) |
| + | static void h3_stream_set_free(uint32_t id, void *stream) |
| { | |
| (void)id; | |
| DEBUGASSERT(stream); | |
| @@ -129,7 +129,7 @@ CURLcode Curl_cf_ngtcp2_ctx_init(struct cf_ngtcp2_ctx *ctx, | |
| Curl_bufcp_init(&ctx->stream_bufcp, H3_STREAM_CHUNK_SIZE, | |
| H3_STREAM_POOL_SPARES); | |
| curlx_dyn_init(&ctx->scratch, CURL_MAX_HTTP_HEADER); | |
| - | Curl_uint32_hash_init(&ctx->streams, 63, h3_stream_hash_free); |
| + | Curl_u32_ptrset_init(&ctx->streams, h3_stream_set_free); |
| ctx->init_h3_conn_cb = init_h3_conn_cb; | |
| ctx->initialized = TRUE; | |
| return Curl_vquic_tls_peer_init(origin, peer, sslc, &ctx->ssl_peer); | |
| @@ -142,7 +142,7 @@ void Curl_cf_ngtcp2_ctx_cleanup(struct cf_ngtcp2_ctx *ctx) | |
| Curl_vquic_ctx_free(&ctx->q); | |
| Curl_bufcp_free(&ctx->stream_bufcp); | |
| curlx_dyn_free(&ctx->scratch); | |
| - | Curl_uint32_hash_destroy(&ctx->streams); |
| + | Curl_u32_ptrset_clear(&ctx->streams); |
| Curl_ssl_peer_cleanup(&ctx->ssl_peer); | |
| curlx_safefree(ctx->tunnel_inbuf); | |
| ctx->tunnel_inbuf_len = 0; | |
| @@ -1399,7 +1399,7 @@ static struct h3_stream_ctx *cf_ngtcp2_get_stream(struct cf_ngtcp2_ctx *ctx, | |
| struct cf_ngtcp2_sfind_ctx fctx; | |
| fctx.stream_id = stream_id; | |
| fctx.stream = NULL; | |
| - | Curl_uint32_hash_visit(&ctx->streams, cf_ngtcp2_sfind, &fctx); |
| + | Curl_u32_ptrset_visit(&ctx->streams, cf_ngtcp2_sfind, &fctx); |
| return fctx.stream; | |
| } | |
| #else | |
| @@ -1857,7 +1857,7 @@ static void cf_ngtcp2_setup_keep_alive(struct Curl_cfilter *cf, | |
| ngtcp2_conn_set_keep_alive_timeout(ctx->qconn, UINT64_MAX); | |
| CURL_TRC_CF(data, cf, "no peer idle timeout, unset keep-alive"); | |
| } | |
| - | else if(!Curl_uint32_hash_count(&ctx->streams)) { |
| + | else if(!Curl_u32_ptrset_count(&ctx->streams)) { |
| ngtcp2_conn_set_keep_alive_timeout(ctx->qconn, UINT64_MAX); | |
| CURL_TRC_CF(data, cf, "no active streams, unset keep-alive"); | |
| } | |
| @@ -1900,12 +1900,12 @@ CURLcode Curl_cf_ngtcp2_h3_stream_setup(struct Curl_cfilter *cf, | |
| stream->window_size_max = H3_STREAM_WINDOW_SIZE_INITIAL; | |
| Curl_h1_req_parse_init(&stream->h1, H1_PARSE_DEFAULT_MAX_LINE_LEN); | |
| - | if(!Curl_uint32_hash_set(&ctx->streams, data->mid, stream)) { |
| + | if(Curl_u32_ptrset_set(&ctx->streams, data->mid, stream)) { |
| Curl_cf_ngtcp2_h3_stream_ctx_free(stream); | |
| return CURLE_OUT_OF_MEMORY; | |
| } | |
| - | if(Curl_uint32_hash_count(&ctx->streams) == 1) |
| + | if(Curl_u32_ptrset_count(&ctx->streams) == 1) |
| cf_ngtcp2_setup_keep_alive(cf, data); | |
| return CURLE_OK; | |
| @@ -1942,8 +1942,8 @@ void Curl_cf_ngtcp2_h3_stream_done(struct Curl_cfilter *cf, | |
| if(stream) { | |
| CURL_TRC_CF(data, cf, "[%" PRId64 "] easy handle is done", stream->id); | |
| Curl_cf_ngtcp2_h3_stream_close(cf, data, stream); | |
| - | Curl_uint32_hash_remove(&ctx->streams, data->mid); |
| - | if(!Curl_uint32_hash_count(&ctx->streams)) |
| + | Curl_u32_ptrset_unset(&ctx->streams, data->mid); |
| + | if(!Curl_u32_ptrset_count(&ctx->streams)) |
| cf_ngtcp2_setup_keep_alive(cf, data); | |
| } | |
| } | |
| @@ -58,7 +58,7 @@ | |
| #include <nghttp3/nghttp3.h> | |
| #include "http1.h" | |
| - | #include "uint-hash.h" |
| + | #include "u32_ptrset.h" |
| #include "vtls/vtls.h" | |
| #include "vquic/vquic_int.h" | |
| #include "vquic/vquic-tls.h" | |
| @@ -128,7 +128,7 @@ struct cf_ngtcp2_ctx { | |
| struct curltime handshake_at; /* time connect handshake finished */ | |
| struct bufc_pool stream_bufcp; /* chunk pool for streams */ | |
| struct dynbuf scratch; /* temp buffer for header construction */ | |
| - | struct uint_hash streams; /* hash data->mid to h3_stream_ctx */ |
| + | struct u32_ptrset streams; /* set of data->mid + h3_stream_ctx */ |
| uint64_t used_bidi_streams; /* bidi streams we have opened */ | |
| uint64_t max_bidi_streams; /* max bidi streams we can open */ | |
| size_t earlydata_max; /* max amount of early data supported by | |
| @@ -27,7 +27,7 @@ | |
| #include "urldata.h" | |
| #include "url.h" | |
| - | #include "uint-hash.h" |
| + | #include "u32_ptrset.h" |
| #include "curl_trc.h" | |
| #include "rand.h" | |
| #include "multiif.h" | |
| @@ -29,7 +29,7 @@ | |
| #include <openssl/ssl.h> | |
| #include "bufq.h" | |
| - | #include "uint-hash.h" |
| + | #include "u32_ptrset.h" |
| #include "urldata.h" | |
| #include "cfilters.h" | |
| #include "cf-socket.h" | |
| @@ -86,7 +86,7 @@ struct cf_quiche_ctx { | |
| uint8_t scid[QUICHE_MAX_CONN_ID_LEN]; | |
| struct curltime started_at; /* time the current attempt started */ | |
| struct curltime handshake_at; /* time connect handshake finished */ | |
| - | struct uint_hash streams; /* hash `data->mid` to `stream_ctx` */ |
| + | struct u32_ptrset streams; /* set of `data->mid` + `stream_ctx` */ |
| struct dynbuf h1hdr; /* temp buffer for header construction */ | |
| struct bufq writebuf; /* temp buffer for writing bodies */ | |
| curl_off_t data_recvd; | |
| @@ -107,7 +107,7 @@ static void quiche_debug_log(const char *line, void *argp) | |
| } | |
| #endif | |
| - | static void h3_stream_hash_free(unsigned int id, void *stream); |
| + | static void h3_stream_set_free(uint32_t id, void *stream); |
| static CURLcode cf_quiche_ctx_init(struct cf_quiche_ctx *ctx, | |
| struct Curl_peer *origin, | |
| @@ -122,7 +122,7 @@ static CURLcode cf_quiche_ctx_init(struct cf_quiche_ctx *ctx, | |
| } | |
| #endif | |
| curlx_dyn_init(&ctx->h1hdr, CURL_MAX_HTTP_HEADER); | |
| - | Curl_uint32_hash_init(&ctx->streams, 63, h3_stream_hash_free); |
| + | Curl_u32_ptrset_init(&ctx->streams, h3_stream_set_free); |
| Curl_bufq_init2(&ctx->writebuf, H3_STREAM_CHUNK_SIZE, H3_STREAM_RECV_CHUNKS, | |
| BUFQ_OPT_SOFT_LIMIT); | |
| ctx->data_recvd = 0; | |
| @@ -138,7 +138,7 @@ static void cf_quiche_ctx_free(struct cf_quiche_ctx *ctx) | |
| Curl_vquic_tls_cleanup(&ctx->tls); | |
| Curl_ssl_peer_cleanup(&ctx->ssl_peer); | |
| Curl_vquic_ctx_free(&ctx->q); | |
| - | Curl_uint32_hash_destroy(&ctx->streams); |
| + | Curl_u32_ptrset_clear(&ctx->streams); |
| curlx_dyn_free(&ctx->h1hdr); | |
| Curl_bufq_free(&ctx->writebuf); | |
| } | |
| @@ -193,7 +193,7 @@ static void h3_stream_ctx_free(struct h3_stream_ctx *stream) | |
| curlx_free(stream); | |
| } | |
| - | static void h3_stream_hash_free(unsigned int id, void *stream) |
| + | static void h3_stream_set_free(uint32_t id, void *stream) |
| { | |
| (void)id; | |
| DEBUGASSERT(stream); | |
| @@ -233,7 +233,7 @@ static void cf_quiche_for_all_streams(struct Curl_cfilter *cf, | |
| vctx.multi = multi; | |
| vctx.cb = do_cb; | |
| vctx.user_data = user_data; | |
| - | Curl_uint32_hash_visit(&ctx->streams, cf_quiche_stream_do, &vctx); |
| + | Curl_u32_ptrset_visit(&ctx->streams, cf_quiche_stream_do, &vctx); |
| } | |
| static bool cf_quiche_do_resume(struct Curl_cfilter *cf, | |
| @@ -278,7 +278,7 @@ static CURLcode h3_data_setup(struct Curl_cfilter *cf, | |
| stream->id = -1; | |
| Curl_h1_req_parse_init(&stream->h1, H1_PARSE_DEFAULT_MAX_LINE_LEN); | |
| - | if(!Curl_uint32_hash_set(&ctx->streams, data->mid, stream)) { |
| + | if(Curl_u32_ptrset_set(&ctx->streams, data->mid, stream)) { |
| h3_stream_ctx_free(stream); | |
| return CURLE_OUT_OF_MEMORY; | |
| } | |
| @@ -318,7 +318,7 @@ static void h3_data_done(struct Curl_cfilter *cf, struct Curl_easy *data) | |
| if(stream) { | |
| CURL_TRC_CF(data, cf, "[%" PRIu64 "] easy handle is done", stream->id); | |
| cf_quiche_stream_close(cf, data, stream); | |
| - | Curl_uint32_hash_remove(&ctx->streams, data->mid); |
| + | Curl_u32_ptrset_unset(&ctx->streams, data->mid); |
| } | |
| } | |
| @@ -635,7 +635,7 @@ static CURLcode cf_poll_events(struct Curl_cfilter *cf, | |
| dctx.cf = cf; | |
| dctx.multi = data->multi; | |
| dctx.ev = ev; | |
| - | Curl_uint32_hash_visit(&ctx->streams, cf_quiche_disp_event, &dctx); |
| + | Curl_u32_ptrset_visit(&ctx->streams, cf_quiche_disp_event, &dctx); |
| quiche_h3_event_free(ev); | |
| } | |
| } | |
| @@ -28,6 +28,7 @@ | |
| #ifdef USE_HTTP3 | |
| #include "bufq.h" | |
| + | #include "u32_ptrset.h" |
| #define MAX_UDP_PAYLOAD_SIZE 1452 | |
| @@ -78,7 +79,7 @@ struct cf_quic_ctx { | |
| }; | |
| #define H3_STREAM_CTX(ctx, data) \ | |
| - | ((data) ? Curl_uint32_hash_get(&(ctx)->streams, (data)->mid) : NULL) |
| + | ((data) ? Curl_u32_ptrset_get(&(ctx)->streams, (data)->mid) : NULL) |
| CURLcode Curl_vquic_ctx_init(struct Curl_easy *data, | |
| struct cf_quic_ctx *qctx); | |
| @@ -1634,7 +1634,6 @@ TESTCASES = \ | |
| test1613 \ | |
| test1614 \ | |
| test1615 \ | |
| - | test1616 \ |
| test1617 \ | |
| test1618 \ | |
| test1619 \ | |
| @@ -1,19 +0,0 @@ | |
| - | <?xml version="1.0" encoding="US-ASCII"?> |
| - | <testcase> |
| - | <info> |
| - | <keywords> |
| - | unittest |
| - | uint_hash |
| - | </keywords> |
| - | </info> |
| - | |
| - | # Client-side |
| - | <client> |
| - | <features> |
| - | unittest |
| - | </features> |
| - | <name> |
| - | uint_hash create/add/destroy testing, exercising clean functions |
| - | </name> |
| - | </client> |
| - | </testcase> |
| @@ -5,6 +5,7 @@ | |
| unittest | |
| uint_bset | |
| u8_strset | |
| + | u32_ptrset |
| </keywords> | |
| </info> | |
| @@ -14,7 +15,7 @@ u8_strset | |
| unittest | |
| </features> | |
| <name> | |
| - | uint_bset and u8_strset unit tests |
| + | uint_bset, u8_strset and u32_ptrset unit tests |
| </name> | |
| </client> | |
| </testcase> | |
| @@ -55,7 +55,6 @@ TESTS_C = \ | |
| unit1612.c \ | |
| unit1614.c \ | |
| unit1615.c \ | |
| - | unit1616.c \ |
| unit1620.c \ | |
| unit1625.c \ | |
| unit1626.c \ | |
| @@ -120,7 +120,7 @@ static CURLcode test_unit1399(const char *arg) | |
| /* Accumulated times are now 3 seconds: | |
| * - 2 after 1st request start | |
| - | * - 1 aftger 2nd requerst start */ |
| + | * - 1 after 2nd requerst start */ |
| expect_timer_seconds(data, 3); | |
| UNITTEST_END(t1399_stop(data)) | |
| @@ -1,85 +0,0 @@ | |
| - | /*************************************************************************** |
| - | * _ _ ____ _ |
| - | * Project ___| | | | _ \| | |
| - | * / __| | | | |_) | | |
| - | * | (__| |_| | _ <| |___ |
| - | * \___|\___/|_| \_\_____| |
| - | * |
| - | * Copyright (C) Daniel Stenberg, <[email protected]>, et al. |
| - | * |
| - | * This software is licensed as described in the file COPYING, which |
| - | * you should have received as part of this distribution. The terms |
| - | * are also available at https://curl.se/docs/copyright.html. |
| - | * |
| - | * You may opt to use, copy, modify, merge, publish, distribute and/or sell |
| - | * copies of the Software, and permit persons to whom the Software is |
| - | * furnished to do so, under the terms of the COPYING file. |
| - | * |
| - | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY |
| - | * KIND, either express or implied. |
| - | * |
| - | * SPDX-License-Identifier: curl |
| - | * |
| - | ***************************************************************************/ |
| - | #include "unitcheck.h" |
| - | #include "uint-hash.h" |
| - | |
| - | static void t1616_mydtor(uint32_t id, void *elem) |
| - | { |
| - | int *ptr = (int *)elem; |
| - | (void)id; |
| - | curlx_free(ptr); |
| - | } |
| - | |
| - | static CURLcode t1616_setup(struct uint_hash *hash) |
| - | { |
| - | Curl_uint32_hash_init(hash, 15, t1616_mydtor); |
| - | return CURLE_OK; |
| - | } |
| - | |
| - | static void t1616_stop(struct uint_hash *hash) |
| - | { |
| - | Curl_uint32_hash_destroy(hash); |
| - | } |
| - | |
| - | static CURLcode test_unit1616(const char *arg) |
| - | { |
| - | struct uint_hash hash; |
| - | |
| - | UNITTEST_BEGIN(t1616_setup(&hash)) |
| - | |
| - | int *value, *v; |
| - | int *value2; |
| - | bool ok; |
| - | |
| - | uint32_t key = 20; |
| - | uint32_t key2 = 25; |
| - | |
| - | value = curlx_malloc(sizeof(int)); |
| - | abort_unless(value, "Out of memory"); |
| - | *value = 199; |
| - | ok = Curl_uint32_hash_set(&hash, key, value); |
| - | if(!ok) |
| - | curlx_free(value); |
| - | abort_unless(ok, "insertion into hash failed"); |
| - | v = Curl_uint32_hash_get(&hash, key); |
| - | abort_unless(v == value, "lookup present entry failed"); |
| - | v = Curl_uint32_hash_get(&hash, key2); |
| - | abort_unless(!v, "lookup missing entry failed"); |
| - | uint_hash_clear(&hash); |
| - | |
| - | /* Attempt to add another key/value pair */ |
| - | value2 = curlx_malloc(sizeof(int)); |
| - | abort_unless(value2, "Out of memory"); |
| - | *value2 = 204; |
| - | ok = Curl_uint32_hash_set(&hash, key2, value2); |
| - | if(!ok) |
| - | curlx_free(value2); |
| - | abort_unless(ok, "insertion into hash failed"); |
| - | v = Curl_uint32_hash_get(&hash, key2); |
| - | abort_unless(v == value2, "lookup present entry failed"); |
| - | v = Curl_uint32_hash_get(&hash, key); |
| - | abort_unless(!v, "lookup missing entry failed"); |
| - | |
| - | UNITTEST_END(t1616_stop(&hash)) |
| - | } |
| @@ -25,6 +25,7 @@ | |
| #include "urldata.h" | |
| #include "uint-bset.h" | |
| #include "u8_strset.h" | |
| + | #include "u32_ptrset.h" |
| #include "curl_trc.h" | |
| static void t3211_check_bset(const char *name, uint32_t capacity, | |
| @@ -202,7 +203,7 @@ static void t3211_check_u8_strset(void) | |
| fail_unless(!t3211_strcmp(buf, Curl_u8_strset_get(&set, idx)), | |
| "wrong get loop5"); | |
| } | |
| - | fail_unless(Curl_u8_strset_count(&set) == 9, "wrong count aftger add 5"); |
| + | fail_unless(Curl_u8_strset_count(&set) == 9, "wrong count after add 5"); |
| Curl_u8_strset_clear(&set); | |
| @@ -220,6 +221,62 @@ static void t3211_check_u8_strset(void) | |
| fail_unless(!Curl_u8_strset_count(&set), "cleared strset not empty"); | |
| } | |
| + | static void t3211_check_u32_ptrset(void) |
| + | { |
| + | struct u32_ptrset set; |
| + | CURLcode result; |
| + | uint32_t i, idx; |
| + | |
| + | Curl_u32_ptrset_init(&set, NULL); |
| + | fail_unless(!Curl_u32_ptrset_count(&set), "initial ptrset not empty"); |
| + | |
| + | result = Curl_u32_ptrset_set(&set, 0, CURL_UNCONST("123")); |
| + | fail_unless(!result, "ptrset add1 failed"); |
| + | fail_unless(Curl_u32_ptrset_get(&set, 0), "ptrset get failed"); |
| + | fail_unless(!t3211_strcmp("123", Curl_u32_ptrset_get(&set, 0)), |
| + | "ptrset wrong get1"); |
| + | result = Curl_u32_ptrset_set(&set, 0, CURL_UNCONST("456")); |
| + | fail_unless(!result, "add2 failed"); |
| + | fail_unless(!t3211_strcmp("456", Curl_u32_ptrset_get(&set, 0)), |
| + | "ptrset wrong get2"); |
| + | Curl_u32_ptrset_unset(&set, 0); |
| + | fail_unless(!Curl_u32_ptrset_get(&set, 0), "ptrset unset failed"); |
| + | |
| + | /* Initial size is 64, add 64 hash collisions */ |
| + | for(i = 0; i < 64; ++i) { |
| + | idx = (uint32_t)((64 * i) + 3); |
| + | result = Curl_u32_ptrset_set(&set, idx, CURL_UNCONST("loop64")); |
| + | fail_unless(!result, "ptrset loop64 add failed"); |
| + | fail_unless(!t3211_strcmp("loop64", Curl_u32_ptrset_get(&set, idx)), |
| + | "ptrset wrong get loop64"); |
| + | } |
| + | |
| + | /* Remove collided entry 2, check again */ |
| + | idx = (uint32_t)((64 * 2) + 3); |
| + | Curl_u32_ptrset_unset(&set, idx); |
| + | fail_unless(!Curl_u32_ptrset_get(&set, idx), "ptrset unset2 failed"); |
| + | |
| + | /* Add entry 2 again, check */ |
| + | idx = (uint8_t)((64 * 2) + 3); |
| + | result = Curl_u32_ptrset_set(&set, idx, CURL_UNCONST("loop64b")); |
| + | fail_unless(!result, "ptrset re-add 2 failed"); |
| + | fail_unless(!t3211_strcmp("loop64b", Curl_u32_ptrset_get(&set, idx)), |
| + | "ptrset wrong re-add 2 get"); |
| + | |
| + | /* Add a 65th, set grows */ |
| + | fail_unless(Curl_u32_ptrset_count(&set) == 64, |
| + | "ptrset wrong count pre add 5"); |
| + | idx = (uint32_t)((65 * 4) + 3); |
| + | result = Curl_u32_ptrset_set(&set, idx, CURL_UNCONST("add65")); |
| + | fail_unless(!result, "ptrset add65 failed"); |
| + | fail_unless(!t3211_strcmp("add65", Curl_u32_ptrset_get(&set, idx)), |
| + | "ptrset wrong result after add65"); |
| + | fail_unless(Curl_u32_ptrset_count(&set) == 65, "wrong count after add65"); |
| + | |
| + | Curl_u32_ptrset_clear(&set); |
| + | fail_unless(!Curl_u32_ptrset_count(&set), "ptrset cleared not empty"); |
| + | } |
| + | |
| static CURLcode test_unit3211(const char *arg) | |
| { | |
| UNITTEST_BEGIN_SIMPLE | |
| @@ -244,6 +301,7 @@ static CURLcode test_unit3211(const char *arg) | |
| t3211_check_bset("s2", 1000, s2, CURL_ARRAYSIZE(s2)); | |
| t3211_check_u8_strset(); | |
| + | t3211_check_u32_ptrset(); |
| UNITTEST_END_SIMPLE | |
| } | |