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