SHOGUN  v2.0.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
Map.h
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or modify
3  * it under the terms of the GNU General Public License as published by
4  * the Free Software Foundation; either version 3 of the License, or
5  * (at your option) any later version.
6  *
7  * Written (W) 2012 Evgeniy Andreev (gsomix)
8  *
9  * Copyright (C) 2012 Evgeniy Andreev (gsomix)
10  */
11 
12 #ifndef _MAP_H_
13 #define _MAP_H_
14 
15 #include <shogun/base/SGObject.h>
16 #include <shogun/lib/common.h>
17 #include <shogun/lib/Hash.h>
18 #include <shogun/base/DynArray.h>
19 
20 #include <cstdio>
21 
22 #include <shogun/io/SGIO.h>
23 #include <shogun/base/Parallel.h>
24 
25 #ifdef HAVE_PTHREAD
26 #include <pthread.h>
27 #endif
28 
29 namespace shogun
30 {
31 
32 #define IGNORE_IN_CLASSLIST
33 
34 #define MapNode CMapNode<K, T>
35 
36 #ifndef DOXYGEN_SHOULD_SKIP_THIS
37 
38 IGNORE_IN_CLASSLIST template<class K, class T> struct CMapNode
39 {
41  int32_t index;
42 
44  bool free;
45 
47  K key;
48 
50  T data;
51 
53  CMapNode *left;
54 
56  CMapNode *right;
57 };
58 #endif
59 
63 IGNORE_IN_CLASSLIST template<class K, class T> class CMap: public CSGObject
64 {
65 public:
67  CMap(int32_t size=41, int32_t reserved=128, bool tracable=true)
68  {
69  hash_size=size;
70  free_index=0;
71  num_elements=0;
72  use_sg_mallocs=tracable;
73 
74  if (use_sg_mallocs)
76  else
77  hash_array=(CMapNode<K, T>**) calloc(size, sizeof(CMapNode<K, T>*));
78 
79  for (int32_t i=0; i<size; i++)
80  {
81  hash_array[i]=NULL;
82  }
83 
84  array=new DynArray<CMapNode<K, T>*>(reserved, tracable);
85 
86 #ifdef HAVE_PTHREAD
87  PTHREAD_LOCK_INIT(&lock);
88 #endif
89  }
90 
92  virtual ~CMap()
93  {
94 #ifdef HAVE_PTHREAD
95  PTHREAD_LOCK_DESTROY(&lock);
96 #endif
97  destroy_map();
98  }
99 
101  virtual const char* get_name() const { return "Map"; }
102 
109  int32_t add(const K& key, const T& data)
110  {
111  int32_t index=hash(key);
112  if (chain_search(index, key)==NULL)
113  {
114 #ifdef HAVE_PTHREAD
115  PTHREAD_LOCK(&lock);
116 #endif
117  int32_t added_index=insert_key(index, key, data);
118  num_elements++;
119 #ifdef HAVE_PTHREAD
120  PTHREAD_UNLOCK(&lock);
121 #endif
122 
123  return added_index;
124  }
125 
126  return -1;
127  }
128 
134  bool contains(const K& key)
135  {
136  int32_t index=hash(key);
137  if (chain_search(index, key)!=NULL)
138  return true;
139 
140  return false;
141  }
142 
147  void remove(const K& key)
148  {
149  int32_t index=hash(key);
150  CMapNode<K, T>* result=chain_search(index, key);
151 
152  if (result!=NULL)
153  {
154 #ifdef HAVE_PTHREAD
155  PTHREAD_LOCK(&lock);
156 #endif
157  delete_key(index, result);
158  num_elements--;
159 #ifdef HAVE_PTHREAD
160  PTHREAD_UNLOCK(&lock);
161 #endif
162  }
163  }
164 
170  int32_t index_of(const K& key)
171  {
172  int32_t index=hash(key);
173  CMapNode<K ,T>* result=chain_search(index, key);
174 
175  if (result!=NULL)
176  return result->index;
177 
178  return -1;
179  }
180 
187  T get_element(const K& key)
188  {
189  int32_t index=hash(key);
190  CMapNode<K, T>* result=chain_search(index, key);
191 
192  if (result!=NULL)
193  return result->data;
194  else
195  {
196  int32_t added_index=add(key, T());
197  result=get_node_ptr(added_index);
198 
199  return result->data;
200  }
201  }
202 
208  void set_element(const K& key, const T& data)
209  {
210  int32_t index=hash(key);
211  CMapNode<K, T>* result=chain_search(index, key);
212 
213 #ifdef HAVE_PTHREAD
214  PTHREAD_LOCK(&lock);
215 #endif
216  if (result!=NULL)
217  result->data=data;
218  else
219  {
220  add(key, data);
221  }
222 
223 #ifdef HAVE_PTHREAD
224  PTHREAD_UNLOCK(&lock);
225 #endif
226  }
227 
232  int32_t get_num_elements() const
233  {
234  return num_elements;
235  }
236 
241  int32_t get_array_size() const
242  {
243  return array->get_num_elements();
244  }
245 
253  T* get_element_ptr(int32_t index)
254  {
255  CMapNode<K, T>* result=array->get_element(index);
256  if (result!=NULL && !is_free(result))
257  return &(array->get_element(index)->data);
258  return NULL;
259  }
260 
268  CMapNode<K, T>* get_node_ptr(int32_t index)
269  {
270  return array->get_element(index);
271  }
272 
274  CMapNode<K, T>** get_array()
275  {
276  return array->get_array();
277  }
278 
280  CMap& operator =(const CMap& orig)
281  {
282 
283  destroy_map();
285 
286  hash_size = orig.hash_size;
287 
288  if (use_sg_mallocs)
290  else
291  hash_array = (CMapNode<K, T>**) calloc(hash_size,
292  sizeof(CMapNode<K, T>*));
293 
294  for (int32_t i = 0; i<hash_size; i++)
295  {
296  hash_array[i] = NULL;
297  }
298 
300 
301  for (int i = 0; i < orig.num_elements; i++)
302  {
303  CMapNode<K, T>* node = orig.array->get_element(i);
304  add(node->key, node->data);
305  }
306 
307  return *this;
308  }
309 
310 private:
314  int32_t hash(const K& key)
315  {
316  return CHash::MurmurHash3((uint8_t*)(&key), sizeof(key), 0xDEADBEEF) % hash_size;
317  }
318 
320  bool is_free(CMapNode<K, T>* node)
321  {
322  if (node->free==true)
323  return true;
324 
325  return false;
326  }
327 
329  CMapNode<K, T>* chain_search(int32_t index, const K& key)
330  {
331  if (hash_array[index]==NULL)
332  {
333  return NULL;
334  }
335  else
336  {
337  CMapNode<K, T>* current=hash_array[index];
338 
339  do // iterating all items in the list
340  {
341  if (current->key==key)
342  return current; // it's a search key
343 
344  current=current->right;
345 
346  } while (current!=NULL);
347 
348  return NULL;
349  }
350  }
351 
353  int32_t insert_key(int32_t index, const K& key, const T& data)
354  {
355  int32_t new_index;
356  CMapNode<K, T>* new_node;
357 
359  {
360  // init new node
361  if (use_sg_mallocs)
362  new_node=SG_CALLOC(MapNode, 1);
363  else
364  new_node=(CMapNode<K, T>*) calloc(1, sizeof(CMapNode<K, T>));
365 
366  new (&new_node->key) K();
367  new (&new_node->data) T();
368 
369  array->append_element(new_node);
370 
371  new_index=free_index;
372  free_index++;
373  }
374  else
375  {
376  new_node=array->get_element(free_index);
377  ASSERT(is_free(new_node));
378 
379  new_index=free_index;
380  free_index=new_node->index;
381  }
382 
383  new_node->index=new_index;
384  new_node->free=false;
385  new_node->key=key;
386  new_node->data=data;
387  new_node->left=NULL;
388  new_node->right=NULL;
389 
390  // add new node in start of list
391  if (hash_array[index]==NULL)
392  {
393  hash_array[index]=new_node;
394  }
395  else
396  {
397  hash_array[index]->left=new_node;
398  new_node->right=hash_array[index];
399 
400  hash_array[index]=new_node;
401  }
402 
403  return new_index;
404  }
405 
407  void delete_key(int32_t index, CMapNode<K, T>* node)
408  {
409  int32_t temp=0;
410 
411  if (node==NULL)
412  return;
413 
414  if (node->right!=NULL)
415  node->right->left = node->left;
416 
417  if (node->left!=NULL)
418  node->left->right = node->right;
419  else
420  hash_array[index] = node->right;
421 
422  temp=node->index;
423 
424  node->index=free_index;
425  node->free=true;
426  node->left=NULL;
427  node->right=NULL;
428 
429  free_index=temp;
430  }
431 
432  /*cleans up map*/
433  void destroy_map()
434  {
435  if (array!=NULL)
436  {
437  for(int32_t i=0; i<array->get_num_elements(); i++)
438  {
439  CMapNode<K, T>* element = array->get_element(i);
440  if (element!=NULL)
441  {
442  element->key.~K();
443  element->data.~T();
444 
445  if (use_sg_mallocs)
446  SG_FREE(element);
447  else
448  free(element);
449  }
450  }
451  delete array;
452  }
453 
454  if (hash_array!=NULL)
455  {
456  if (use_sg_mallocs)
458  else
459  free(hash_array);
460  }
461 
462  }
463 
464 protected:
467 
469  int32_t hash_size;
470 
472  int32_t free_index;
473 
475  int32_t num_elements;
476 
478  CMapNode<K, T>** hash_array;
479 
482 
483 #ifdef HAVE_PTHREAD
484 
485  PTHREAD_LOCK_T lock;
486 #endif
487 };
488 
489 }
490 
491 #endif /* _MAP_H_ */

SHOGUN Machine Learning Toolbox - Documentation