CFx SDK Documentation  2023 SP0
OdLinkedArray.h
Go to the documentation of this file.
1 // Copyright (C) 2002-2017, Open Design Alliance (the "Alliance").
3 // All rights reserved.
4 //
5 // This software and its documentation and related materials are owned by
6 // the Alliance. The software may only be incorporated into application
7 // programs owned by members of the Alliance, subject to a signed
8 // Membership Agreement and Supplemental Software License Agreement with the
9 // Alliance. The structure and organization of this software are the valuable
10 // trade secrets of the Alliance and its suppliers. The software is also
11 // protected by copyright law and international treaty provisions. Application
12 // programs incorporating this software must include the following statement
13 // with their copyright notices:
14 //
15 // This application incorporates Teigha(R) software pursuant to a license
16 // agreement with Open Design Alliance.
17 // Teigha(R) Copyright (C) 2002-2017 by Open Design Alliance.
18 // All rights reserved.
19 //
20 // By use of this software, its documentation or related materials, you
21 // acknowledge and accept the above terms.
23 
24 
25 #ifndef ODLINKEDARRAY_H_INCLUDED
26 #define ODLINKEDARRAY_H_INCLUDED
27 
28 #include "OdArray.h" // to use allocators
29 
30 template <class T, class A = OdObjectsAllocator<T> >
32 {
33 public:
34  typedef typename A::size_type size_type;
35 
36  class PAGE
37  {
38  public:
42 
43  // Page allocation/deallocation
44  //
45  static PAGE* allocate(size_type pageSize)
46  {
47  PAGE* page = (PAGE*)::odrxAlloc(sizeof(PAGE) + pageSize * sizeof(T));
48  if (!page)
49  throw OdError(eOutOfMemory);
50  page->_prev = 0;
51  page->_next = 0;
52  page->_size = 0;
53  return page;
54  }
55  void release()
56  {
57  A::destroy(items(), _size);
58  ::odrxFree(this);
59  }
60 
61  // Access to items on page
62  //
64  {
65  assertValid(index);
66  return *(items(index));
67  }
68  const T& at(size_type index) const
69  {
70  assertValid(index);
71  return *(items(index));
72  }
73 
74  // Add items to page
75  //
77  {
78  A::construct(items(_size), value);
79  return ++_size;
80  }
82  {
83  size_type moved = _size - i;
84  ODA_ASSERT(moved<=_size);
85  A::move(items(i+1), items(i), moved);
86  A::construct(items(i), value);
87  return ++_size;
88  }
89  void resize(size_type newSize, const T& value)
90  {
91  ODA_ASSERT(newSize>_size);
92  A::constructn(items(_size), newSize-_size, value);
93  _size = newSize;
94  }
95  void resize(size_type newSize)
96  {
97  if(newSize>_size) {
98  A::constructn(items(_size), newSize-_size);
99  _size = newSize;
100  }
101  else {
102  A::destroy(items(0), _size - newSize);
103  _size = newSize;
104  }
105  }
106  void moveFrom(PAGE* src, size_type start)
107  {
108  ODA_ASSERT(src && (this!=src));
109  ODA_ASSERT(start && start<src->_size);
110 
111  A::copy(items(_size), src->items(), start);
112  _size += start;
113 
114  src->_size -= start;
115  A::move(src->items(), src->items(start), src->_size);
116  }
118  {
119  A::destroy(items(i), 1);
120  --_size;
121  if ( i < _size )
122  A::move(items(i), items(i+1), _size - i);
123  }
124  void removeLast()
125  {
126  A::destroy(items(_size--), 1);
127  }
128 
129  private:
130  T* items(size_type i = 0)
131  {
132  return (T*)((OdUInt8*)this + sizeof(PAGE)) + i;
133  }
134  void assertValid(size_type index) const
135  {
136  if (index >= _size)
137  {
138  ODA_FAIL();
139  throw OdError(eInvalidIndex);
140  }
141  }
142  };
143 
144 private:
145  // Add/insert new page
146  //
147  PAGE* addPage()
148  {
149  PAGE* page = PAGE::allocate(_pageSize);
150 
151  if (!_last)
152  {
153  ODA_ASSERT(!_first);
154  _first = page;
155  _last = page;
156  }
157  else
158  {
159  ODA_ASSERT(_first);
160  _last->_next = page;
161  page->_prev = _last;
162  _last = page;
163  }
164 
165  ++_pageNums;
166  return page;
167  }
168 
169  PAGE* insertPage(PAGE* prev)
170  {
171  PAGE* page = PAGE::allocate(_pageSize);
172 
173  if (!_first)
174  {
175  ODA_ASSERT(!prev && !_last);
176  _first = page;
177  _last = page;
178  }
179  else if (!prev)
180  {
181  ODA_ASSERT(_first && _last);
182  _first->_prev = page;
183  page->_next = _first;
184  _first = page;
185  }
186  else
187  {
188  ODA_ASSERT(_first && _last);
189  if (prev == _last)
190  {
191  _last = page;
192  }
193  else
194  {
195  ODA_ASSERT(prev->_next);
196  prev->_next->_prev = page;
197  page->_next = prev->_next;
198  }
199  prev->_next = page;
200  page->_prev = prev;
201  }
202 
203  ++_pageNums;
204  return page;
205  }
206 
207  PAGE* _first;
208  PAGE* _last;
209  size_type _pageNums;
210  size_type _pageSize;
211  size_type _itemNums;
212 
213 private:
214  // Prohibit usage
216  OdLinkedArray& operator = (const OdLinkedArray&);
217 
218  // Construction/destruction
219  //
220 public:
221  OdLinkedArray(OdUInt32 pageSize = 0x10)
222  : _first(0)
223  , _last(0)
224  , _pageNums(0)
225  , _pageSize(pageSize)
226  , _itemNums(0)
227  {
228  }
229 
231  {
232  clear();
233  }
234 
235  void reserve(size_type) {}; // For compatibility with other array types
236 
237  void clear()
238  {
239  PAGE *next, *curr = _first;
240  while (curr)
241  {
242  next = curr->_next;
243  curr->release();
244  curr = next;
245  }
246  _first = 0;
247  _last = 0;
248  _pageNums = 0;
249  _itemNums = 0;
250  }
251 
252  void freeExtra() {
253  if(_last) {
254  PAGE *curr = _last->_next;
255  _last->_next = 0;
256  while ( curr ) {
257  PAGE *tmp = curr;
258  ODA_ASSERT( curr->_size==0 );
259  curr->release();
260  curr = tmp;
261  }
262  }
263  }
264 
266  {
267  if (_itemNums == 0)
268  {
269  ODA_FAIL();
270  return T();
271  }
272  T data = _last->at(_last->_size - 1);
273  --_itemNums;
274  _last->removeLast();
275  if (!_last->_size)
276  {
277  --_pageNums;
278  PAGE* p = _last->_prev;
279  _last->release();
280  _last = p;
281  if (!_last)
282  _first = 0;
283  else
284  _last->_next = 0;
285  }
286  return data;
287  }
288 
289  // Iterators
290  //
292  {
293  public:
295  : _page(0)
296  , _ind(0) {}
297 
299  : _page(page)
300  , _ind(ind) {}
301 
302  const T& operator*() const
303  {
304  return _page->at(_ind);
305  }
306 
307  operator const T*() const {
308  return &_page->at(_ind);
309  }
310 
311  const T* operator->() const
312  {
313  return &**this;
314  }
315 
317  {
318  next();
319  return *this;
320  }
321 
323  {
324  const_iterator tmp = *this;
325  ++*this;
326  return tmp;
327  }
328 
330  {
331  prev();
332  return *this;
333  }
334 
336  {
337  const_iterator tmp = *this;
338  --*this;
339  return tmp;
340  }
341 
343  seek(n);
344  return *this;
345  }
346 
348  seek(-n);
349  return *this;
350  }
351 
352  bool operator==(const const_iterator& it) const
353  {
354  return (_page == it._page && _ind == it._ind);
355  }
356 
357  bool operator!=(const const_iterator& it) const
358  {
359  return (!(*this == it));
360  }
361 
362  bool done() const
363  {
364  return (!_page || (_ind >= _page->_size/* && !_page->_next*/));
365  }
366  protected:
367  void seek(int n) {
368  if(n > 0)
369  next(n);
370  else
371  prev(-n);
372  }
373 
374  void next(int n=1)
375  {
376  if (!_page)
377  {
378  ODA_FAIL();
379  return;
380  }
381 
382  _ind += n;
383  while (_page && _page->_next && _ind>=_page->_size)
384  {
385  _ind -= _page->_size;
386  _page = _page->_next;
387  }
388  }
389 
390  void prev(int n=1)
391  {
392  if (!_page)
393  {
394  ODA_FAIL();
395  return;
396  }
397 
398  while (_page && _page->_prev && _ind < (unsigned)n) {
399  _page = _page->_prev;
400  _ind += _page->_size;
401  }
402  _ind -= n;
403  }
404 
406  unsigned _ind;
407 
408  friend class OdLinkedArray<T,A>;
409  };
410 
412  {
413  public:
414  iterator() {}
415 
417  : const_iterator(page, ind) {}
418 
419  T& operator*() const
420  {
421  return this->_page->at(this->_ind);
422  }
423 
424  operator T*() {
425  return &(this->_page->at(this->_ind));
426  }
427 
428  T* operator->() {
429  return &**this;
430  }
431 
433  {
434  this->next();
435  return *this;
436  }
437 
439  {
440  iterator tmp = *this;
441  ++*this;
442  return tmp;
443  }
444 
446  this->seek(n);
447  return *this;
448  }
449 
451  this->seek(-n);
452  return *this;
453  }
454 
456  {
457  this->prev();
458  return *this;
459  }
460 
462  {
463  iterator tmp = *this;
464  --*this;
465  return tmp;
466  }
467  };
468 
469  // Return iterator for beginning/end of sequence
470  //
472  {
473  return iterator(_first, 0);
474  }
476  {
477  return const_iterator(_first, 0);
478  }
480  {
481  return iterator(_last, (_last ? _last->_size : 0));
482  }
484  {
485  return const_iterator(_last, (_last ? _last->_size : 0));
486  }
487 
488  // Find value in sequence
489  //
490  iterator find(const T& val)
491  {
492  iterator it = begin(),
493  endIt = end();
494  while (it != endIt && *it != val)
495  {
496  ++it;
497  }
498  return it;
499  }
500  const_iterator find(const T& val) const
501  {
502  const_iterator it = begin(),
503  endIt = end();
504  while (it != endIt && *it != val)
505  {
506  ++it;
507  }
508  return it;
509  }
510 
511  bool contains(const T& val) const
512  {
513  const_iterator it = find(val);
514  return !it.done();
515  }
516 
517  // Add new items to array
518  // resize
519  // insert
520  // append
521  //
522  void resize(size_type newSize)
523  {
524  int d = newSize - size();
525  if (d > 0)
526  {
527  if (_last) {
528  // fill last existed page
529  int d0;
530  if(_last->_size < _pageSize) {
531  d0 = odmin(d, (int)(_pageSize - _last->_size));
532  _last->resize(_last->_size + d0);
533  d -= d0;
534  }
535  // reuse clear pages
536  while (d && _last->_next) {
537  _last = _last->_next;
538  ODA_ASSERT(_last->_size==0);
539  d0 = odmin(d, (int)_pageSize);
540  _last->resize(d0);
541  d -= d0;
542  }
543  }
544  // add new full pages
545  while (d>=(int)_pageSize)
546  {
547  addPage()->resize(_pageSize);
548  d -= _pageSize;
549  }
550  // add new partial page
551  if (d>0)
552  {
553  addPage()->resize(d);
554  }
555 
556  _itemNums = newSize;
557  }
558  else if (d < 0)
559  {
560  while ((size_type)-d > _last->_size) {
561  d += _last->_size;
562  PAGE* pToRemove = _last;
563  _last = _last->_prev;
564  if (_last)
565  _last->_next = NULL;
566  else
567  _first = NULL;
568  pToRemove->release();
569  --_pageNums;
570  }
571  if (-d > 0) {
572  d += _last->_size;
573  _last->resize(d);
574  }
575  _itemNums = newSize;
576  }
577  }
578 
579  iterator insert(iterator before, const T& val = T())
580  {
581  if (before.done())
582  {
583  append(val);
584  before = end();
585  --before;
586  }
587  else
588  {
589  size_type curInd = before._ind;
590  PAGE* curPage = before._page;
591  ODA_ASSERT(curPage);
592 
593  if (curPage->_size < _pageSize)
594  {
595  curPage->insertAt(curInd, val); // there is free space in current page
596  }
597  else
598  {
599  PAGE* prevPage = curPage->_prev;
600  if (!prevPage || (prevPage->_size + curInd) >= _pageSize)
601  {
602  prevPage = insertPage(prevPage); // there is not enough free space in previous page
603  }
604  if (curInd)
605  {
606  prevPage->moveFrom(curPage, curInd); // move part of data to previous page
607  }
608  ODA_ASSERT(prevPage);
609  prevPage->append(val);
610  before = iterator(prevPage, prevPage->_size-1);
611  }
612 
613  ++_itemNums;
614  }
615  return before;
616  }
617 
619  {
620  size_type curInd = at._ind;
621  PAGE* curPage = at._page;
622  if (curPage == _last && curInd == (_last->_size - 1))
623  return removeLast();
624  T data = curPage->at(curInd);
625  if (curPage->_size == 1) // removing last page item
626  {
627  if (curPage->_prev)
628  curPage->_prev->_next = curPage->_next;
629  else
630  this->_first = curPage->_next;
631  if (curPage->_next)
632  curPage->_next->_prev = curPage->_prev;
633  curPage->release();
634  --this->_pageNums;
635  }
636  else
637  {
638  curPage->remove(curInd);
639  }
640  --this->_itemNums;
641  return data;
642  }
643 
644  void append(const T& value)
645  {
646  if (_last && _last->_size < _pageSize)
647  {
648  _last->append(value);
649  }
650  else
651  {
652  addPage()->append(value);
653  }
654 
655  ++_itemNums;
656  }
657 
659  resize(size()+1);
660  return --end();
661  }
662 
663  T& first() {
664  return *begin();
665  }
666 
667  const T& first() const {
668  return *begin();
669  }
670 
671  T& last() {
672  return *(--end());
673  }
674 
675  const T& last() const {
676  return *(--end());
677  }
678 
679  bool empty() const {
680  return size()==0;
681  }
682 
683  size_type size() const
684  {
685 #ifdef _DEBUG
686  size_type itemNums = 0,
687  pageNums = 0;
688  PAGE* page = _first;
689  while (page)
690  {
691  ++pageNums;
692  itemNums += page->_size;
693  page = page->_next;
694  }
695  ODA_ASSERT(_itemNums == itemNums);
696  ODA_ASSERT(_pageNums == pageNums);
697 #endif
698  return _itemNums;
699  }
700 };
701 
702 #endif // ODLINKEDARRAY_H_INCLUDED
#define ODA_ASSERT(exp)
Definition: DebugStuff.h:49
#define ODA_FAIL()
Definition: DebugStuff.h:65
#define NULL
Definition: GsProperties.h:177
ALLOCDLL_EXPORT void * odrxAlloc(size_t nBytes)
ALLOCDLL_EXPORT void odrxFree(void *pMemBlock)
#define OD_TYPENAME2
Definition: OdPlatform.h:585
#define odmin(X, Y)
Definition: OdPlatform.h:34
#define OD_LINKEDARRAY_SCOPE
Definition: OdPlatform.h:601
unsigned int OdUInt32
unsigned char OdUInt8
void resize(size_type newSize)
Definition: OdLinkedArray.h:95
void resize(size_type newSize, const T &value)
Definition: OdLinkedArray.h:89
size_type insertAt(size_type i, const T &value)
Definition: OdLinkedArray.h:81
void moveFrom(PAGE *src, size_type start)
void remove(size_type i)
static PAGE * allocate(size_type pageSize)
Definition: OdLinkedArray.h:45
size_type append(const T &value)
Definition: OdLinkedArray.h:76
const T & at(size_type index) const
Definition: OdLinkedArray.h:68
T & at(size_type index)
Definition: OdLinkedArray.h:63
bool operator==(const const_iterator &it) const
const_iterator operator-=(int n)
bool operator!=(const const_iterator &it) const
const T * operator->() const
OD_TYPENAME2 OD_LINKEDARRAY_SCOPE PAGE * _page
const_iterator(OD_TYPENAME2 OD_LINKEDARRAY_SCOPE PAGE *page, unsigned ind=0)
const_iterator operator++(int)
const_iterator & operator++()
const_iterator operator--(int)
const_iterator operator+=(int n)
const_iterator & operator--()
iterator operator++(int)
iterator operator--(int)
iterator operator-=(int n)
iterator(OD_TYPENAME2 OD_LINKEDARRAY_SCOPE PAGE *page, unsigned ind=0)
iterator operator+=(int n)
void reserve(size_type)
iterator find(const T &val)
void append(const T &value)
const_iterator find(const T &val) const
iterator insert(iterator before, const T &val=T())
iterator begin()
const T & first() const
bool contains(const T &val) const
T remove(iterator at)
A::size_type size_type
Definition: OdLinkedArray.h:34
void resize(size_type newSize)
iterator end()
const_iterator begin() const
const_iterator end() const
bool empty() const
OdLinkedArray(OdUInt32 pageSize=0x10)
const T & last() const
iterator append()
size_type size() const
GLint GLenum GLsizei GLsizei GLint GLsizei const void * data
Definition: gles2_ext.h:110
GLuint index
Definition: gles2_ext.h:265
GLsizei const GLfloat * value
Definition: gles2_ext.h:302