Path: blob/21.2-virgl/src/gallium/auxiliary/cso_cache/cso_hash.c
4565 views
/**************************************************************************1*2* Copyright 2007 VMware, Inc.3* All Rights Reserved.4*5* Permission is hereby granted, free of charge, to any person obtaining a6* copy of this software and associated documentation files (the7* "Software"), to deal in the Software without restriction, including8* without limitation the rights to use, copy, modify, merge, publish,9* distribute, sub license, and/or sell copies of the Software, and to10* permit persons to whom the Software is furnished to do so, subject to11* the following conditions:12*13* The above copyright notice and this permission notice (including the14* next paragraph) shall be included in all copies or substantial portions15* of the Software.16*17* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS18* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF19* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.20* IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR21* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,22* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE23* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.24*25**************************************************************************/2627/*28* Authors:29* Zack Rusin <[email protected]>30*/3132#include "util/u_debug.h"33#include "util/u_memory.h"3435#include "cso_hash.h"3637#ifndef MAX38#define MAX(a, b) ((a > b) ? (a) : (b))39#endif4041static const int MinNumBits = 4;4243static const unsigned char prime_deltas[] = {440, 0, 1, 3, 1, 5, 3, 3, 1, 9, 7, 5, 3, 9, 25, 3,451, 21, 3, 21, 7, 15, 9, 5, 3, 29, 15, 0, 0, 0, 0, 046};4748static int primeForNumBits(int numBits)49{50return (1 << numBits) + prime_deltas[numBits];51}5253/*54Returns the smallest integer n such that55primeForNumBits(n) >= hint.56*/57static int countBits(int hint)58{59int numBits = 0;60int bits = hint;6162while (bits > 1) {63bits >>= 1;64numBits++;65}6667if (numBits >= (int)sizeof(prime_deltas)) {68numBits = sizeof(prime_deltas) - 1;69} else if (primeForNumBits(numBits) < hint) {70++numBits;71}72return numBits;73}7475static struct cso_node *76cso_hash_create_node(struct cso_hash *hash,77unsigned akey, void *avalue,78struct cso_node **anextNode)79{80struct cso_node *node = MALLOC(sizeof(struct cso_node));8182if (!node)83return NULL;8485node->key = akey;86node->value = avalue;8788node->next = *anextNode;89*anextNode = node;90++hash->size;91return node;92}9394static void cso_data_rehash(struct cso_hash *hash, int hint)95{96if (hint < 0) {97hint = countBits(-hint);98if (hint < MinNumBits)99hint = MinNumBits;100hash->userNumBits = (short)hint;101while (primeForNumBits(hint) < (hash->size >> 1))102++hint;103} else if (hint < MinNumBits) {104hint = MinNumBits;105}106107if (hash->numBits != hint) {108struct cso_node *e = (struct cso_node *)hash;109struct cso_node **oldBuckets = hash->buckets;110int oldNumBuckets = hash->numBuckets;111int i = 0;112113hash->numBits = (short)hint;114hash->numBuckets = primeForNumBits(hint);115hash->buckets = MALLOC(sizeof(struct cso_node*) * hash->numBuckets);116for (i = 0; i < hash->numBuckets; ++i)117hash->buckets[i] = e;118119for (i = 0; i < oldNumBuckets; ++i) {120struct cso_node *firstNode = oldBuckets[i];121while (firstNode != e) {122unsigned h = firstNode->key;123struct cso_node *lastNode = firstNode;124struct cso_node *afterLastNode;125struct cso_node **beforeFirstNode;126127while (lastNode->next != e && lastNode->next->key == h)128lastNode = lastNode->next;129130afterLastNode = lastNode->next;131beforeFirstNode = &hash->buckets[h % hash->numBuckets];132while (*beforeFirstNode != e)133beforeFirstNode = &(*beforeFirstNode)->next;134lastNode->next = *beforeFirstNode;135*beforeFirstNode = firstNode;136firstNode = afterLastNode;137}138}139FREE(oldBuckets);140}141}142143static void cso_data_might_grow(struct cso_hash *hash)144{145if (hash->size >= hash->numBuckets)146cso_data_rehash(hash, hash->numBits + 1);147}148149static void cso_data_has_shrunk(struct cso_hash *hash)150{151if (hash->size <= (hash->numBuckets >> 3) &&152hash->numBits > hash->userNumBits) {153int max = MAX(hash->numBits-2, hash->userNumBits);154cso_data_rehash(hash, max);155}156}157158static struct cso_node *cso_data_first_node(struct cso_hash *hash)159{160struct cso_node *e = (struct cso_node *)hash;161struct cso_node **bucket = hash->buckets;162int n = hash->numBuckets;163164while (n--) {165if (*bucket != e)166return *bucket;167++bucket;168}169return e;170}171172struct cso_hash_iter cso_hash_insert(struct cso_hash *hash,173unsigned key, void *data)174{175cso_data_might_grow(hash);176177struct cso_node **nextNode = cso_hash_find_node(hash, key);178struct cso_node *node = cso_hash_create_node(hash, key, data, nextNode);179if (!node) {180struct cso_hash_iter null_iter = {hash, 0};181return null_iter;182}183184struct cso_hash_iter iter = {hash, node};185return iter;186}187188void cso_hash_init(struct cso_hash *hash)189{190hash->fakeNext = 0;191hash->buckets = 0;192hash->size = 0;193hash->userNumBits = (short)MinNumBits;194hash->numBits = 0;195hash->numBuckets = 0;196hash->end = (struct cso_node*)hash;197}198199void cso_hash_deinit(struct cso_hash *hash)200{201struct cso_node *e_for_x = hash->end;202struct cso_node **bucket = hash->buckets;203int n = hash->numBuckets;204205while (n--) {206struct cso_node *cur = *bucket++;207while (cur != e_for_x) {208struct cso_node *next = cur->next;209FREE(cur);210cur = next;211}212}213FREE(hash->buckets);214}215216unsigned cso_hash_iter_key(struct cso_hash_iter iter)217{218if (!iter.node || iter.hash->end == iter.node)219return 0;220return iter.node->key;221}222223struct cso_node *cso_hash_data_next(struct cso_node *node)224{225union {226struct cso_node *next;227struct cso_node *e;228struct cso_hash *d;229} a;230int start;231struct cso_node **bucket;232int n;233234a.next = node->next;235if (!a.next) {236debug_printf("iterating beyond the last element\n");237return NULL;238}239if (a.next->next)240return a.next;241242start = (node->key % a.d->numBuckets) + 1;243bucket = a.d->buckets + start;244n = a.d->numBuckets - start;245while (n--) {246if (*bucket != a.e)247return *bucket;248++bucket;249}250return a.e;251}252253void *cso_hash_take(struct cso_hash *hash, unsigned akey)254{255struct cso_node **node = cso_hash_find_node(hash, akey);256257if (*node != hash->end) {258void *t = (*node)->value;259struct cso_node *next = (*node)->next;260FREE(*node);261*node = next;262--hash->size;263cso_data_has_shrunk(hash);264return t;265}266return NULL;267}268269struct cso_hash_iter cso_hash_first_node(struct cso_hash *hash)270{271struct cso_hash_iter iter = {hash, cso_data_first_node(hash)};272return iter;273}274275int cso_hash_size(struct cso_hash *hash)276{277return hash->size;278}279280struct cso_hash_iter cso_hash_erase(struct cso_hash *hash, struct cso_hash_iter iter)281{282struct cso_hash_iter ret = iter;283struct cso_node *node = iter.node;284struct cso_node **node_ptr;285286if (node == hash->end)287return iter;288289ret = cso_hash_iter_next(ret);290node_ptr = &hash->buckets[node->key % hash->numBuckets];291while (*node_ptr != node)292node_ptr = &(*node_ptr)->next;293*node_ptr = node->next;294FREE(node);295--hash->size;296return ret;297}298299bool cso_hash_contains(struct cso_hash *hash, unsigned key)300{301struct cso_node **node = cso_hash_find_node(hash, key);302return *node != hash->end;303}304305306