CFx SDK Documentation  2023 SP0
OdArrayMemAlloc.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 #ifndef ODARRAYMEMALLOC_H_INCLUDED
24 #define ODARRAYMEMALLOC_H_INCLUDED
25 
26 #include <new>
27 
28 #include "TD_PackPush.h"
29 
30 #include "OdArray.h"
31 #include "OdAlloc.h"
32 
36 {
37 public:
38  static void* Alloc(size_t nBytes) { return ::odrxAlloc(nBytes); }
39  static void Free(void* pMemBlock) { ::odrxFree(pMemBlock); }
40  static void* Realloc(void* pMemBlock, size_t newSize, size_t oldSize)
41  {
42  return ::odrxRealloc(pMemBlock, newSize, oldSize);
43  }
44 };
45 template <class T, class A = OdObjectsAllocator<T>, class Mm = OdrxMemoryManager> class OdArrayMemAlloc;
46 
64 template <class T, class A, class Mm> class OdArrayMemAlloc
65 {
66 public:
67  typedef typename A::size_type size_type;
68  typedef T* iterator;
69  typedef const T* const_iterator;
70 private:
71  struct Buffer : OdArrayBuffer
72  {
73  T* data() const { return (T*)(this+1); }
74 
75  static Buffer* allocate(size_type nLength2Allocate, int nGrowBy)
76  {
77  size_type nBytes2Allocate = sizeof(Buffer) + nLength2Allocate * sizeof(T);
78  ODA_ASSERT(nBytes2Allocate > nLength2Allocate); // size_type overflow
79  if(nBytes2Allocate > nLength2Allocate)
80  {
81  Buffer* pBuffer = (Buffer*)Mm::Alloc(nBytes2Allocate);
82  if (pBuffer)
83  {
84  pBuffer->m_nRefCounter = 1;
85  pBuffer->m_nGrowBy = nGrowBy;
86  pBuffer->m_nAllocated = nLength2Allocate;
87  pBuffer->m_nLength = 0;
88  return pBuffer;
89  }
90  }
91  throw OdError(eOutOfMemory);
92  }
93  static Buffer* _default()
94  {
95  return (Buffer*)&g_empty_array_buffer;
96  }
97  void release()
98  {
99  ODA_ASSERT(m_nRefCounter);
100  if((--m_nRefCounter)==0 && this != _default())
101  {
102  A::destroy(data(), m_nLength);
103  Mm::Free(this);
104  }
105  }
106  void addref() const { ++m_nRefCounter; }
107  };
108  class reallocator
109  {
110  bool _may_use_realloc;
111  Buffer* m_pBuffer;
112  public:
113  inline reallocator( bool may_use_realloc = false ) : _may_use_realloc(may_use_realloc) , m_pBuffer(NULL)
114  {
115  if ( !_may_use_realloc )
116  {
117  m_pBuffer = Buffer::_default();
118  m_pBuffer->addref();
119  }
120  }
121  inline void reallocate(OdArrayMemAlloc* pArray, size_type nNewLen )
122  {
123  if(!pArray->referenced())
124  {
125  if(nNewLen > pArray->physicalLength())
126  {
127  if ( !_may_use_realloc )
128  {
129  m_pBuffer->release();
130  m_pBuffer = pArray->buffer();
131  m_pBuffer->addref(); // save buffer to ensure copy from itself would work (e.g insertAt)
132  }
133  pArray->copy_buffer(nNewLen, _may_use_realloc);
134  }
135  }
136  else
137  {
138  pArray->copy_buffer(nNewLen);
139  }
140  }
141  inline ~reallocator()
142  {
143  if ( !_may_use_realloc ) m_pBuffer->release();
144  }
145  };
146  friend class reallocator;
147  const_iterator begin_const() const { return begin(); }
148  iterator begin_non_const() { return begin(); }
149  const_iterator end_const() { return end(); }
150  iterator end_non_const() { return end(); }
151  void copy_before_write(size_type len, bool may_use_realloc = false )
152  {
153  if( referenced() )
154  copy_buffer(len);
155  else if ( len > physicalLength() )
156  copy_buffer( len, may_use_realloc );
157  }
158  void copy_if_referenced() { if(referenced()) { copy_buffer(physicalLength()); } }
159  void copy_buffer( size_type len, bool may_use_realloc = false, bool force_size = false )
160  {
161  Buffer* pOldBuffer = buffer();
162  int nGrowBy = pOldBuffer->m_nGrowBy;
163  size_type len2 = len;
164  if ( !force_size )
165  {
166  if(nGrowBy > 0)
167  {
168  len2 += nGrowBy;
169  len2 = ((len2 - 1) / nGrowBy) * nGrowBy;
170  }
171  else
172  {
173  len2 = pOldBuffer->m_nLength;
174  len2 = len2 + -nGrowBy * len2 / 100;
175  if(len2 < len)
176  {
177  len2 = len;
178  }
179  }
180  }
181  if ( may_use_realloc && A::useRealloc() && !empty() )
182  {
183  Buffer* pNewBuffer = reinterpret_cast<Buffer*>( Mm::Realloc(
184  pOldBuffer, len2 * sizeof(T) + sizeof(Buffer), pOldBuffer->m_nAllocated * sizeof(T) + sizeof(Buffer) ) );
185  pNewBuffer->m_nAllocated = len2;
186  pNewBuffer->m_nLength = odmin(pNewBuffer->m_nLength, len);
187  m_pData = pNewBuffer->data();
188  }
189  else
190  {
191  Buffer* pNewBuffer = Buffer::allocate(len2, nGrowBy);
192  len = odmin(pOldBuffer->m_nLength, len);
193  A::constructn(pNewBuffer->data(), pOldBuffer->data(), len);
194  pNewBuffer->m_nLength = len;
195  m_pData = pNewBuffer->data();
196  pOldBuffer->release();
197  }
198  }
199  inline void assertValid(size_type index) const { if(!isValid(index)) { ODA_FAIL(); throw OdError_InvalidIndex(); } }
200  static inline void rise_error(OdResult e) { ODA_FAIL(); throw OdError(e); }
201 public:
202  // STL-like interface
203 
207  iterator begin() { if(!empty()) { copy_if_referenced(); return data(); } return 0; }
211  const_iterator begin() const { if(!empty()) { return data(); } return 0; }
212 
216  iterator end() { if(!empty()) { copy_if_referenced(); return data() + length(); } return 0; }
220  const_iterator end() const { if(!empty()) { return data()+length(); } return 0; }
221 
232  void insert(
233  iterator before,
235  const_iterator afterLast)
236  {
237  size_type len = length();
238  size_type index = (size_type)(before - begin_const());
240  {
241  if(afterLast > first)
242  {
243  size_type num2copy = (size_type)(afterLast - first);
244  reallocator r( first < begin() || first >= end() );
245  r.reallocate(this, len + num2copy);
246  A::constructn(m_pData + len, first, num2copy);
247  buffer()->m_nLength = len + num2copy;
248  T* pDestination = m_pData + index;
249  if(index != len)
250  {
251  A::move(pDestination + num2copy, pDestination, len - index);
252  }
253  A::copy(pDestination, first, (size_type)(afterLast - first));
254  }
255  }
256  else
257  {
258  rise_error(eInvalidInput);
259  }
260  }
266  void resize(
268  const T& value )
269  {
270  size_type len = length();
271  int d = logicalLength - len;
272  if ( d > 0 )
273  {
274  reallocator r( m_pData > &value || &value > (m_pData + len) );
275  r.reallocate(this, logicalLength);
276  A::constructn(m_pData + len, d, value);
277  }
278  else if ( d < 0 )
279  {
280  d=-d;
281  if(!referenced())
282  {
283  A::destroy(m_pData + logicalLength, d);
284  }
285  else
286  {
287  copy_buffer(logicalLength);
288  }
289  }
290  buffer()->m_nLength = logicalLength;
291  }
292 
297  void resize(
299  {
300  size_type len = length();
301  int d = logicalLength - len;
302  if ( d > 0 )
303  {
304  copy_before_write( len + d, true );
305  A::constructn(m_pData + len, d);
306  }
307  else if ( d < 0 )
308  {
309  d = -d;
310  if ( !referenced() )
311  {
312  A::destroy( m_pData + logicalLength, d );
313  }
314  else
315  {
316  copy_buffer(logicalLength);
317  }
318  }
319  buffer()->m_nLength = logicalLength;
320  }
321 
325  size_type size() const { return buffer()->m_nLength; }
326 
330  bool empty() const { return size() == 0; }
331 
335  size_type capacity() const { return buffer()->m_nAllocated; }
336 
343  void reserve(
344  size_type reserveLength) { if(physicalLength() < reserveLength) { setPhysicalLength(reserveLength); } }
345 
356  void assign(
358  const_iterator afterLast)
359  { erase(begin_non_const(), end_non_const()); insert(begin_non_const(), first, afterLast); }
360 
368  iterator first,
369  iterator afterLast)
370  {
371  size_type i = (size_type)(first - begin_const());
372  if(first != afterLast)
373  {
374  removeSubArray(i, (size_type)(afterLast-begin_const()-1));
375  }
376  return begin_non_const()+i;
377  }
378 
385  iterator where)
386  {
387  size_type i = where - begin_const();
388  removeAt(i);
389  return begin_non_const()+i;
390  }
394  void clear() { erase(begin_non_const(), end_non_const()); }
395 
399  void push_back(
400  const T& value) { insertAt(length(), value); }
401 
413  iterator before,
414  size_type numElements,
415  const T& value)
416  {
417  size_type len = length();
418  size_type index = before - begin_const();
419  reallocator r( m_pData > &value || &value > (m_pData + len) );
420  r.reallocate(this, len + numElements);
421  A::constructn(m_pData + len, numElements, value);
422  buffer()->m_nLength = len + numElements;
423  T* pData = data();
424  pData += index;
425  if(index != len)
426  {
427  A::move(pData + numElements, pData, len - index);
428  }
429  while(numElements--)
430  {
431  pData[numElements] = value;
432  }
433  return begin_non_const()+index;
434  }
435 
446  iterator before,
447  const T& value = T())
448  {
449  size_type index = before - begin_const();
450  insertAt(index, value);
451  return (begin_non_const() + index);
452  }
453 
454  // ARX-like interface
455 
462  bool contains(
463  const T& value,
464  size_type start = 0) const
465  { size_type dummy; return find(value, dummy, start); }
466 
467 
471  size_type length() const { return buffer()->m_nLength; }
472 
476  bool isEmpty() const { return length() == 0; }
477 
481  size_type logicalLength() const { return length(); }
482 
486  size_type physicalLength() const { return buffer()->m_nAllocated; }
487 
491  int growLength() const { return buffer()->m_nGrowBy; }
492 
496  const T* asArrayPtr() const { return data(); }
497 
501  const T* getPtr() const { return data(); }
502 
506  T* asArrayPtr() { copy_if_referenced(); return data(); }
507 
511  const T& operator [](
512  size_type index) const { assertValid(index); return m_pData[index]; }
514  size_type index) { assertValid(index); copy_if_referenced(); return m_pData[index]; }
515 
516 
521  T& at(
522  size_type arrayIndex) { assertValid(arrayIndex); copy_if_referenced(); return *(data() + arrayIndex); }
527  const T& at(size_type arrayIndex) const { assertValid(arrayIndex); return *(data() + arrayIndex); }
528 
535  size_type arrayIndex,
536  const T& value)
537  { assertValid(arrayIndex); copy_if_referenced(); m_pData[arrayIndex] = value; return *this; }
538 
543  const T& getAt(
544  size_type arrayIndex) const { assertValid(arrayIndex); return *(data() + arrayIndex); }
545 
549  T& first() { return *begin(); }
553  const T& first() const { return *begin(); }
554 
558  T& last() { return at(length()-1); }
562  const T& last() const { return at(length()-1); }
563 
573  const T& value) { insertAt(length(), value); return length()-1; }
574 
579  iterator append() { size_type i = append(T()); return begin_non_const() + i; }
580 
585 
590 
596  int growLength)
597  {
598  if(growLength != 0)
599  {
600  copy_if_referenced();
601  buffer()->m_nGrowBy = growLength;
602  }
603  else
604  {
605  ODA_FAIL();
606  }
607  return *this;
608  }
609 
613  explicit OdArrayMemAlloc(
615  int growLength = 8) : m_pData(0)
616  {
617  if(growLength != 0)
618  {
619  m_pData = Buffer::allocate(physicalLength, growLength)->data();
620  }
621  else
622  {
623  ODA_FAIL();
624  *this = OdArrayMemAlloc<T,A>();
625  }
626  }
627 
628  OdArrayMemAlloc() : m_pData(Buffer::_default()->data()) { buffer()->addref(); }
629 
630  OdArrayMemAlloc(const OdArrayMemAlloc& source) : m_pData((T*)source.data()) { buffer()->addref(); }
631 
632  ~OdArrayMemAlloc() { buffer()->release(); }
633 
635  const OdArrayMemAlloc& source)
636  {
637  source.buffer()->addref();
638  if (m_pData != 0)
639  buffer()->release();
640  m_pData = source.m_pData;
641  return *this;
642  }
643 
645  const OdArrayMemAlloc& array) const
646  {
647  if(length() == array.length())
648  {
649  for(size_type i = 0; i < length(); i++)
650  {
651  if(at(i) != array[i])
652  {
653  return false;
654  }
655  }
656  return true;
657  }
658  return false;
659  }
660 
666  const T& value)
667  {
668  copy_if_referenced();
669  T* pData = data();
670  size_type n = length();
671  while(n)
672  {
673  pData[--n] = value;
674  }
675  return *this;
676  }
686  const OdArrayMemAlloc& otherArray)
687  {
688  insert(end_non_const(), otherArray.begin(), otherArray.end());
689  return *this;
690  }
691 
706  size_type arrayIndex,
707  const T& value)
708  {
709  size_type len = length();
710  if( arrayIndex == len )
711  {
712  resize( len + 1, value );
713  }
714  else if ( arrayIndex < len )
715  {
716  reallocator r( m_pData > &value || &value > (m_pData + len) );
717  r.reallocate( this, len+1 );
718  A::construct( m_pData + len );
719  ++(buffer()->m_nLength);
720  A::move(m_pData + arrayIndex + 1, m_pData + arrayIndex, len - arrayIndex);
721  m_pData[arrayIndex] = value;
722  }
723  else
724  {
725  rise_error(eInvalidIndex);
726  }
727  return *this;
728  }
729 
743  size_type arrayIndex)
744  {
745  assertValid(arrayIndex);
746  size_type len = length();
747  if(arrayIndex < --len)
748  {
749  copy_if_referenced();
750  T* pData = data();
751  A::move(pData + arrayIndex, pData + arrayIndex + 1, len - arrayIndex);
752  }
753  resize(len);
754  return *this;
755  }
756 
769  size_type startIndex,
770  size_type endIndex)
771  {
772  if(!isValid(startIndex) || startIndex > endIndex)
773  {
774  rise_error(eInvalidIndex);
775  }
776  size_type len = length();
777  copy_if_referenced();
778  T* pData = data();
779  ++endIndex;
780  size_type n2remove = endIndex - startIndex;
781  A::move(pData + startIndex, pData + endIndex, len - endIndex);
782  A::destroy(pData + len - n2remove, n2remove);
783  buffer()->m_nLength -= n2remove;
784  return *this;
785  }
786 
797  bool find(
798  const T& value,
799  size_type& findIndex,
800  size_type start=0) const
801  {
802  if(!empty())
803  {
804  assertValid(start);
805  size_type len = length();
806  const T* pData = data();
807  for(size_type i = start; i<len; ++i)
808  {
809  if(pData[i] == value)
810  {
811  findIndex = i;
812  return true;
813  }
814  }
815  }
816  return false;
817  }
818 
826  size_type logLength)
827  {
828  resize(logLength);
829  return *this;
830  }
831 
839  size_type physLength)
840  {
841  if(physLength==0)
842  {
843  *this = OdArrayMemAlloc<T, A>();
844  }
845  else if(physLength != physicalLength())
846  {
847  copy_buffer(physLength,true,true);
848  }
849  return *this;
850  }
851 
856  {
857  if(!empty())
858  {
859  copy_if_referenced();
860  T tmp;
861  iterator iter1 = begin_non_const();
862  iterator iter2 = end_non_const();
863  --iter2;
864  while(iter1 < iter2)
865  {
866  tmp = *iter1;
867  *iter1 = *iter2;
868  *iter2 = tmp;
869  ++iter1;
870  --iter2;
871  }
872  }
873  return *this;
874  }
875 
876 
883  size_type firstIndex,
884  size_type secondIndex)
885  {
886  if(!isValid(firstIndex) || !isValid(secondIndex))
887  {
888  rise_error(eInvalidIndex);
889  }
890  if(firstIndex != secondIndex)
891  {
892  const T tmp = at(firstIndex);
893  at(firstIndex) = at(secondIndex);
894  at(secondIndex) = tmp;
895  }
896  return *this;
897  }
909  bool remove(
910  const T& value,
911  size_type start = 0)
912  {
913  size_type i = 0;
914  if(find(value, i, start))
915  {
916  removeAt(i);
917  return true;
918  }
919  return false;
920  }
921 private:
922 
923  T* m_pData;
924 
925  bool isValid(size_type i) const { return (i < length()); }
926 
927  T* data() { return (length() ? m_pData : 0); }
928 
929  const T* data() const { return m_pData; }
930 
931  Buffer* buffer() const
932  {
933  return (reinterpret_cast<Buffer*>(const_cast<OdArrayMemAlloc*>(this)->m_pData) - 1);
934  }
935  bool referenced() const
936  {
937  return (buffer()->m_nRefCounter>1);
938  }
939 };
940 
941 #include "TD_PackPop.h"
942 
943 #endif // ODARRAYMEMALLOC_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 * odrxRealloc(void *pMemBlock, size_t newSize, size_t oldSize)
ALLOCDLL_EXPORT void * odrxAlloc(size_t nBytes)
ALLOCDLL_EXPORT void odrxFree(void *pMemBlock)
#define odmin(X, Y)
Definition: OdPlatform.h:34
OdResult
Definition: OdResult.h:29
OdArrayMemAlloc & operator=(const OdArrayMemAlloc &source)
OdArrayMemAlloc & swap(size_type firstIndex, size_type secondIndex)
bool contains(const T &value, size_type start=0) const
bool remove(const T &value, size_type start=0)
const T & at(size_type arrayIndex) const
OdArrayMemAlloc & removeLast()
iterator insert(iterator before, size_type numElements, const T &value)
const T * const_iterator
OdArrayMemAlloc & reverse()
void reserve(size_type reserveLength)
bool isEmpty() const
void insert(iterator before, const_iterator first, const_iterator afterLast)
const_iterator end() const
bool find(const T &value, size_type &findIndex, size_type start=0) const
size_type append(const T &value)
const_iterator begin() const
OdArrayMemAlloc(const OdArrayMemAlloc &source)
iterator insert(iterator before, const T &value=T())
void push_back(const T &value)
OdArrayMemAlloc & setAll(const T &value)
const T & last() const
OdArrayMemAlloc & setLogicalLength(size_type logLength)
OdArrayMemAlloc & setAt(size_type arrayIndex, const T &value)
A::size_type size_type
size_type size() const
iterator erase(iterator where)
OdArrayMemAlloc & insertAt(size_type arrayIndex, const T &value)
bool operator==(const OdArrayMemAlloc &array) const
size_type logicalLength() const
OdArrayMemAlloc & removeAt(size_type arrayIndex)
const T & operator[](size_type index) const
int growLength() const
OdArrayMemAlloc & removeSubArray(size_type startIndex, size_type endIndex)
OdArrayMemAlloc(size_type physicalLength, int growLength=8)
const T * getPtr() const
void resize(size_type logicalLength)
const T & first() const
OdArrayMemAlloc & append(const OdArrayMemAlloc &otherArray)
size_type physicalLength() const
OdArrayMemAlloc & removeFirst()
OdArrayMemAlloc & setGrowLength(int growLength)
void assign(const_iterator first, const_iterator afterLast)
const T * asArrayPtr() const
OdArrayMemAlloc & setPhysicalLength(size_type physLength)
friend class reallocator
T & at(size_type arrayIndex)
size_type length() const
size_type capacity() const
iterator erase(iterator first, iterator afterLast)
const T & getAt(size_type arrayIndex) const
void resize(size_type logicalLength, const T &value)
bool empty() const
static void Free(void *pMemBlock)
static void * Realloc(void *pMemBlock, size_t newSize, size_t oldSize)
static void * Alloc(size_t nBytes)
GLuint buffer
Definition: gles2_ext.h:178
GLint GLenum GLsizei GLsizei GLint GLsizei const void * data
Definition: gles2_ext.h:110
GLuint index
Definition: gles2_ext.h:265
GLsizei GLsizei GLchar * source
Definition: gles2_ext.h:282
GLsizei const GLfloat * value
Definition: gles2_ext.h:302