llalignedarray.h 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. /**
  2. * @file llalignedarray.h
  3. * @brief A static array which obeys alignment restrictions and mimics std::vector accessors.
  4. *
  5. * $LicenseInfo:firstyear=2013&license=viewergpl$
  6. *
  7. * Copyright (c) 2013, Linden Research, Inc.
  8. *
  9. * Second Life Viewer Source Code
  10. * The source code in this file ("Source Code") is provided by Linden Lab
  11. * to you under the terms of the GNU General Public License, version 2.0
  12. * ("GPL"), unless you have obtained a separate licensing agreement
  13. * ("Other License"), formally executed by you and Linden Lab. Terms of
  14. * the GPL can be found in doc/GPL-license.txt in this distribution, or
  15. * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  16. *
  17. * There are special exceptions to the terms and conditions of the GPL as
  18. * it is applied to this Source Code. View the full text of the exception
  19. * in the file doc/FLOSS-exception.txt in this software distribution, or
  20. * online at
  21. * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  22. *
  23. * By copying, modifying or distributing this software, you acknowledge
  24. * that you have read and understood your obligations described above,
  25. * and agree to abide by those obligations.
  26. *
  27. * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
  28. * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
  29. * COMPLETENESS OR PERFORMANCE.
  30. * $/LicenseInfo$
  31. */
  32. #ifndef LL_LLALIGNEDARRAY_H
  33. #define LL_LLALIGNEDARRAY_H
  34. #include "llmemory.h"
  35. LL_NO_INLINE static void ll_aligned_array_out_of_bounds(U32 idx, U32 count,
  36. U32 loc)
  37. {
  38. llwarns << "Out of bounds LLAlignedArray index requested (" << loc << "): "
  39. << idx << " - size: " << count << llendl;
  40. llassert(false);
  41. }
  42. template <class T, U32 alignment>
  43. class LLAlignedArray
  44. {
  45. protected:
  46. LOG_CLASS(LLAlignedArray);
  47. // Sets the container to the requested 'size' if possible. When successful
  48. // returns true (at which point mElementCount has also been set to 'size'),
  49. // or false when there has been a failure to expand the capacity to fit the
  50. // requested size (mElementCount is then left untouched).
  51. bool expand(U32 size);
  52. public:
  53. LL_INLINE LLAlignedArray() noexcept
  54. : mArray(NULL),
  55. mElementCount(0),
  56. mCapacity(0)
  57. {
  58. }
  59. LL_INLINE ~LLAlignedArray() noexcept
  60. {
  61. if (mArray)
  62. {
  63. ll_aligned_free((void*)mArray);
  64. mArray = NULL;
  65. }
  66. mElementCount = mCapacity = 0;
  67. }
  68. LL_INLINE void push_back(const T& elem)
  69. {
  70. if (mCapacity <= mElementCount)
  71. {
  72. if (expand(mElementCount + 1))
  73. {
  74. // Because expand() just incremented it...
  75. --mElementCount;
  76. }
  77. }
  78. if (!mArray || mCapacity <= mElementCount)
  79. {
  80. // Cannot go further...
  81. llassert(false);
  82. return;
  83. }
  84. mArray[mElementCount++] = elem;
  85. }
  86. LL_INLINE U32 size() const
  87. {
  88. return mElementCount;
  89. }
  90. LL_INLINE U32 empty() const
  91. {
  92. return mElementCount == 0;
  93. }
  94. LL_INLINE void resize(U32 size)
  95. {
  96. expand(size);
  97. }
  98. LL_INLINE T* append(S32 N)
  99. {
  100. U32 sz = size();
  101. resize(sz + N);
  102. return &((*this)[sz]);
  103. }
  104. LL_INLINE T& operator[](U32 idx)
  105. {
  106. if (idx >= mElementCount)
  107. {
  108. ll_aligned_array_out_of_bounds(idx, mElementCount, 1);
  109. // Avoids crashing for release builds...
  110. return mDummy;
  111. }
  112. return mArray[idx];
  113. }
  114. LL_INLINE const T& operator[](U32 idx) const
  115. {
  116. if (idx >= mElementCount)
  117. {
  118. ll_aligned_array_out_of_bounds(idx, mElementCount, 2);
  119. // Avoids crashing for release builds...
  120. return mDummy;
  121. }
  122. return mArray[idx];
  123. }
  124. public:
  125. T* mArray;
  126. T mDummy;
  127. U32 mElementCount;
  128. U32 mCapacity;
  129. };
  130. template <class T, U32 alignment>
  131. LL_NO_INLINE bool LLAlignedArray<T, alignment>::expand(U32 size)
  132. {
  133. if (mCapacity < size)
  134. {
  135. U32 new_capacity = size <= 128 ? 2 * size + 16 : size + size / 8;
  136. T* new_buf = (T*)ll_aligned_malloc(new_capacity * sizeof(T),
  137. alignment);
  138. if (!new_buf)
  139. {
  140. // Try with the strict required number of elements
  141. new_capacity = size;
  142. new_buf = (T*)ll_aligned_malloc(new_capacity * sizeof(T),
  143. alignment);
  144. }
  145. if (!new_buf)
  146. {
  147. llwarns << "Failure to resize to " << size << " elements !"
  148. << llendl;
  149. return false;
  150. }
  151. // Zero out the new allocated elements in the new array. HB
  152. memset((void*)(new_buf + mCapacity), 0,
  153. (size - mCapacity) * sizeof(T));
  154. if (mArray && mElementCount)
  155. {
  156. ll_memcpy_nonaliased_aligned_16((char*)new_buf,
  157. (char*)mArray,
  158. sizeof(T) * mElementCount);
  159. }
  160. if (mArray)
  161. {
  162. ll_aligned_free((void*)mArray);
  163. }
  164. mArray = new_buf;
  165. mCapacity = new_capacity;
  166. }
  167. mElementCount = size;
  168. return true;
  169. }
  170. #endif