/* * Copyright (c) 2010-2013 BitTorrent, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #ifndef __UTP_HASH_H__ #define __UTP_HASH_H__ #include // memset #include // malloc #include "utp_types.h" #include "utp_templates.h" // TODO: make utp_link_t a template parameter to HashTable typedef uint32 utp_link_t; #ifdef _MSC_VER // Silence the warning about the C99-compliant zero-length array at the end of the structure #pragma warning (disable: 4200) #endif typedef uint32 (*utp_hash_compute_t)(const void *keyp, size_t keysize); typedef uint (*utp_hash_equal_t)(const void *key_a, const void *key_b, size_t keysize); // In memory the HashTable is laid out as follows: // ---------------------------- low // | hash table data members | // ---------------------------- _ // | indices | ^ // | . | | utp_link_t indices into the key-values. // | . | . // ---------------------------- - <----- bep // | keys and values | each key-value pair has size total_size // | . | // | . | // ---------------------------- high // // The code depends on the ability of the compiler to pad the length // of the hash table data members structure to // a length divisible by 32-bits with no remainder. // // Since the number of hash buckets (indices) should be odd, the code // asserts this and adds one to the hash bucket count to ensure that the // following key-value pairs array starts on a 32-bit boundary. // // The key-value pairs array should start on a 32-bit boundary, otherwise // processors like the ARM will silently mangle 32-bit data in these structures // (e.g., turning 0xABCD into 0XCDAB when moving a value from memory to register // when the memory address is 16 bits offset from a 32-bit boundary), // also, the value will be stored at an address two bytes lower than the address // value would ordinarily indicate. // // The key-value pair is of type T. The first field in T must // be the key, i.e., the first K bytes of T contains the key. // total_size = sizeof(T) and thus sizeof(T) >= sizeof(K) // // N is the number of buckets. // struct utp_hash_t { utp_link_t N; byte K; byte E; size_t count; utp_hash_compute_t hash_compute; utp_hash_equal_t hash_equal; utp_link_t allocated; utp_link_t used; utp_link_t free; utp_link_t inits[0]; }; #ifdef _MSC_VER #pragma warning (default: 4200) #endif struct utp_hash_iterator_t { utp_link_t bucket; utp_link_t elem; utp_hash_iterator_t() : bucket(0xffffffff), elem(0xffffffff) {} }; uint utp_hash_mem(const void *keyp, size_t keysize); uint utp_hash_comp(const void *key_a, const void *key_b, size_t keysize); utp_hash_t *utp_hash_create(int N, int key_size, int total_size, int initial, utp_hash_compute_t hashfun = utp_hash_mem, utp_hash_equal_t eqfun = NULL); void *utp_hash_lookup(utp_hash_t *hash, const void *key); void *utp_hash_add(utp_hash_t **hashp, const void *key); void *utp_hash_del(utp_hash_t *hash, const void *key); void *utp_hash_iterate(utp_hash_t *hash, utp_hash_iterator_t *iter); void utp_hash_free_mem(utp_hash_t *hash); /* This HashTable requires that T have at least sizeof(K)+sizeof(utp_link_t) bytes. Usually done like this: struct K { int whatever; }; struct T { K wtf; utp_link_t link; // also wtf }; */ template class utpHashTable { utp_hash_t *hash; public: static uint compare(const void *k1, const void *k2, size_t ks) { return *((K*)k1) == *((K*)k2); } static uint32 compute_hash(const void *k, size_t ks) { return ((K*)k)->compute_hash(); } void Init() { hash = NULL; } bool Allocated() { return (hash != NULL); } void Free() { utp_hash_free_mem(hash); hash = NULL; } void Create(int N, int initial) { hash = utp_hash_create(N, sizeof(K), sizeof(T), initial, &compute_hash, &compare); } T *Lookup(const K &key) { return (T*)utp_hash_lookup(hash, &key); } T *Add(const K &key) { return (T*)utp_hash_add(&hash, &key); } T *Delete(const K &key) { return (T*)utp_hash_del(hash, &key); } T *Iterate(utp_hash_iterator_t &iterator) { return (T*)utp_hash_iterate(hash, &iterator); } size_t GetCount() { return hash->count; } }; #endif //__UTP_HASH_H__