1 /////////////////////////////////////////////////////////////////////////////// 2 // BSD 3-Clause License 3 // 4 // Copyright (c) 2019, Nefelus Inc 5 // All rights reserved. 6 // 7 // Redistribution and use in source and binary forms, with or without 8 // modification, are permitted provided that the following conditions are met: 9 // 10 // * Redistributions of source code must retain the above copyright notice, this 11 // list of conditions and the following disclaimer. 12 // 13 // * Redistributions in binary form must reproduce the above copyright notice, 14 // this list of conditions and the following disclaimer in the documentation 15 // and/or other materials provided with the distribution. 16 // 17 // * Neither the name of the copyright holder nor the names of its 18 // contributors may be used to endorse or promote products derived from 19 // this software without specific prior written permission. 20 // 21 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 25 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 26 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 27 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 29 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 31 // POSSIBILITY OF SUCH DAMAGE. 32 33 // Header file for the Athena Utilities 34 35 #include <assert.h> 36 //#define _CRTDBG_MAP_ALLOC 37 38 #pragma once 39 40 #include "array1.h" 41 #include "atypes.h" 42 43 unsigned int AthHashFunction(char* key, unsigned int len, unsigned int prime); 44 int Ath__double2int(double v); 45 46 namespace odb { 47 int AthResourceLog(const char* title, int smallScale = 0); 48 } // namespace odb 49 50 // Simple list 51 template <class T> 52 class AthList 53 { 54 private: 55 struct t_elem 56 { 57 T m_data; 58 t_elem* m_next; 59 }; 60 t_elem* m_start; 61 62 public: AthList(void)63 AthList(void) { m_start = NULL; }; ~AthList(void)64 ~AthList(void) 65 { 66 t_elem* i; 67 i = m_start; 68 while (i) { 69 t_elem* next = i->m_next; 70 delete i; 71 i = next; 72 } 73 }; push(T a)74 void push(T a) 75 { 76 t_elem* new_t_elem = new t_elem; 77 new_t_elem->m_next = m_start; 78 new_t_elem->m_data = a; 79 m_start = new_t_elem; 80 }; 81 82 struct iterator 83 { 84 AthList<T>* actual_class; 85 t_elem* ptr_to_elem; 86 nextiterator87 iterator next(void) 88 { 89 ptr_to_elem = ptr_to_elem->m_next; 90 return *this; 91 } 92 getValiterator93 T getVal(void) { return ptr_to_elem->m_data; } 94 enditerator95 bool end(void) 96 { 97 if (ptr_to_elem) 98 return false; 99 else 100 return true; 101 } 102 }; start(void)103 iterator start(void) 104 { 105 iterator ret_val; 106 ret_val.actual_class = this; 107 ret_val.ptr_to_elem = m_start; 108 return ret_val; 109 } 110 }; 111 112 // A class that implements an array that can grow efficiently 113 template <class T> 114 class AthArray 115 { 116 private: 117 unsigned int m_alloc_size; 118 T** m_ptr; 119 unsigned int m_num_allocated_elem; 120 unsigned int m_num_mallocated_elem; 121 unsigned int m_num_mallocated_first_level; find_indexes(unsigned int num,unsigned int & first_level,unsigned int & second_level)122 void find_indexes(unsigned int num, 123 unsigned int& first_level, 124 unsigned int& second_level) 125 { 126 first_level = num / m_alloc_size; 127 second_level = num % m_alloc_size; 128 } 129 130 public: 131 AthArray(unsigned int alloc_size = 128) 132 { 133 if (alloc_size < 2) 134 alloc_size = 2; 135 m_alloc_size = alloc_size; 136 m_num_mallocated_first_level = alloc_size; 137 m_ptr = (T**) malloc(sizeof(T*) * m_num_mallocated_first_level); 138 unsigned int i; 139 for (i = 0; i < m_num_mallocated_first_level; i++) { 140 m_ptr[i] = NULL; 141 } 142 m_num_allocated_elem = 0; 143 m_num_mallocated_elem = 0; 144 } 145 ~AthArray()146 ~AthArray() 147 { 148 unsigned int i; 149 for (i = 0; i < m_num_mallocated_first_level; i++) 150 if (m_ptr[i]) 151 free(m_ptr[i]); 152 free(m_ptr); 153 } allocNext(unsigned int * ii,unsigned int * jj)154 void allocNext(unsigned int* ii, unsigned int* jj) 155 { 156 unsigned int first_level_idx, second_level_idx; 157 find_indexes(m_num_allocated_elem, first_level_idx, second_level_idx); 158 // reallocate first level if it is too small 159 if (m_num_mallocated_first_level * m_alloc_size <= m_num_allocated_elem) { 160 int orig_first_level_size = m_num_mallocated_first_level; 161 m_num_mallocated_first_level++; 162 m_ptr = (T**) realloc(m_ptr, sizeof(T*) * m_num_mallocated_first_level); 163 assert(m_ptr); 164 for (unsigned int i = orig_first_level_size; 165 i < m_num_mallocated_first_level; 166 i++) { 167 m_ptr[i] = NULL; 168 } 169 } 170 // Allocate more elements if needed 171 if (m_ptr[first_level_idx] == NULL) { 172 unsigned int size = sizeof(T); 173 m_ptr[first_level_idx] = (T*) malloc(size * m_alloc_size); 174 m_num_mallocated_elem = m_num_mallocated_first_level * m_alloc_size; 175 } 176 *ii = first_level_idx; 177 *jj = second_level_idx; 178 } add(void)179 void add(void) 180 { 181 unsigned int first_level_idx, second_level_idx; 182 allocNext(&first_level_idx, &second_level_idx); 183 // int n= m_num_allocated_elem++; 184 m_num_allocated_elem++; 185 } add(T elem)186 int add(T elem) 187 { 188 unsigned int first_level_idx, second_level_idx; 189 190 allocNext(&first_level_idx, &second_level_idx); 191 192 m_ptr[first_level_idx][second_level_idx] = elem; 193 int n = m_num_allocated_elem++; 194 return n; 195 } 196 197 T& operator[](unsigned int idx) 198 { 199 /* 200 if (!(idx < m_num_allocated_elem)) { 201 fprintf(stdout, "idx= %d, m_num_allocated_elem= %d\n", idx, 202 m_num_allocated_elem); 203 } 204 */ 205 206 assert(idx < m_num_allocated_elem); 207 unsigned int first_level_idx, second_level_idx; 208 find_indexes(idx, first_level_idx, second_level_idx); 209 return m_ptr[first_level_idx][second_level_idx]; 210 } get(unsigned int idx)211 T get(unsigned int idx) 212 { 213 assert(idx < m_num_allocated_elem); 214 unsigned int first_level_idx, second_level_idx; 215 find_indexes(idx, first_level_idx, second_level_idx); 216 return m_ptr[first_level_idx][second_level_idx]; 217 } getLast(void)218 unsigned int getLast(void) { return m_num_allocated_elem; } 219 }; 220 221 // A simple pool allocation function 222 template <class T> 223 class AthPool 224 { 225 private: 226 AthArray<T>* m_heap; 227 Ath__array1D<T*>* _freeTable; 228 AthArray<T*>* _dbgTable; 229 bool _memDbg; 230 char _className[256]; 231 232 public: 233 AthPool(bool dbgMem, 234 unsigned int freeAllocSize, 235 unsigned int alloc_size = 4096) 236 { 237 m_heap = new AthArray<T>(alloc_size); 238 _freeTable = new Ath__array1D<T*>(freeAllocSize); 239 240 _memDbg = false; 241 _dbgTable = NULL; 242 if (dbgMem) { 243 _dbgTable = new AthArray<T*>(alloc_size); 244 _memDbg = true; 245 } 246 } ~AthPool()247 ~AthPool() 248 { 249 delete m_heap; 250 delete _freeTable; 251 252 if (_dbgTable != NULL) 253 delete _dbgTable; 254 } 255 256 T* alloc(uint* freeTableFlag = NULL, uint* id = NULL) 257 { 258 T* a = NULL; 259 260 if (!_memDbg) { 261 if (_freeTable->notEmpty()) { 262 a = _freeTable->pop(); 263 264 if (freeTableFlag != NULL) 265 *freeTableFlag = 1; 266 } else { 267 m_heap->add(); 268 uint n = m_heap->getLast() - 1; 269 a = &(*m_heap)[n]; 270 271 if (id != NULL) 272 *id = n; 273 274 if (freeTableFlag != NULL) 275 *freeTableFlag = 0; 276 } 277 } else { 278 a = new T; 279 // TODO replace new with malloc 280 // TODO check for error 281 assert(a); 282 283 uint n = _dbgTable->add(a); 284 285 if (id != NULL) 286 *id = n; 287 if (freeTableFlag != NULL) 288 *freeTableFlag = 1; 289 } 290 return a; 291 } free(T * a)292 void free(T* a) 293 { 294 assert(a); // should not free NULL 295 if (_memDbg) { 296 delete a; 297 } else if (_freeTable != NULL) { 298 _freeTable->add(a); 299 } 300 } get(uint ii)301 T* get(uint ii) 302 { 303 T* a = &(*m_heap)[ii]; 304 return a; 305 } getCnt()306 uint getCnt() { return m_heap->getLast(); } 307 }; 308 309 // A simple hash implementation 310 template <class T> 311 class AthHash 312 { 313 unsigned int* m_listOfPrimes; 314 init_list_of_primes(void)315 void init_list_of_primes(void) 316 { 317 m_listOfPrimes = new unsigned int[16]; 318 m_listOfPrimes[0] = 49978783; 319 m_listOfPrimes[1] = 18409199; 320 m_listOfPrimes[2] = 1299827; 321 m_listOfPrimes[3] = 1176221; 322 m_listOfPrimes[4] = 981493; 323 m_listOfPrimes[5] = 779377; 324 m_listOfPrimes[6] = 530279; 325 m_listOfPrimes[7] = 143567; 326 m_listOfPrimes[8] = 30389; 327 m_listOfPrimes[9] = 6869; 328 m_listOfPrimes[10] = 1049; 329 m_listOfPrimes[11] = 149; 330 m_listOfPrimes[12] = 11; 331 m_listOfPrimes[13] = 3; 332 m_listOfPrimes[14] = 2; 333 m_listOfPrimes[15] = 1; 334 } 335 336 // unsigned int m_prime; 337 l_find_largest_prime_below_number(unsigned int number)338 unsigned int l_find_largest_prime_below_number(unsigned int number) 339 { 340 assert(number > 3); 341 int i = 0; 342 while (m_listOfPrimes[i] > number) 343 i++; 344 return m_listOfPrimes[i]; 345 } 346 hashFunction(char * key,unsigned int,unsigned int prime)347 unsigned int hashFunction(char* key, unsigned int, unsigned int prime) 348 { 349 unsigned int hash = 0; 350 int c; 351 352 while ((c = *key++) != '\0') 353 hash = c + (hash << 6) + (hash << 16) - hash; 354 355 return hash % prime; 356 } 357 358 #if 0 359 // original "broken" hash function 360 unsigned int hashFunction(char *key, unsigned int len, 361 unsigned int prime) 362 { 363 unsigned int hash, i; 364 for (hash=len, i=0; i<len; ++i) 365 hash = (hash<<4)^(hash>>28)^key[i]; 366 return (hash % prime); 367 } 368 #endif 369 370 struct t_elem 371 { 372 char* key; 373 T data; 374 }; 375 int _allocKeyFlag; 376 // AthList<t_elem> *m_data; 377 public: 378 AthList<t_elem>* m_data; 379 unsigned int m_prime; 380 381 AthHash(unsigned int size = 100, int store = 1) 382 { 383 init_list_of_primes(); 384 m_prime = l_find_largest_prime_below_number(size); 385 m_data = new AthList<t_elem>[m_prime]; 386 _allocKeyFlag = store; 387 } 388 ~AthHash()389 ~AthHash() 390 { 391 delete m_listOfPrimes; 392 unsigned int i; 393 for (i = 0; i < m_prime; i++) { 394 typename AthList<t_elem>::iterator iter = m_data[i].start(); 395 while (!iter.end()) { 396 if (_allocKeyFlag > 0) 397 free(iter.getVal().key); 398 iter.next(); 399 } 400 } 401 delete[] m_data; 402 } 403 add(char * key,T data)404 void add(char* key, T data) 405 { 406 unsigned int hash_val = hashFunction(key, strlen(key), m_prime); 407 t_elem new_t_elem; 408 new_t_elem.data = data; 409 if (_allocKeyFlag > 0) 410 new_t_elem.key = strdup(key); 411 else 412 new_t_elem.key = key; 413 m_data[hash_val].push(new_t_elem); 414 } 415 416 // Get a stored value. Returns success of failure depending 417 // if the value actually is stored or not get(char * key,T & data)418 bool get(char* key, T& data) 419 { 420 unsigned int hash_val = hashFunction(key, strlen(key), m_prime); 421 typename AthList<t_elem>::iterator iter = m_data[hash_val].start(); 422 while (!iter.end()) { 423 if (strcmp(key, iter.getVal().key) == 0) { 424 data = iter.getVal().data; 425 return true; 426 } 427 iter.next(); 428 } 429 return false; 430 } 431 struct iterator 432 { 433 unsigned int m_first_level_idx; 434 typename AthList<t_elem>::iterator m_list_iterator; 435 AthHash<T>* m_ptr_to_hash; 436 nextiterator437 iterator next() 438 { 439 if (m_list_iterator.end()) { 440 m_first_level_idx++; 441 m_list_iterator = m_ptr_to_hash->m_data[m_first_level_idx].start(); 442 } else { 443 m_list_iterator.next(); 444 } 445 if (m_list_iterator.end()) { 446 assert(m_first_level_idx < m_ptr_to_hash->m_prime); 447 return next(); 448 } else 449 return *this; 450 } 451 enditerator452 bool end() 453 { 454 if (m_first_level_idx >= m_ptr_to_hash->m_prime) 455 return true; 456 if (m_first_level_idx < m_ptr_to_hash->m_prime - 1) 457 return false; 458 return m_list_iterator.end(); 459 } 460 getValiterator461 T getVal(void) { return m_list_iterator.getVal().data; } 462 getKeyiterator463 char* getKey(void) { return m_list_iterator.getVal().key; } 464 }; 465 start(void)466 iterator start(void) 467 { 468 iterator tmp_iter; 469 unsigned int i; 470 for (i = 0; i < m_prime; i++) { 471 tmp_iter.m_list_iterator = m_data[i].start(); 472 if (!tmp_iter.m_list_iterator.end()) 473 break; 474 } 475 tmp_iter.m_first_level_idx = i; 476 tmp_iter.m_ptr_to_hash = this; 477 return tmp_iter; 478 } 479 }; 480