/
githubmirror
/
curl
Обзор
Документация
Войти
/
githubmirror
/
curl
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
lib/uint-spbset.c
305 строк
9 KB
Stefan Eissing
uint-spbset: reused empty chunks
21 июл 2026, 01:38
Не верифицирован
21 июл 2026, 01:38
c5fd5eb
Код
Авторство
О чём код?
/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, 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-bset.h" #include "uint-spbset.h" #ifdef DEBUGBUILD #define CURL_UINT32_SPBSET_MAGIC 0x70737362 #endif void Curl_uint32_spbset_init(struct uint32_spbset *bset) { memset(bset, 0, sizeof(*bset)); #ifdef DEBUGBUILD bset->init = CURL_UINT32_SPBSET_MAGIC; #endif } /* Clear the bitset, making it empty. @unittest 3213 */ UNITTEST void uint32_spbset_clear(struct uint32_spbset *bset); UNITTEST void uint32_spbset_clear(struct uint32_spbset *bset) { struct uint32_spbset_chunk *next, *chunk; for(chunk = bset->head.next; chunk; chunk = next) { next = chunk->next; curlx_free(chunk); } memset(&bset->head, 0, sizeof(bset->head)); } void Curl_uint32_spbset_destroy(struct uint32_spbset *bset) { DEBUGASSERT(bset->init == CURL_UINT32_SPBSET_MAGIC); uint32_spbset_clear(bset); } uint32_t Curl_uint32_spbset_count(struct uint32_spbset *bset) { struct uint32_spbset_chunk *chunk; uint32_t i, n = 0; for(chunk = &bset->head; chunk; chunk = chunk->next) { for(i = 0; i < CURL_UINT32_SPBSET_CH_SLOTS; ++i) { if(chunk->slots[i]) n += CURL_POPCOUNT64(chunk->slots[i]); } } return n; } static bool uint32_spbset_empty_chunk(struct uint32_spbset_chunk *chunk) { uint32_t i; for(i = 0; i < CURL_UINT32_SPBSET_CH_SLOTS; ++i) { if(chunk->slots[i]) return FALSE; } return TRUE; } static struct uint32_spbset_chunk *uint32_spbset_unlink_empty( struct uint32_spbset *bset, uint32_t for_offset) { struct uint32_spbset_chunk *chunk, **panchor = NULL; for(chunk = &bset->head; chunk; panchor = &chunk->next, chunk = chunk->next) { if(uint32_spbset_empty_chunk(chunk)) break; } if(chunk) { if(chunk == &bset->head) { /* head chunk is empty */ if(!bset->head.next || (for_offset < bset->head.next->offset)) { return &bset->head; } /* swap head and next, unlink */ chunk = bset->head.next; memcpy(&bset->head, chunk, sizeof(bset->head)); memset(chunk, 0, sizeof(*chunk)); } else { *panchor = chunk->next; /* unlink */ memset(chunk, 0, sizeof(*chunk)); } } return chunk; } static struct uint32_spbset_chunk *uint32_spbset_insert_chunk( struct uint32_spbset *bset, struct uint32_spbset_chunk *nchunk) { struct uint32_spbset_chunk *chunk, **panchor; /* insert nchunk into set's ordered chunk list */ if(nchunk->offset < bset->head.offset) { /* swap chunk and head */ uint32_t offset = nchunk->offset; memcpy(nchunk, &bset->head, sizeof(*nchunk)); memset(&bset->head, 0, sizeof(bset->head)); bset->head.next = nchunk; bset->head.offset = offset; return &bset->head; } DEBUGASSERT(nchunk->offset > bset->head.offset); panchor = &bset->head.next; for(chunk = *panchor; chunk; panchor = &chunk->next, chunk = chunk->next) { if(chunk->offset > nchunk->offset) { /* insert before this chunk */ nchunk->next = chunk; *panchor = nchunk; return nchunk; } } /* no chunk with larger offset, append */ *panchor = nchunk; return nchunk; } static struct uint32_spbset_chunk *uint32_spbset_get_chunk( struct uint32_spbset *bset, uint32_t i, bool grow) { struct uint32_spbset_chunk *chunk; uint32_t i_offset = (i & ~CURL_UINT32_SPBSET_CH_MASK); if(!bset) return NULL; for(chunk = &bset->head; chunk; chunk = chunk->next) { if(chunk->offset == i_offset) return chunk; else if(chunk->offset > i_offset) break; /* need new chunk here */ } if(!grow) /* just a check if the chunk exists */ return NULL; /* Is there an empty chunk to reuse? */ chunk = uint32_spbset_unlink_empty(bset, i_offset); if(chunk) { chunk->offset = i_offset; if(chunk == &bset->head) /* head chunk is empty, stayed linked */ return &bset->head; /* was really unlinked, need to insert below */ } else { /* need a new one */ chunk = curlx_calloc(1, sizeof(*chunk)); if(!chunk) return NULL; chunk->offset = i_offset; } return uint32_spbset_insert_chunk(bset, chunk); } bool Curl_uint32_spbset_add(struct uint32_spbset *bset, uint32_t i) { struct uint32_spbset_chunk *chunk = uint32_spbset_get_chunk(bset, i, TRUE); if(!chunk) return FALSE; DEBUGASSERT(i >= chunk->offset); i -= chunk->offset; DEBUGASSERT(i < (CURL_UINT32_SPBSET_CH_SLOTS * 64)); chunk->slots[(i / 64)] |= ((uint64_t)1 << (i % 64)); return TRUE; } void Curl_uint32_spbset_remove(struct uint32_spbset *bset, uint32_t i) { struct uint32_spbset_chunk *chunk = uint32_spbset_get_chunk(bset, i, FALSE); if(chunk) { DEBUGASSERT(i >= chunk->offset); i -= chunk->offset; DEBUGASSERT(i < (CURL_UINT32_SPBSET_CH_SLOTS * 64)); chunk->slots[(i / 64)] &= ~((uint64_t)1 << (i % 64)); } } bool Curl_uint32_spbset_contains(struct uint32_spbset *bset, uint32_t i) { struct uint32_spbset_chunk *chunk = uint32_spbset_get_chunk(bset, i, FALSE); if(chunk) { DEBUGASSERT(i >= chunk->offset); i -= chunk->offset; DEBUGASSERT(i < (CURL_UINT32_SPBSET_CH_SLOTS * 64)); return (chunk->slots[i / 64] & ((uint64_t)1 << (i % 64))) != 0; } return FALSE; } bool Curl_uint32_spbset_first(struct uint32_spbset *bset, uint32_t *pfirst) { struct uint32_spbset_chunk *chunk; uint32_t i; for(chunk = &bset->head; chunk; chunk = chunk->next) { for(i = 0; i < CURL_UINT32_SPBSET_CH_SLOTS; ++i) { if(chunk->slots[i]) { *pfirst = chunk->offset + ((i * 64) + CURL_CTZ64(chunk->slots[i])); return TRUE; } } } *pfirst = 0; /* give it a defined value even if it should not be used */ return FALSE; } static bool uint32_spbset_chunk_first(struct uint32_spbset_chunk *chunk, uint32_t *pfirst) { uint32_t i; for(i = 0; i < CURL_UINT32_SPBSET_CH_SLOTS; ++i) { if(chunk->slots[i]) { *pfirst = chunk->offset + ((i * 64) + CURL_CTZ64(chunk->slots[i])); return TRUE; } } *pfirst = UINT32_MAX; /* a value we cannot store */ return FALSE; } static bool uint32_spbset_chunk_next(struct uint32_spbset_chunk *chunk, uint32_t last, uint32_t *pnext) { if(chunk->offset <= last) { uint64_t x; uint32_t i = ((last - chunk->offset) / 64); if(i < CURL_UINT32_SPBSET_CH_SLOTS) { x = (chunk->slots[i] >> (last % 64)); if(x) { /* more bits set, next is `last` + trailing 0s of the shifted slot */ *pnext = last + CURL_CTZ64(x); return TRUE; } /* no more bits set in the last slot, scan forward */ for(i = i + 1; i < CURL_UINT32_SPBSET_CH_SLOTS; ++i) { if(chunk->slots[i]) { *pnext = chunk->offset + ((i * 64) + CURL_CTZ64(chunk->slots[i])); return TRUE; } } } } *pnext = UINT32_MAX; return FALSE; } bool Curl_uint32_spbset_next(struct uint32_spbset *bset, uint32_t last, uint32_t *pnext) { struct uint32_spbset_chunk *chunk; uint32_t last_offset; ++last; /* look for the next higher number */ last_offset = (last & ~CURL_UINT32_SPBSET_CH_MASK); for(chunk = &bset->head; chunk; chunk = chunk->next) { if(chunk->offset >= last_offset) { break; } } if(chunk && (chunk->offset == last_offset)) { /* is there a number higher than last in this chunk? */ if(uint32_spbset_chunk_next(chunk, last, pnext)) return TRUE; /* not in this chunk */ chunk = chunk->next; } /* look for the first in the "higher" chunks, if there are any. */ while(chunk) { if(uint32_spbset_chunk_first(chunk, pnext)) return TRUE; chunk = chunk->next; } *pnext = UINT32_MAX; return FALSE; }