Mem Extended.cpp 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287
  1. /******************************************************************************/
  2. #include "stdafx.h"
  3. #if APPLE
  4. #ifndef PAGE_SIZE
  5. #define PAGE_SIZE 4096 // Apple has 4k page size - https://developer.apple.com/library/mac/documentation/performance/conceptual/managingmemory/articles/aboutmemory.html "In both OS X and iOS, the size of a page is 4 kilobytes."
  6. #endif
  7. #endif
  8. #if IOS
  9. #define RISKY_MEM 1
  10. #endif
  11. namespace EE{
  12. /******************************************************************************
  13. 'valid', 'invalid' - they point into index in 'abs'
  14. data in 'abs' - first there is UInt index pointing into 'valid' or 'invalid' (SIGN_BIT), after UInt there is actual data
  15. /******************************************************************************/
  16. #if RISKY_MEM
  17. static inline Bool RiskyMem(CPtr data) {return (UIntPtr(data)&(PAGE_SIZE-1))<SIZE(UInt);} // if the data lies at the page boundary making the previous UInt to belong to a different page
  18. #endif
  19. /******************************************************************************/
  20. void _Memx::_reset(Int elm_size, Int block_elms, void (*_new)(Ptr elm), void (*_del)(Ptr elm))
  21. {
  22. T.~_Memx();
  23. new(this)_Memx(elm_size, block_elms, _new, _del);
  24. }
  25. _Memx::_Memx(Int elm_size, Int block_elms, void (*_new)(Ptr elm), void (*_del)(Ptr elm)) : _abs(SIZE(UInt)+elm_size, block_elms, null, null)
  26. {
  27. T._new=_new;
  28. T._del=_del;
  29. }
  30. void _Memx::del()
  31. {
  32. clear();
  33. _abs.del();
  34. _valid.del();
  35. _invalid.del();
  36. }
  37. void _Memx::clear()
  38. {
  39. if(_del)REPA(_valid)_del(validElm(i));
  40. _abs.clear();
  41. _valid.clear();
  42. _invalid.clear();
  43. }
  44. /******************************************************************************/
  45. Ptr _Memx::New()
  46. {
  47. UInt i; if(_invalid.elms())i=_invalid.pop();else i=_abs.addNum(1);
  48. UInt v=_valid.addNum(1);
  49. _valid[v]=i;
  50. Ptr elm=absElm(i);
  51. ((UInt*)elm)[-1]=v; // store valid index
  52. if(_new)_new(elm);else if(!elmSize())Exit("Attempting to create an object of zero size in 'Memx' container.\nThe container is not initialized or it is abstract and 'replaceClass' hasn't been called.");
  53. return elm;
  54. }
  55. Ptr _Memx::NewAt(Int i)
  56. {
  57. Clamp(i, 0, elms());
  58. Ptr elm=New(); // now 'elm' is at the end
  59. for(Int j=elms()-2; j>=i; j--)swapOrder(j, j+1);
  60. return elm;
  61. }
  62. /******************************************************************************/
  63. void _Memx::removeAbs(Int i, Bool keep_order)
  64. {
  65. if(InRange(i, _abs))
  66. {
  67. Ptr elm =absElm(i);
  68. UInt index=((UInt*)elm)[-1];
  69. if(!(index&SIGN_BIT))removeValid(index, keep_order); // if actually valid
  70. }
  71. }
  72. void _Memx::removeValid(Int i, Bool keep_order)
  73. {
  74. if(InRange(i, _valid))
  75. {
  76. // element info
  77. UInt abs=_valid [i ];
  78. Ptr elm= absElm(abs);
  79. // put removed to invalid
  80. UInt inv=_invalid.addNum(1);
  81. _invalid[inv]=abs;
  82. ((UInt*)elm)[-1]=inv^SIGN_BIT;
  83. if(keep_order)
  84. {
  85. _valid.remove(i, true); // remove from valid, 'true' is required because of UInt indexes
  86. for(; i<_valid.elms(); i++)
  87. {
  88. Ptr elm=validElm(i);
  89. ((UInt*)elm)[-1]=i; // set updated index
  90. }
  91. }else
  92. {
  93. _valid.remove(i, false); // remove from valid, 'false' is required because of UInt indexes
  94. if(_valid.elms()>i ) // fix another valid which was moved in 'remove'
  95. {
  96. Ptr elm=validElm(i);
  97. ((UInt*)elm)[-1]=i; // set updated index of element which was placed into removed element place
  98. }
  99. }
  100. // delete element
  101. if(_del)_del(elm);
  102. }
  103. }
  104. void _Memx::removeData(CPtr elm, Bool keep_order)
  105. {
  106. removeValid(validIndex(elm), keep_order);
  107. }
  108. void _Memx::removeLast()
  109. {
  110. removeValid(elms()-1);
  111. }
  112. void _Memx::setNum(Int num)
  113. {
  114. MAX(num, 0);
  115. if (num>elms()) // add elements
  116. {
  117. REP(num-elms())New();
  118. }else
  119. if(num<elms()) // remove elements
  120. {
  121. REP(elms()-num)removeValid(num+i);
  122. }
  123. }
  124. Int _Memx::addNum(Int num) {Int index=elms(); setNum(elms()+num); return index;}
  125. void _Memx::reverseOrder()
  126. {
  127. Int last=elms()-1;
  128. REP(elms()/2)
  129. {
  130. Int j=last-i;
  131. UInt &ai=_valid[i], // absolute index of i-th valid element
  132. &aj=_valid[j]; // absolute index of j-th valid element
  133. Swap(*(UInt*)(_abs[ai]), *((UInt*)_abs[aj]));
  134. Swap( ai , aj );
  135. }
  136. }
  137. void _Memx::swapOrder(Int i, Int j)
  138. {
  139. if(InRange(i, elms()) && InRange(j, elms()) && i!=j)
  140. {
  141. UInt &ai=_valid[i], // absolute index of i-th valid element
  142. &aj=_valid[j]; // absolute index of j-th valid element
  143. Swap(*(UInt*)(_abs[ai]), *((UInt*)_abs[aj]));
  144. Swap( ai , aj );
  145. }
  146. }
  147. void _Memx::moveElm(Int elm, Int new_index)
  148. {
  149. if(InRange(elm, elms()))
  150. {
  151. Clamp(new_index, 0, elms()-1); if(new_index!=elm)
  152. {
  153. if(new_index>elm) // moving from left to right
  154. {
  155. for(Int i=elm+1; i<=new_index; i++){Int abs=_valid[i]; (*(UInt*)(_abs[abs]))--;} // elements now have smaller valid indexes
  156. }else // moving from right to left
  157. {
  158. for(Int i=elm-1; i>=new_index; i--){Int abs=_valid[i]; (*(UInt*)(_abs[abs]))++;} // elements now have bigger valid indexes
  159. }
  160. Int abs=_valid[elm]; *(UInt*)(_abs[abs])=new_index;
  161. _valid.moveElm(elm, new_index);
  162. }
  163. }
  164. }
  165. void _Memx::moveElmLeftUnsafe(Int elm, Int new_index)
  166. {
  167. if(new_index!=elm)
  168. {
  169. #if 0 // not needed since we're always moving left in this function
  170. if(new_index>elm) // moving from left to right
  171. {
  172. for(Int i=elm+1; i<=new_index; i++){Int abs=_valid[i]; (*(UInt*)(_abs[abs]))--;} // elements now have smaller valid indexes
  173. }else // moving from right to left
  174. #endif
  175. {
  176. for(Int i=elm-1; i>=new_index; i--){Int abs=_valid[i]; (*(UInt*)(_abs[abs]))++;} // elements now have bigger valid indexes
  177. }
  178. Int abs=_valid[elm]; *(UInt*)(_abs[abs])=new_index;
  179. UInt temp; ASSERT(SIZE(*_valid.data())==SIZE(temp)); _valid.moveElmLeftUnsafe(elm, new_index, &temp);
  180. }
  181. }
  182. void _Memx::moveToStart(Int i) {moveElm(i, 0);}
  183. void _Memx::moveToEnd (Int i) {moveElm(i, elms()-1);}
  184. /******************************************************************************/
  185. void _Memx::copyTo ( Ptr dest)C {if(dest)FREPA(T){CopyFast(dest, T[i], elmSize()); dest=(Byte*)dest+elmSize();}}
  186. void _Memx::copyFrom(CPtr src ) { FREPA(T){Copy (T[i], src , elmSize()); if(src)src =(Byte*)src +elmSize();}}
  187. /******************************************************************************/
  188. UInt _Memx::memUsage()C
  189. {
  190. return _abs.memUsage()
  191. +_valid.memUsage()
  192. +_invalid.memUsage();
  193. }
  194. /******************************************************************************/
  195. Int _Memx::validToAbsIndex(Int valid)C
  196. {
  197. return InRange(valid, _valid) ? _valid[valid] : -1;
  198. }
  199. Int _Memx::absToValidIndex(Int abs)C
  200. {
  201. if(InRange(abs, _abs))
  202. {
  203. Ptr elm =absElm(abs);
  204. UInt index=((UInt*)elm)[-1];
  205. if(!(index&SIGN_BIT))return index; // if not removed
  206. }
  207. return -1;
  208. }
  209. Int _Memx::absIndex(CPtr elm)C
  210. {
  211. if(elm && absElms()) // check if there are still elements left (in case memory was already released by destructor)
  212. {
  213. #if RISKY_MEM
  214. if(RiskyMem(elm))return _abs.index(elm); // when the memory is risky then do a slow/safe version to avoid EXC_BAD_ACCESS
  215. #endif
  216. UInt index=((UInt*)elm)[-1];
  217. if( index&SIGN_BIT) // removed
  218. {
  219. index^=SIGN_BIT; if(InRange(index, _invalid))
  220. {
  221. Int abs_index=_invalid[index];
  222. if( absElm(abs_index)==elm)return abs_index;
  223. }
  224. }else
  225. {
  226. if(InRange(index, _valid))
  227. {
  228. Int abs_index=_valid[index];
  229. if( absElm(abs_index)==elm)return abs_index;
  230. }
  231. }
  232. }
  233. return -1;
  234. }
  235. Int _Memx::absIndexFastUnsafeValid(CPtr elm)C
  236. {
  237. UInt index=((UInt*)elm)[-1]; return _valid[index];
  238. }
  239. Int _Memx::validIndex(CPtr elm)C
  240. {
  241. if(elm && validElms()) // check if there are still elements left (in case memory was already released by destructor)
  242. {
  243. #if RISKY_MEM
  244. if(RiskyMem(elm) && _abs.index(elm)<0)return -1; // when the memory is risky then do a slow/safe check to avoid EXC_BAD_ACCESS
  245. #endif
  246. UInt index=((UInt*)elm)[-1];
  247. if(!(index&SIGN_BIT)) // if index points to a valid element
  248. if(InRange(index, _valid)) // if index fits
  249. if(validElm(index)==elm)return index; // if memory address fits
  250. }
  251. return -1;
  252. }
  253. /******************************************************************************/
  254. void _Memx::verify()C
  255. {
  256. REPA(T)
  257. {
  258. Int abs=validToAbsIndex(i);
  259. if(!InRange(abs, _abs))Exit("Invalid abs index");
  260. Int valid=absToValidIndex(abs);
  261. if( valid!=i)Exit("Invalid valid index");
  262. }
  263. }
  264. /******************************************************************************/
  265. Bool _Memx::saveRaw(File &f)C
  266. {
  267. f.cmpUIntV(elms());
  268. FREPA(T)f.put(T[i], elmSize());
  269. return f.ok();
  270. }
  271. Bool _Memx::loadRaw(File &f)
  272. {
  273. setNum(f.decUIntV());
  274. FREPA(T)f.getFast(T[i], elmSize());
  275. if(f.ok())return true;
  276. clear(); return false;
  277. }
  278. /******************************************************************************/
  279. }
  280. /******************************************************************************/