jarray.cpp 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. /*##############################################################################
  2. HPCC SYSTEMS software Copyright (C) 2012 HPCC Systems®.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. ############################################################################## */
  13. #include "jiface.hpp"
  14. #include "jarray.hpp"
  15. #include "jsort.hpp"
  16. #include "jmisc.hpp"
  17. #include "jlib.hpp"
  18. #include <assert.h>
  19. #define FIRST_CHUNK_SIZE 8
  20. #define DOUBLE_LIMIT 0x100000 // must be a power of 2
  21. #define ALLOCA_LIMIT 64
  22. inline unsigned ensurePowerOfTwo(unsigned value)
  23. {
  24. value--;
  25. value |= (value >> 1);
  26. value |= (value >> 2);
  27. value |= (value >> 4);
  28. value |= (value >> 8);
  29. value |= (value >> 16);
  30. return value+1;
  31. }
  32. void Allocator::_space(size32_t iSize)
  33. {
  34. if ( used == max )
  35. _reallocate(used+1, iSize);
  36. used++;
  37. }
  38. void Allocator::_ensure(aindex_t next, size32_t iSize)
  39. {
  40. aindex_t req = used + next;
  41. if (req > max )
  42. {
  43. if ((max == 0) && (req < DOUBLE_LIMIT))
  44. max = ensurePowerOfTwo(req);
  45. _reallocate(req, iSize);
  46. }
  47. }
  48. void Allocator::kill()
  49. {
  50. if (_head)
  51. {
  52. free(_head);
  53. _init();
  54. }
  55. }
  56. void Allocator::_reallocate(aindex_t newLen, size32_t itemSize)
  57. {
  58. size32_t newMax = max;
  59. if (newMax == 0)
  60. newMax = FIRST_CHUNK_SIZE;
  61. if (newLen > DOUBLE_LIMIT)
  62. {
  63. newMax = (newLen + DOUBLE_LIMIT) & ~(DOUBLE_LIMIT-1);
  64. if (newLen >= newMax) // wraparound
  65. {
  66. PrintLog("Out of memory (overflow) in Array allocator: itemSize = %d, trying to allocate %d items", itemSize, newLen);
  67. throw MakeStringException(0, "Out of memory (overflow) in Array allocator: itemSize = %d, trying to allocate %d items",itemSize, newLen);
  68. }
  69. }
  70. else
  71. {
  72. while (newLen > newMax)
  73. newMax += newMax;
  74. }
  75. size_t allocSize = (size_t)itemSize * newMax;
  76. if (allocSize < newMax)
  77. {
  78. PrintLog("Out of memory (overflow) in Array allocator: itemSize = %d, trying to allocate %d items", itemSize, newLen);
  79. throw MakeStringException(0, "Out of memory (overflow) in Array allocator: itemSize = %u, trying to allocate %u items",itemSize, newLen);
  80. }
  81. void *newhead = realloc(_head, allocSize);
  82. if (!newhead)
  83. {
  84. PrintLog("Out of memory in Array allocator: itemSize = %d, trying to allocate %d items", itemSize, max);
  85. throw MakeStringException(0, "Out of memory in Array allocator: itemSize = %d, trying to allocate %d items",itemSize, max);
  86. }
  87. max = newMax;
  88. _head = newhead;
  89. };
  90. void Allocator::_doRotateR(aindex_t pos1, aindex_t pos2, size32_t iSize, aindex_t numItems)
  91. {
  92. size32_t saveSize = numItems * iSize;
  93. size32_t blockSize = (pos2+1-pos1) * iSize;
  94. if (blockSize == saveSize)
  95. return;
  96. assertex(blockSize > saveSize);
  97. char * head= (char *)_head;
  98. char * lower = head + pos1 * iSize;
  99. char * upper = lower + (blockSize - saveSize);
  100. char * temp = (char *)((saveSize <= ALLOCA_LIMIT) ? alloca(saveSize) : malloc(saveSize));
  101. memcpy(temp, upper, saveSize);
  102. memmove(lower + saveSize, lower, blockSize-saveSize);
  103. memcpy(lower, temp, saveSize);
  104. if (saveSize > ALLOCA_LIMIT)
  105. free(temp);
  106. }
  107. void Allocator::_doRotateL(aindex_t pos1, aindex_t pos2, size32_t iSize, size32_t numItems)
  108. {
  109. size32_t saveSize = numItems * iSize;
  110. size32_t blockSize = (pos2+1-pos1) * iSize;
  111. if (blockSize == saveSize)
  112. return;
  113. assertex(blockSize > saveSize);
  114. char * head= (char *)_head;
  115. char * lower = head + pos1 * iSize;
  116. char * upper = lower + (blockSize - saveSize);
  117. char * temp = (char *)((saveSize <= ALLOCA_LIMIT) ? alloca(saveSize) : malloc(saveSize));
  118. memcpy(temp, lower, saveSize);
  119. memmove(lower, lower + saveSize, blockSize - saveSize);
  120. memcpy(upper, temp, saveSize);
  121. if (saveSize > ALLOCA_LIMIT)
  122. free(temp);
  123. }
  124. void Allocator::_doSwap(aindex_t pos1, aindex_t pos2, size32_t iSize)
  125. {
  126. char * head= (char *)_head;
  127. char * lower = head + pos1 * iSize;
  128. char * upper = head + pos2 * iSize;
  129. char * temp = (char *)alloca(iSize);
  130. memcpy(temp, lower, iSize);
  131. memmove(lower, upper, iSize );
  132. memcpy(upper, temp, iSize);
  133. }
  134. void Allocator::_doTransfer(aindex_t to, aindex_t from, size32_t iSize)
  135. {
  136. if (from != to)
  137. {
  138. if (from < to)
  139. _doRotateL(from, to, iSize, 1);
  140. else
  141. _doRotateR(to, from, iSize, 1);
  142. }
  143. }
  144. void * Allocator::_doBAdd(void * newItem, size32_t _size, StdCompare compare, bool & isNew)
  145. {
  146. return ::binary_add(newItem, _head, used-1, _size, compare, &isNew);
  147. }
  148. void * Allocator::_doBSearch(const void * key, size32_t _size, StdCompare compare) const
  149. {
  150. return bsearch(key, _head, used, _size, compare);
  151. }
  152. void Allocator::_doSort(size32_t _size, StdCompare compare)
  153. {
  154. if (used > 1)
  155. qsort(_head, used, _size, compare);
  156. }
  157. void Allocator::doSwapWith(Allocator & other)
  158. {
  159. void * saveHead = _head;
  160. _head = other._head;
  161. other._head = saveHead;
  162. aindex_t saveUsed = used;
  163. used = other.used;
  164. other.used = saveUsed;
  165. aindex_t saveMax = max;
  166. max = other.max;
  167. other.max = saveMax;
  168. }