Hermes2D  2.0
hash.cpp
1 // This file is part of Hermes2D.
2 //
3 // Hermes2D is free software: you can redistribute it and/or modify
4 // it under the terms of the GNU General Public License as published by
5 // the Free Software Foundation, either version 2 of the License, or
6 // (at your option) any later version.
7 //
8 // Hermes2D is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 // GNU General Public License for more details.
12 //
13 // You should have received a copy of the GNU General Public License
14 // along with Hermes2D. If not, see <http://www.gnu.org/licenses/>.
15 
16 #include "global.h"
17 #include "mesh.h"
18 #include "hash.h"
19 
20 namespace Hermes
21 {
22  namespace Hermes2D
23  {
24  HashTable::HashTable()
25  {
26  v_table = NULL; e_table = NULL;
27  }
28 
29  HashTable::~HashTable()
30  {
31  free();
32  }
33 
34  void HashTable::init(int size)
35  {
36  v_table = e_table = NULL;
37 
38  mask = size-1;
39  if(size & mask) throw Hermes::Exceptions::Exception("Parameter 'size' must be a power of two.");
40 
41  // allocate and initialize the hash tables
42  v_table = new Node*[size];
43  e_table = new Node*[size];
44 
45  memset(v_table, 0, size * sizeof(Node*));
46  memset(e_table, 0, size * sizeof(Node*));
47  }
48 
49  void HashTable::copy_list(Node** ptr, Node* node)
50  {
51  while (node != NULL)
52  {
53  *ptr = &nodes[node->id];
54  ptr = &((*ptr)->next_hash);
55  node = node->next_hash;
56  }
57  *ptr = NULL;
58  }
59 
60  Node* HashTable::get_node(int id) const
61  {
62  return &(nodes[id]);
63  }
64 
67  {
68  return nodes.get_num_items();
69  }
70 
73  {
74  return nodes.get_size();
75  }
76 
77  void HashTable::copy(const HashTable* ht)
78  {
79  free();
80  nodes.copy(ht->nodes);
81  mask = ht->mask;
82 
83  v_table = new Node*[mask + 1];
84  e_table = new Node*[mask + 1];
85  for (int i = 0; i <= mask; i++)
86  {
87  copy_list(v_table + i, ht->v_table[i]);
88  copy_list(e_table + i, ht->e_table[i]);
89  }
90  }
91 
93  {
94  memset(v_table, 0, (mask + 1) * sizeof(Node*));
95  memset(e_table, 0, (mask + 1) * sizeof(Node*));
96 
97  Node* node;
98  for_all_nodes(node, this)
99  {
100  int p1 = node->p1, p2 = node->p2;
101  if(p1 > p2) std::swap(p1, p2);
102  int idx = hash(p1, p2);
103 
104  if(node->type == HERMES_TYPE_VERTEX)
105  {
106  node->next_hash = v_table[idx];
107  v_table[idx] = node;
108  }
109  else
110  {
111  node->next_hash = e_table[idx];
112  e_table[idx] = node;
113  }
114  }
115  }
116 
118  {
119  nodes.free();
120  if(v_table != NULL)
121  {
122  delete [] v_table;
123  v_table = NULL;
124  }
125  if(e_table != NULL)
126  {
127  delete [] e_table;
128  e_table = NULL;
129  }
130  }
131 
132  inline Node* HashTable::search_list(Node* node, int p1, int p2) const
133  {
134  while (node != NULL)
135  {
136  if(node->p1 == p1 && node->p2 == p2)
137  return node;
138  node = node->next_hash;
139  }
140  return NULL;
141  }
142 
144  {
145  // search for the node in the vertex hashtable
146  if(p1 > p2) std::swap(p1, p2);
147  int i = hash(p1, p2);
148  Node* node = search_list(v_table[i], p1, p2);
149  if(node != NULL)
150  return node;
151 
152  // not found - create a new one
153  Node* newnode = nodes.add();
154 
155  // initialize the new Node
156  newnode->type = HERMES_TYPE_VERTEX;
157  newnode->ref = 0;
158  newnode->bnd = 0;
159  newnode->p1 = p1;
160  newnode->p2 = p2;
161  assert(nodes[p1].type == HERMES_TYPE_VERTEX && nodes[p2].type == HERMES_TYPE_VERTEX);
162  newnode->x = (nodes[p1].x + nodes[p2].x) * 0.5;
163  newnode->y = (nodes[p1].y + nodes[p2].y) * 0.5;
164 
165  // insert into hashtable
166  newnode->next_hash = v_table[i];
167  v_table[i] = newnode;
168 
169  return newnode;
170  }
171 
173  {
174  // search for the node in the edge hashtable
175  if(p1 > p2) std::swap(p1, p2);
176  int i = hash(p1, p2);
177  Node* node = search_list(e_table[i], p1, p2);
178  if(node != NULL) return node;
179 
180  // not found - create a new one
181  Node* newnode = nodes.add();
182 
183  // initialize the new node
184  newnode->type = HERMES_TYPE_EDGE;
185  newnode->ref = 0;
186  newnode->bnd = 0;
187  newnode->p1 = p1;
188  newnode->p2 = p2;
189  newnode->marker = 0;
190  newnode->elem[0] = newnode->elem[1] = NULL;
191 
192  // insert into hashtable
193  newnode->next_hash = e_table[i];
194  e_table[i] = newnode;
195 
196  return newnode;
197  }
198 
199  Node* HashTable::peek_vertex_node(int p1, int p2) const
200  {
201  if(p1 > p2) std::swap(p1, p2);
202  return search_list(v_table[hash(p1, p2)], p1, p2);
203  }
204 
205  Node* HashTable::peek_edge_node(int p1, int p2) const
206  {
207  if(p1 > p2) std::swap(p1, p2);
208  return search_list(e_table[hash(p1, p2)], p1, p2);
209  }
210 
212  {
213  // remove the node from the hash table
214  int i = hash(nodes[id].p1, nodes[id].p2);
215  Node** ptr = v_table + i;
216  Node* node = *ptr;
217  while (node != NULL)
218  {
219  if(node->id == id)
220  {
221  *ptr = node->next_hash;
222  break;
223  }
224  ptr = &node->next_hash;
225  node = *ptr;
226  }
227 
228  // remove node from the array
229  nodes.remove(id);
230  }
231 
233  {
234  // remove the node from the hash table
235  int i = hash(nodes[id].p1, nodes[id].p2);
236  Node** ptr = e_table + i;
237  Node* node = *ptr;
238  while (node != NULL)
239  {
240  if(node->id == id)
241  {
242  *ptr = node->next_hash;
243  break;
244  }
245  ptr = &node->next_hash;
246  node = *ptr;
247  }
248 
249  // remove node from the array
250  nodes.remove(id);
251  }
252  }
253 }