HermesCommon  3.0
array.h
Go to the documentation of this file.
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/>.
18 #ifndef __HERMES_COMMON_ARRAY_H
19 #define __HERMES_COMMON_ARRAY_H
20 
21 #include "common.h"
22 #include "../util/memory_handling.h"
23 
24 #ifndef INVALID_IDX
25 #define INVALID_IDX INT_MAX
26 #endif
27 namespace Hermes
28 {
37 
38 #define HERMES_PAGE_BITS 8
39 #define HERMES_PAGE_SIZE (1 << HERMES_PAGE_BITS)
40 #define HERMES_PAGE_MASK (HERMES_PAGE_SIZE - 1)
41 
42  template<class TYPE>
43  class Array
44  {
45  protected:
47  TYPE** pages;
48  int* unused;
49  unsigned int page_count, size, nitems, unused_size, nunused;
50  bool append_only;
51  public:
52 
53  Array(int initial_page_count = 0) : pages(nullptr), unused(nullptr)
54  {
55  size = nitems = nunused = 0;
56  page_count = initial_page_count;
57  unused_size = initial_page_count;
58 
59  if (page_count)
60  {
61  this->pages = malloc_with_check<Array<TYPE>, TYPE*>(page_count, this, true);
62  for (unsigned i = 0; i < this->page_count; i++)
63  this->pages[i] = malloc_with_check<Array<TYPE>, TYPE>(HERMES_PAGE_SIZE, this);
64  this->unused = malloc_with_check<Array<TYPE>, int>(unused_size, this, true);
65  }
66  else
67  {
68  this->pages = nullptr;
69  this->unused = nullptr;
70  }
71  append_only = false;
72  }
73 
74  Array(Array& array) { copy(array); }
75 
76  ~Array()
77  {
78  free();
79  free_with_check(this->pages, true);
80  free_with_check(this->unused, true);
81  }
82 
84  void copy(const Array& array)
85  {
86  free();
87 
88  this->pages = realloc_with_check<Array, TYPE*>(this->pages, array.page_count, this);
89  this->unused = realloc_with_check<Array, int>(this->unused, array.unused_size, this);
90 
91  memcpy(this->unused, array.unused, array.unused_size * sizeof(int));
92 
93  this->page_count = array.page_count;
94  this->size = array.size;
95  this->nitems = array.nitems;
96  this->unused_size = array.unused_size;
97  this->nunused = array.nunused;
98  this->append_only = array.append_only;
99 
100  for (unsigned i = 0; i < this->page_count; i++)
101  {
102  TYPE* new_page = malloc_with_check<Array<TYPE>, TYPE>(HERMES_PAGE_SIZE, this);
103  memcpy(new_page, array.pages[i], sizeof(TYPE)* HERMES_PAGE_SIZE);
104  this->pages[i] = new_page;
105  }
106  }
107 
109  void free()
110  {
111  for (unsigned i = 0; i < this->page_count; i++)
112  free_with_check(pages[i]);
113  size = nitems = nunused = page_count = unused_size = 0;
114  }
115 
121  void set_append_only(bool append_only)
122  {
123  this->append_only = append_only;
124  }
125 
127  int add(TYPE item)
128  {
129  TYPE* ptr = this->add();
130  *ptr = item;
131  return ptr->id;
132  }
133 
138  TYPE* add()
139  {
140  TYPE* item;
141  if (!nunused || append_only)
142  {
143  if (!(size & HERMES_PAGE_MASK))
144  {
145  this->pages = realloc_with_check <Array<TYPE>, TYPE*>(this->pages, this->page_count + 1, this);
146  TYPE* new_page = malloc_with_check<Array<TYPE>, TYPE>(HERMES_PAGE_SIZE, this);
147  pages[this->page_count++] = new_page;
148  }
149  item = pages[size >> HERMES_PAGE_BITS] + (size & HERMES_PAGE_MASK);
150  item->id = size++;
151  item->used = 1;
152  }
153  else
154  {
155  int id = unused[nunused-- - 1];
156  item = pages[id >> HERMES_PAGE_BITS] + (id & HERMES_PAGE_MASK);
157  item->used = 1;
158  }
159  nitems++;
160  return item;
161  }
162 
167  void remove(int id)
168  {
169  TYPE* item = pages[id >> HERMES_PAGE_BITS] + (id & HERMES_PAGE_MASK);
170  item->used = 0;
171  if (nunused >= unused_size)
172  {
173  this->unused_size = std::max<int>(unused_size + 1, (int)(unused_size * 1.5));
174  this->unused = realloc_with_check<Array, int>(this->unused, this->unused_size, this);
175  }
176  unused[nunused++] = id;
177  nitems--;
178  }
179 
180  // Iterators
181 
188  int first(int idx = 0)
189  {
190  int index = idx;
191  while (get(index).used == false)
192  {
193  index++;
194  if (index >= nitems) return INVALID_IDX;
195  }
196  return index;
197  }
198 
205  int next(int idx = 0)
206  {
207  int index = idx + 1;
208  while (get(index).used == false)
209  {
210  index++;
211  if (index >= nitems) return INVALID_IDX;
212  }
213  return index;
214  }
215 
222  int last(int idx = INT_MAX)
223  {
224  int index = idx;
225  if (index > nitems - 1) index = nitems - 1;
226  while (get(index).used == false)
227  {
228  index--;
229  if (index < 0) return INVALID_IDX;
230  }
231  return index;
232  }
233 
240  int prev(int idx = INT_MAX)
241  {
242  int index = idx - 1;
243  if (index > nitems - 1) index = nitems - 1;
244  while (get(index).used == false)
245  {
246  index--;
247  if (index < 0) return INVALID_IDX;
248  }
249  return index;
250  }
251 
253  bool exists(int idx)
254  {
255  if (get(idx).used == true) return true;
256  else return false;
257  }
258 
261  TYPE* skip_slot()
262  {
263  if (!(size & HERMES_PAGE_MASK))
264  {
265  int local_page_count = this->page_count;
266  this->page_count = std::max<int>(this->page_count + 1, (int)(this->page_count * 1.5));
267  this->pages = realloc_with_check<Array, TYPE*>(this->pages, this->page_count, this);
268  for (int new_i = local_page_count; new_i < this->page_count; new_i++)
269  pages[new_i] = malloc_with_check<Array, TYPE>(HERMES_PAGE_SIZE, this);
270  }
271  TYPE* item = pages[size >> HERMES_PAGE_BITS] + (size & HERMES_PAGE_MASK);
272  item->id = size++;
273  item->used = 0;
274  nitems++;
275  return item;
276  }
277 
278  int get_size() const { return size; }
279  int get_num_items() const { return nitems; }
280 
281  TYPE& get(int id) const { return pages[id >> HERMES_PAGE_BITS][id & HERMES_PAGE_MASK]; }
282  TYPE& operator[] (int id) const { return get(id); }
283  };
284 
287  template<class TYPE>
289  {
290  protected:
291  TYPE** pages;
292  int page_count;
293  bool ** presence;
294  unsigned int size;
295 
296  const unsigned int page_bits;
297  const unsigned int page_size;
298  const unsigned int page_mask;
299 
300  public:
301 
302  LightArray(unsigned int page_bits = 9, unsigned int default_page_count = 512) : page_bits(page_bits), page_size(1 << page_bits), page_mask((1 << page_bits) - 1), page_count(default_page_count), pages(nullptr), presence(nullptr)
303  {
304  size = 0;
305  pages = malloc_with_check<LightArray<TYPE>, TYPE*>(page_count, this, true);
306  presence = malloc_with_check<LightArray<TYPE>, bool*>(page_count, this, true);
307 
308  for (int i = 0; i < page_count; i++)
309  {
310  pages[i] = malloc_with_check<LightArray<TYPE>, TYPE>(page_size, this);
311  presence[i] = calloc_with_check<LightArray<TYPE>, bool>(page_size, this);
312  }
313  }
314 
315  void clear()
316  {
317  for (unsigned int i = 0; i < page_count; i++)
318  {
319  memset(presence[i], 0, page_size * sizeof(bool));
320  }
321  }
322 
323  ~LightArray()
324  {
325  free();
326  }
327 
328  void free()
329  {
330  for (unsigned int i = 0; i < page_count; i++)
331  {
332  free_with_check(pages[i]);
333  free_with_check(presence[i]);
334  }
335  free_with_check(pages, true);
336  free_with_check(presence, true);
337  }
338 
340  void add(TYPE item, unsigned int id)
341  {
342  TYPE* temp;
343 
344  if (id >= page_count * page_size)
345  {
346  int new_page_count = page_count + ((id - (page_count * page_size)) / page_size) + 2;
347 
348  pages = realloc_with_check<LightArray<TYPE>, TYPE*>(pages, new_page_count, this);
349  presence = realloc_with_check<LightArray<TYPE>, bool*>(presence, new_page_count, this);
350 
351  for (int i = page_count; i < new_page_count; i++)
352  {
353  pages[i] = malloc_with_check<LightArray<TYPE>, TYPE>(page_size, this);
354  presence[i] = calloc_with_check<LightArray<TYPE>, bool>(page_size, this);
355  }
356 
357  page_count = new_page_count;
358  }
359 
360  temp = pages[id >> page_bits] + (id & page_mask);
361  *temp = item;
362 
363  presence[id >> page_bits][id & page_mask] = true;
364 
365  if (id >= size)
366  size = id + 1;
367  return;
368  }
369 
370  unsigned int get_size() const
371  {
372  return size;
373  }
374 
376  bool present(unsigned int id) const
377  {
378  if (id >= size)
379  return false;
380  return presence[id >> page_bits][id & page_mask];
381  }
382 
384  TYPE& get(unsigned int id) const
385  {
386  return pages[id >> page_bits][id & page_mask];
387  }
388  };
389 }
390 #endif
TYPE ** pages
Definition: array.h:47
General namespace for the Hermes library.
void set_append_only(bool append_only)
Definition: array.h:121
int last(int idx=INT_MAX)
Definition: array.h:222
bool exists(int idx)
Checks whether an element exists at position idx.
Definition: array.h:253
void copy(const Array &array)
Makes this array to hold a copy of another one.
Definition: array.h:84
int first(int idx=0)
Definition: array.h:188
int prev(int idx=INT_MAX)
Definition: array.h:240
int add(TYPE item)
Wrapper function for std::vector::add() for compatibility purposes.
Definition: array.h:127
TYPE * add()
Definition: array.h:138
void add(TYPE item, unsigned int id)
Adds a new_ item to the array.
Definition: array.h:340
A light version of the array. For ordinal types or pointers, does not provide memory handling...
Definition: array.h:288
TYPE * skip_slot()
Definition: array.h:261
File containing common definitions, and basic global enums etc. for HermesCommon. ...
bool present(unsigned int id) const
Checks the id position for presence.
Definition: array.h:376
#define HERMES_PAGE_BITS
A generic, inflatable array.
Definition: array.h:38
void free()
Removes all elements from the array.
Definition: array.h:109
int next(int idx=0)
Definition: array.h:205