CFx SDK Documentation 2026 SP0
Loading...
Searching...
No Matches
OdLinkedArray.h
Go to the documentation of this file.
1// FELIX_CHANGE_BEGIN file was take from ODA gitlab repository https://gitlab.opendesign.com/
3// Copyright (C) 2002-2024, Open Design Alliance (the "Alliance").
4// All rights reserved.
5//
6// This software and its documentation and related materials are owned by
7// the Alliance. The software may only be incorporated into application
8// programs owned by members of the Alliance, subject to a signed
9// Membership Agreement and Supplemental Software License Agreement with the
10// Alliance. The structure and organization of this software are the valuable
11// trade secrets of the Alliance and its suppliers. The software is also
12// protected by copyright law and international treaty provisions. Application
13// programs incorporating this software must include the following statement
14// with their copyright notices:
15//
16// This application incorporates Open Design Alliance software pursuant to a license
17// agreement with Open Design Alliance.
18// Open Design Alliance Copyright (C) 2002-2024 by Open Design Alliance.
19// All rights reserved.
20//
21// By use of this software, its documentation or related materials, you
22// acknowledge and accept the above terms.
24#ifndef ODLINKEDARRAY_H_INCLUDED
25#define ODLINKEDARRAY_H_INCLUDED
26#include "OdArray.h" // to use allocators
38template <class T, class A = OdObjectsAllocator<T> >
39class OdLinkedArray
40{
41public:
42 typedef typename A::size_type size_type;
43private:
44 class PAGE
45 {
46 public:
47 PAGE* _next;
48 PAGE* _prev;
49 size_type _size;
50 // Page allocation/deallocation
51 //
52 static PAGE* allocate(size_type pageSize)
53 {
54 PAGE* page = (PAGE*)::odrxAlloc(sizeof(PAGE) + pageSize * sizeof(T));
55 if (!page)
56 throw OdError(eOutOfMemory);
57 page->_prev = 0;
58 page->_next = 0;
59 page->_size = 0;
60 return page;
61 }
62 void release()
63 {
64 A::destroyRange(items(), _size);
65 ::odrxFree(this);
66 }
67 // Access to items on page
68 //
69 T& at(size_type index)
70 {
71 assertValid(index);
72 return *(items(index));
73 }
74 const T& at(size_type index) const
75 {
76 assertValid(index);
77 return *(items(index));
78 }
79 // Add items to page
80 //
81 size_type append(const T& value)
82 {
83 A::copyConstruct(items(_size), value);
84 return ++_size;
85 }
86 size_type insertAt(size_type i, const T& value)
87 {
88 size_type moved = _size - i;
89 ODA_ASSERT(moved<=_size);
90 A::copyAssignRange(items(i+1), items(i), moved);
91 A::copyConstruct(items(i), value);
92 return ++_size;
93 }
94 void resize(size_type newSize, const T& value)
95 {
96 ODA_ASSERT(newSize>_size);
97 A::copyConstructFill(items(_size), newSize-_size, value);
98 _size = newSize;
99 }
100 void resize(size_type newSize)
101 {
102 if(newSize>_size) {
103 A::defaultConstructFill(items(_size), newSize-_size);
104 _size = newSize;
105 }
106 else {
107 A::destroyRange(items(0), _size - newSize);
108 _size = newSize;
109 }
110 }
111 void moveFrom(PAGE* src, size_type start)
112 {
113 ODA_ASSERT(src && (this!=src));
114 ODA_ASSERT(start && start<src->_size);
115
116 A::copyAssignRangeDisjoint(items(_size), src->items(), start);
117 _size += start;
118 src->_size -= start;
119 A::copyAssignRange(src->items(), src->items(start), src->_size);
120 }
121 void remove(size_type i)
122 {
123 A::destroyRange(items(i), 1);
124 --_size;
125 if ( i < _size )
126 A::copyAssignRange(items(i), items(i+1), _size - i);
127 }
128 void removeLast()
129 {
130 A::destroyRange(items(_size--), 1);
131 }
132 private:
133 T* items(size_type i = 0)
134 {
135 return (T*)((OdUInt8*)this + sizeof(PAGE)) + i;
136 }
137 void assertValid(size_type index) const
138 {
139 if (index >= _size)
140 {
141 ODA_FAIL();
142 throw OdError(eInvalidIndex);
143 }
144 }
145 };
146private:
147 // Add/insert new page
148 //
149 PAGE* addPage()
150 {
151 PAGE* page = PAGE::allocate(_pageSize);
152 if (!_last)
153 {
154 ODA_ASSERT(!_first);
155 _first = page;
156 _last = page;
157 }
158 else
159 {
160 ODA_ASSERT(_first);
161 _last->_next = page;
162 page->_prev = _last;
163 _last = page;
164 }
165 ++_pageNums;
166 return page;
167 }
168 PAGE* insertPage(PAGE* prev)
169 {
170 PAGE* page = PAGE::allocate(_pageSize);
171 if (!_first)
172 {
173 ODA_ASSERT(!prev && !_last);
174 _first = page;
175 _last = page;
176 }
177 else if (!prev)
178 {
179 ODA_ASSERT(_first && _last);
180 _first->_prev = page;
181 page->_next = _first;
182 _first = page;
183 }
184 else
185 {
186 ODA_ASSERT(_first && _last);
187 if (prev == _last)
188 {
189 _last = page;
190 }
191 else
192 {
193 ODA_ASSERT(prev->_next);
194 prev->_next->_prev = page;
195 page->_next = prev->_next;
196 }
197 prev->_next = page;
198 page->_prev = prev;
199 }
200 ++_pageNums;
201 return page;
202 }
203 PAGE* _first;
204 PAGE* _last;
205 size_type _pageNums;
206 size_type _pageSize;
207 size_type _itemNums;
208private:
209 // Prohibit usage
210 OdLinkedArray(const OdLinkedArray&);
211 OdLinkedArray& operator = (const OdLinkedArray&);
212
213 // Construction/destruction
214 //
215public:
220 OdLinkedArray(OdUInt32 pageSize = 0x10)
221 : _first(0)
222 , _last(0)
223 , _pageNums(0)
224 , _pageSize(pageSize)
225 , _itemNums(0)
226 {
227 if (pageSize == 0) {
228 // throwing an exception from the failed constructor is the standard way of saying to user that
229 // this object is unusable, for more info see https://isocpp.org/wiki/faq/exceptions#ctors-can-throw
230 throw OdError(eInvalidInput);
231 }
232 }
233 //DOM-IGNORE-BEGIN
235 {
236 clear();
237 }
238
243 //DOM-IGNORE-END
247 void clear()
248 {
249 PAGE *next, *curr = _first;
250 while (curr)
251 {
252 next = curr->_next;
253 curr->release();
254 curr = next;
255 }
256 _first = 0;
257 _last = 0;
258 _pageNums = 0;
259 _itemNums = 0;
260 }
261
265 {
266 if (_itemNums == 0)
267 {
268 ODA_FAIL();
269 return T();
270 }
271 T data = _last->at(_last->_size - 1);
272 --_itemNums;
273 _last->removeLast();
274 if (!_last->_size)
275 {
276 --_pageNums;
277 PAGE* p = _last->_prev;
278 _last->release();
279 _last = p;
280 if (!_last)
281 _first = 0;
282 else
283 _last->_next = 0;
284 }
285 return data;
286 }
287 //DOM-IGNORE-BEGIN
289#if defined(_MSC_VER) && (_MSC_VER < 1910)
290 : public std::iterator<std::bidirectional_iterator_tag, T, void>
291#endif
292 {
293 public:
295 : _page(0)
296 , _ind(0) {}
297 const T& operator*() const
298 {
299 return _page->at(_ind);
300 }
301 operator const T*() const {
302 return &_page->at(_ind);
303 }
304 const T* operator->() const
305 {
306 return &**this;
307 }
309 {
310 next();
311 return *this;
312 }
314 {
315 const_iterator tmp = *this;
316 ++*this;
317 return tmp;
318 }
320 {
321 prev();
322 return *this;
323 }
325 {
326 const_iterator tmp = *this;
327 --*this;
328 return tmp;
329 }
330 const_iterator operator += (int n) {
331 seek(n);
332 return *this;
333 }
334 const_iterator operator -= (int n) {
335 seek(-n);
336 return *this;
337 }
338 bool operator==(const const_iterator& it) const
339 {
340 return (_page == it._page && _ind == it._ind);
341 }
342 bool operator!=(const const_iterator& it) const
343 {
344 return (!(*this == it));
345 }
346 bool done() const
347 {
348 return (!_page || (_ind >= _page->_size/* && !_page->_next*/));
349 }
350 protected:
352 : _page(page)
353 , _ind(ind) {}
354 void seek(int n) {
355 if(n > 0)
356 next(n);
357 else
358 prev(-n);
359 }
360 void next(int n=1)
361 {
362 if (!_page)
363 {
364 ODA_FAIL();
365 return;
366 }
367 _ind += n;
368 while (_page && _page->_next && _ind>=_page->_size)
369 {
370 _ind -= _page->_size;
371 _page = _page->_next;
372 }
373 }
374 void prev(int n=1)
375 {
376 if (!_page)
377 {
378 ODA_FAIL();
379 return;
380 }
381 while (_page && _page->_prev && _ind < (unsigned)n) {
382 _page = _page->_prev;
383 _ind += _page->_size;
384 }
385 _ind -= n;
386 }
388 unsigned _ind;
389 friend class OdLinkedArray<T,A>;
390 };
392 {
393 public:
395 T& operator*() const
396 {
397 return this->_page->at(this->_ind);
398 }
399 operator T*() {
400 return &(this->_page->at(this->_ind));
401 }
403 return &**this;
404 }
406 {
407 this->next();
408 return *this;
409 }
411 {
412 iterator tmp = *this;
413 ++*this;
414 return tmp;
415 }
417 this->seek(n);
418 return *this;
419 }
421 this->seek(-n);
422 return *this;
423 }
425 {
426 this->prev();
427 return *this;
428 }
430 {
431 iterator tmp = *this;
432 --*this;
433 return tmp;
434 }
435 private:
436 iterator(OD_TYPENAME2 OD_LINKEDARRAY_SCOPE PAGE* page, unsigned ind = 0)
437 : const_iterator(page, ind) {}
438 friend class OdLinkedArray<T, A>;
439 };
440 //DOM-IGNORE-END
445 {
446 return iterator(_first, 0);
447 }
448
452 {
453 return const_iterator(_first, 0);
454 }
455
459 {
460 return iterator(_last, (_last ? _last->_size : 0));
461 }
462
466 {
467 return const_iterator(_last, (_last ? _last->_size : 0));
468 }
469
475 iterator find(const T& val)
476 {
477 iterator it = begin(),
478 endIt = end();
479 while (it != endIt && *it != val)
480 {
481 ++it;
482 }
483 return it;
484 }
485
491 const_iterator find(const T& val) const
492 {
493 const_iterator it = begin(),
494 endIt = end();
495 while (it != endIt && *it != val)
496 {
497 ++it;
498 }
499 return it;
500 }
501
505 bool contains(const T& val) const
506 {
507 const_iterator it = find(val);
508 return !it.done();
509 }
510
514 void resize(size_type newSize)
515 {
516 int d = newSize - size();
517 if (d > 0)
518 {
519 if (_last) {
520 // fill last existed page
521 int d0;
522 if(_last->_size < _pageSize) {
523 d0 = odmin(d, (int)(_pageSize - _last->_size));
524 _last->resize(_last->_size + d0);
525 d -= d0;
526 }
527 // reuse clear pages
528 while (d && _last->_next) {
529 _last = _last->_next;
530 ODA_ASSERT(_last->_size==0);
531 d0 = odmin(d, (int)_pageSize);
532 _last->resize(d0);
533 d -= d0;
534 }
535 }
536 // add new full pages
537 while (d>=(int)_pageSize)
538 {
539 addPage()->resize(_pageSize);
540 d -= _pageSize;
541 }
542 // add new partial page
543 if (d>0)
544 {
545 addPage()->resize(d);
546 }
547 _itemNums = newSize;
548 }
549 else if (d < 0)
550 {
551 while ((size_type)-d >= _last->_size) {
552 d += _last->_size;
553 PAGE* pToRemove = _last;
554 _last = _last->_prev;
555 pToRemove->release();
556 --_pageNums;
557 if (_last)
558 _last->_next = NULL;
559 else
560 {
561 _first = NULL;
562 break;
563 }
564 }
565 if (-d > 0) {
566 d += _last->_size;
567 _last->resize(d);
568 }
569 _itemNums = newSize;
570 }
571 }
572
577 iterator insert(iterator before, const T& val = T())
578 {
579 if (before.done())
580 {
581 append(val);
582 before = end();
583 --before;
584 }
585 else
586 {
587 size_type curInd = before._ind;
588 PAGE* curPage = before._page;
589 ODA_ASSERT(curPage);
590 if (curPage->_size < _pageSize)
591 {
592 curPage->insertAt(curInd, val); // there is free space in current page
593 }
594 else
595 {
596 PAGE* prevPage = curPage->_prev;
597 if (!prevPage || (prevPage->_size + curInd) >= _pageSize)
598 {
599 prevPage = insertPage(prevPage); // there is not enough free space in previous page
600 }
601 if (curInd)
602 {
603 prevPage->moveFrom(curPage, curInd); // move part of data to previous page
604 }
605 ODA_ASSERT(prevPage);
606 prevPage->append(val);
607 before = iterator(prevPage, prevPage->_size-1);
608 }
609 ++_itemNums;
610 }
611 return before;
612 }
613
618 {
619 size_type curInd = at._ind;
620 PAGE* curPage = at._page;
621 if (curPage == _last && curInd == (_last->_size - 1))
622 return removeLast();
623 T data = curPage->at(curInd);
624 if (curPage->_size == 1) // removing last page item
625 {
626 if (curPage->_prev)
627 curPage->_prev->_next = curPage->_next;
628 else
629 this->_first = curPage->_next;
630 if (curPage->_next)
631 curPage->_next->_prev = curPage->_prev;
632 curPage->release();
633 --this->_pageNums;
634 }
635 else
636 {
637 curPage->remove(curInd);
638 }
639 --this->_itemNums;
640 return data;
641 }
642
645 void append(const T& value)
646 {
647 if (_last && _last->_size < _pageSize)
648 {
649 _last->append(value);
650 }
651 else
652 {
653 addPage()->append(value);
654 }
655 ++_itemNums;
656 }
657
661 resize(size()+1);
662 return --end();
663 }
664
667 T& first() {
668 return *begin();
669 }
670
673 const T& first() const {
674 return *begin();
675 }
676
679 T& last() {
680 return *(--end());
681 }
682
685 const T& last() const {
686 return *(--end());
687 }
688
691 bool empty() const {
692 return size()==0;
693 }
694
698 {
699#ifdef _DEBUG
700 size_type itemNums = 0,
701 pageNums = 0;
702 PAGE* page = _first;
703 while (page)
704 {
705 ++pageNums;
706 itemNums += page->_size;
707 page = page->_next;
708 }
709 ODA_ASSERT(_itemNums == itemNums);
710 ODA_ASSERT(_pageNums == pageNums);
711#endif
712 return _itemNums;
713 }
714
717 void freeExtra() {
718 if (_last) {
719 PAGE *curr = _last->_next;
720 _last->_next = 0;
721 while (curr) {
722 PAGE *tmp = curr;
723 ODA_ASSERT(curr->_size == 0);
724 curr->release();
725 curr = tmp;
726 }
727 }
728 }
729};
730#endif // ODLINKEDARRAY_H_INCLUDED
731// FELIX_CHANGE_END file was take from ODA gitlab repository https://gitlab.opendesign.com/
#define ODA_ASSERT(exp)
Definition DebugStuff.h:57
#define ODA_FAIL()
Definition DebugStuff.h:88
ALLOCDLL_EXPORT void * odrxAlloc(size_t nBytes)
ALLOCDLL_EXPORT void odrxFree(void *pMemBlock)
#define OD_TYPENAME2
ODRX_CONSTEXPR const T & odmin(const T &a, const T &b)
Definition OdPlatform.h:64
#define OD_LINKEDARRAY_SCOPE
unsigned int OdUInt32
unsigned char OdUInt8
bool operator==(const const_iterator &it) const
const_iterator & operator++()
bool operator!=(const const_iterator &it) 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)
iterator operator-=(int n)
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
const T & last() const
bool contains(const T &val) const
T remove(iterator at)
A::size_type size_type
void resize(size_type newSize)
iterator end()
const_iterator begin() const
const_iterator end() const
bool empty() const
OdLinkedArray(OdUInt32 pageSize=0x10)
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