ContinuousPageStack.h 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533
  1. //-------------------------------------------------------------------------------------------------------
  2. // Copyright (C) Microsoft. All rights reserved.
  3. // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
  4. //-------------------------------------------------------------------------------------------------------
  5. #pragma once
  6. // -----------------------------------------------------------------------------------------------------------------------------
  7. // ContinuousPageStack declaration
  8. // -----------------------------------------------------------------------------------------------------------------------------
  9. template<const size_t InitialPageCount = 1>
  10. class ContinuousPageStack : protected Allocator
  11. {
  12. protected:
  13. class Iterator
  14. {
  15. protected:
  16. size_t nextTop;
  17. protected:
  18. inline Iterator(const ContinuousPageStack &stack);
  19. public:
  20. inline size_t Position() const;
  21. inline operator bool() const;
  22. };
  23. friend class Iterator;
  24. private:
  25. PageAllocator *const pageAllocator;
  26. PageAllocation *pageAllocation;
  27. size_t bufferSize;
  28. protected:
  29. size_t nextTop;
  30. protected:
  31. inline ContinuousPageStack(PageAllocator *const pageAllocator, void (*const outOfMemoryFunc)());
  32. ~ContinuousPageStack();
  33. inline char *Buffer() const;
  34. public:
  35. inline bool IsEmpty() const;
  36. inline void Clear();
  37. inline size_t Position() const;
  38. inline char* Push(const size_t size);
  39. inline char* Top(const size_t size) const;
  40. inline char* Pop(const size_t size);
  41. inline void UnPop(const size_t size);
  42. inline void PopTo(const size_t position);
  43. private:
  44. void Resize(size_t requestedSize);
  45. };
  46. // -----------------------------------------------------------------------------------------------------------------------------
  47. // ContinuousPageStackOfFixedElements declaration
  48. // -----------------------------------------------------------------------------------------------------------------------------
  49. template<class T, const size_t InitialPageCount = 1>
  50. class ContinuousPageStackOfFixedElements : public ContinuousPageStack<InitialPageCount>
  51. {
  52. public:
  53. class Iterator : public ContinuousPageStack<InitialPageCount>::Iterator
  54. {
  55. private:
  56. const ContinuousPageStackOfFixedElements &stack;
  57. public:
  58. inline Iterator(const ContinuousPageStackOfFixedElements &stack);
  59. inline T &operator *() const;
  60. inline T *operator ->() const;
  61. inline Iterator &operator ++(); // pre-increment
  62. inline Iterator operator ++(int); // post-increment
  63. };
  64. friend class Iterator;
  65. public:
  66. inline ContinuousPageStackOfFixedElements(PageAllocator *const pageAllocator, void (*const outOfMemoryFunc)());
  67. public:
  68. inline char* Push();
  69. inline T* Top() const;
  70. inline T* Pop();
  71. inline void UnPop();
  72. inline void PopTo(const size_t position);
  73. };
  74. // -----------------------------------------------------------------------------------------------------------------------------
  75. // ContinuousPageStackOfVariableElements declaration
  76. // -----------------------------------------------------------------------------------------------------------------------------
  77. template<class T, const size_t InitialPageCount = 1>
  78. class ContinuousPageStackOfVariableElements : public ContinuousPageStack<InitialPageCount>
  79. {
  80. public:
  81. class Iterator : public ContinuousPageStack<InitialPageCount>::Iterator
  82. {
  83. private:
  84. size_t topElementSize;
  85. const ContinuousPageStackOfVariableElements &stack;
  86. public:
  87. inline Iterator(const ContinuousPageStackOfVariableElements &stack);
  88. inline T &operator *() const;
  89. inline T *operator ->() const;
  90. inline Iterator &operator ++(); // pre-increment
  91. inline Iterator operator ++(int); // post-increment
  92. };
  93. friend class Iterator;
  94. private:
  95. class VariableElement
  96. {
  97. private:
  98. const size_t previousElementSize;
  99. char data[0];
  100. public:
  101. inline VariableElement(const size_t previousElementSize);
  102. public:
  103. template<class ActualT> inline static size_t Size();
  104. inline size_t PreviousElementSize() const;
  105. inline char *Data();
  106. };
  107. private:
  108. size_t topElementSize;
  109. public:
  110. inline ContinuousPageStackOfVariableElements(PageAllocator *const pageAllocator, void (*const outOfMemoryFunc)());
  111. public:
  112. template<class ActualT> inline char* Push();
  113. inline T* Top() const;
  114. inline T* Pop();
  115. template<class ActualT> inline void UnPop();
  116. inline void PopTo(const size_t position);
  117. };
  118. // -----------------------------------------------------------------------------------------------------------------------------
  119. // ContinuousPageStack definition
  120. // -----------------------------------------------------------------------------------------------------------------------------
  121. // --------
  122. // Iterator
  123. // --------
  124. template<const size_t InitialPageCount>
  125. inline ContinuousPageStack<InitialPageCount>::Iterator::Iterator(const ContinuousPageStack &stack)
  126. : nextTop(stack.nextTop)
  127. {
  128. }
  129. template<const size_t InitialPageCount>
  130. inline size_t ContinuousPageStack<InitialPageCount>::Iterator::Position() const
  131. {
  132. return nextTop;
  133. }
  134. template<const size_t InitialPageCount>
  135. inline ContinuousPageStack<InitialPageCount>::Iterator::operator bool() const
  136. {
  137. return nextTop != 0;
  138. }
  139. // -------------------
  140. // ContinuousPageStack
  141. // -------------------
  142. template<const size_t InitialPageCount>
  143. inline ContinuousPageStack<InitialPageCount>::ContinuousPageStack(
  144. PageAllocator *const pageAllocator,
  145. void (*const outOfMemoryFunc)())
  146. : Allocator(outOfMemoryFunc), pageAllocator(pageAllocator), bufferSize(0), nextTop(0)
  147. {
  148. Assert(pageAllocator);
  149. }
  150. template<const size_t InitialPageCount>
  151. ContinuousPageStack<InitialPageCount>::~ContinuousPageStack()
  152. {
  153. if(bufferSize && !pageAllocator->IsClosed())
  154. pageAllocator->ReleaseAllocation(pageAllocation);
  155. }
  156. template<const size_t InitialPageCount>
  157. inline char *ContinuousPageStack<InitialPageCount>::Buffer() const
  158. {
  159. Assert(bufferSize);
  160. return pageAllocation->GetAddress();
  161. }
  162. template<const size_t InitialPageCount>
  163. inline bool ContinuousPageStack<InitialPageCount>::IsEmpty() const
  164. {
  165. return nextTop == 0;
  166. }
  167. template<const size_t InitialPageCount>
  168. inline void ContinuousPageStack<InitialPageCount>::Clear()
  169. {
  170. nextTop = 0;
  171. }
  172. template<const size_t InitialPageCount>
  173. inline size_t ContinuousPageStack<InitialPageCount>::Position() const
  174. {
  175. return nextTop;
  176. }
  177. template<const size_t InitialPageCount>
  178. inline char* ContinuousPageStack<InitialPageCount>::Push(const size_t size)
  179. {
  180. Assert(size);
  181. if(bufferSize - nextTop < size)
  182. Resize(size);
  183. char* const res = Buffer() + nextTop;
  184. nextTop += size;
  185. return res;
  186. }
  187. template<const size_t InitialPageCount>
  188. inline char* ContinuousPageStack<InitialPageCount>::Top(const size_t size) const
  189. {
  190. if (nextTop == 0)
  191. return 0;
  192. else
  193. {
  194. Assert(size != 0);
  195. Assert(size <= nextTop);
  196. return Buffer() + (nextTop - size);
  197. }
  198. }
  199. template<const size_t InitialPageCount>
  200. inline char* ContinuousPageStack<InitialPageCount>::Pop(const size_t size)
  201. {
  202. if (nextTop == 0)
  203. return 0;
  204. else
  205. {
  206. Assert(size != 0);
  207. Assert(nextTop >= size);
  208. nextTop -= size;
  209. return Buffer() + nextTop;
  210. }
  211. }
  212. template<const size_t InitialPageCount>
  213. inline void ContinuousPageStack<InitialPageCount>::UnPop(const size_t size)
  214. {
  215. Assert(size != 0);
  216. Assert(nextTop + size <= bufferSize);
  217. nextTop += size;
  218. }
  219. template<const size_t InitialPageCount>
  220. void ContinuousPageStack<InitialPageCount>::Resize(size_t requestedSize)
  221. {
  222. Assert(requestedSize);
  223. Assert(requestedSize <= InitialPageCount * AutoSystemInfo::PageSize);
  224. if(!bufferSize)
  225. {
  226. pageAllocation = pageAllocator->AllocAllocation(InitialPageCount);
  227. if (!pageAllocation)
  228. {
  229. outOfMemoryFunc();
  230. AnalysisAssert(false);
  231. }
  232. bufferSize = pageAllocation->GetSize();
  233. return;
  234. }
  235. PageAllocation *const newPageAllocation = pageAllocator->AllocAllocation(pageAllocation->GetPageCount() * 2);
  236. if (!newPageAllocation)
  237. {
  238. outOfMemoryFunc();
  239. AnalysisAssert(false);
  240. }
  241. js_memcpy_s(newPageAllocation->GetAddress(), newPageAllocation->GetSize(), Buffer(), nextTop);
  242. pageAllocator->ReleaseAllocation(pageAllocation);
  243. pageAllocation = newPageAllocation;
  244. bufferSize = newPageAllocation->GetSize();
  245. }
  246. template<const size_t InitialPageCount>
  247. inline void ContinuousPageStack<InitialPageCount>::PopTo(const size_t position)
  248. {
  249. Assert(position <= nextTop);
  250. nextTop = position;
  251. }
  252. // -----------------------------------------------------------------------------------------------------------------------------
  253. // ContinuousPageStackOfFixedElements definition
  254. // -----------------------------------------------------------------------------------------------------------------------------
  255. // --------
  256. // Iterator
  257. // --------
  258. template<class T, const size_t InitialPageCount>
  259. inline ContinuousPageStackOfFixedElements<T, InitialPageCount>::Iterator::Iterator(
  260. const ContinuousPageStackOfFixedElements &stack)
  261. : ContinuousPageStack<InitialPageCount>::Iterator(stack), stack(stack)
  262. {
  263. }
  264. template<class T, const size_t InitialPageCount>
  265. inline T &ContinuousPageStackOfFixedElements<T, InitialPageCount>::Iterator::operator *() const
  266. {
  267. Assert(*this);
  268. Assert(this->nextTop <= stack.nextTop);
  269. return *reinterpret_cast<T *>(&stack.Buffer()[this->nextTop - sizeof(T)]);
  270. }
  271. template<class T, const size_t InitialPageCount>
  272. inline T *ContinuousPageStackOfFixedElements<T, InitialPageCount>::Iterator::operator ->() const
  273. {
  274. return &**this;
  275. }
  276. template<class T, const size_t InitialPageCount>
  277. inline typename ContinuousPageStackOfFixedElements<T, InitialPageCount>::Iterator &ContinuousPageStackOfFixedElements<T, InitialPageCount>::Iterator::operator ++() // pre-increment
  278. {
  279. Assert(*this);
  280. this->nextTop -= sizeof(T);
  281. return *this;
  282. }
  283. template<class T, const size_t InitialPageCount>
  284. inline typename ContinuousPageStackOfFixedElements<T, InitialPageCount>::Iterator ContinuousPageStackOfFixedElements<T, InitialPageCount>::Iterator::operator ++(int) // post-increment
  285. {
  286. Iterator it(*this);
  287. ++*this;
  288. return it;
  289. }
  290. // ----------------------------------
  291. // ContinuousPageStackOfFixedElements
  292. // ----------------------------------
  293. template<class T, const size_t InitialPageCount>
  294. inline ContinuousPageStackOfFixedElements<T, InitialPageCount>::ContinuousPageStackOfFixedElements(
  295. PageAllocator *const pageAllocator,
  296. void (*const outOfMemoryFunc)())
  297. : ContinuousPageStack<InitialPageCount>(pageAllocator, outOfMemoryFunc)
  298. {
  299. }
  300. template<class T, const size_t InitialPageCount>
  301. inline char* ContinuousPageStackOfFixedElements<T, InitialPageCount>::Push()
  302. {
  303. return ContinuousPageStack<InitialPageCount>::Push(sizeof(T));
  304. }
  305. template<class T, const size_t InitialPageCount>
  306. inline T* ContinuousPageStackOfFixedElements<T, InitialPageCount>::Top() const
  307. {
  308. return reinterpret_cast<T*>(ContinuousPageStack<InitialPageCount>::Top(sizeof(T)));
  309. }
  310. template<class T, const size_t InitialPageCount>
  311. inline T* ContinuousPageStackOfFixedElements<T, InitialPageCount>::Pop()
  312. {
  313. return reinterpret_cast<T*>(ContinuousPageStack<InitialPageCount>::Pop(sizeof(T)));
  314. }
  315. template<class T, const size_t InitialPageCount>
  316. inline void ContinuousPageStackOfFixedElements<T, InitialPageCount>::UnPop()
  317. {
  318. return ContinuousPageStack<InitialPageCount>::UnPop(sizeof(T));
  319. }
  320. template<class T, const size_t InitialPageCount>
  321. inline void ContinuousPageStackOfFixedElements<T, InitialPageCount>::PopTo(const size_t position)
  322. {
  323. ContinuousPageStack<InitialPageCount>::PopTo(position);
  324. }
  325. // -----------------------------------------------------------------------------------------------------------------------------
  326. // ContinuousPageStackOfVariableElements definition
  327. // -----------------------------------------------------------------------------------------------------------------------------
  328. // --------
  329. // Iterator
  330. // --------
  331. template<class T, const size_t InitialPageCount>
  332. inline ContinuousPageStackOfVariableElements<T, InitialPageCount>::Iterator::Iterator(
  333. const ContinuousPageStackOfVariableElements &stack)
  334. : ContinuousPageStack<InitialPageCount>::Iterator(stack), topElementSize(stack.topElementSize), stack(stack)
  335. {
  336. }
  337. template<class T, const size_t InitialPageCount>
  338. inline T &ContinuousPageStackOfVariableElements<T, InitialPageCount>::Iterator::operator *() const
  339. {
  340. Assert(*this);
  341. Assert(this->nextTop <= stack.nextTop);
  342. return *reinterpret_cast<T*>(reinterpret_cast<VariableElement *>(&stack.Buffer()[this->nextTop - this->topElementSize])->Data());
  343. }
  344. template<class T, const size_t InitialPageCount>
  345. inline T *ContinuousPageStackOfVariableElements<T, InitialPageCount>::Iterator::operator ->() const
  346. {
  347. return &**this;
  348. }
  349. template<class T, const size_t InitialPageCount>
  350. inline typename ContinuousPageStackOfVariableElements<T, InitialPageCount>::Iterator &ContinuousPageStackOfVariableElements<T, InitialPageCount>::Iterator::operator ++() // pre-increment
  351. {
  352. Assert(*this);
  353. Assert(this->nextTop <= stack.nextTop);
  354. topElementSize = reinterpret_cast<VariableElement *>(&stack.Buffer()[this->nextTop -= this->topElementSize])->PreviousElementSize();
  355. return *this;
  356. }
  357. template<class T, const size_t InitialPageCount>
  358. inline typename ContinuousPageStackOfVariableElements<T, InitialPageCount>::Iterator ContinuousPageStackOfVariableElements<T, InitialPageCount>::Iterator::operator ++(int) // post-increment
  359. {
  360. Iterator it(*this);
  361. ++*this;
  362. return it;
  363. }
  364. // ---------------
  365. // VariableElement
  366. // ---------------
  367. template<class T, const size_t InitialPageCount>
  368. inline ContinuousPageStackOfVariableElements<T, InitialPageCount>::VariableElement::VariableElement(
  369. const size_t previousElementSize)
  370. : previousElementSize(previousElementSize)
  371. {
  372. }
  373. template<class T, const size_t InitialPageCount>
  374. template<class ActualT>
  375. inline size_t ContinuousPageStackOfVariableElements<T, InitialPageCount>::VariableElement::Size()
  376. {
  377. return sizeof(VariableElement) + sizeof(ActualT);
  378. }
  379. template<class T, const size_t InitialPageCount>
  380. inline size_t ContinuousPageStackOfVariableElements<T, InitialPageCount>::VariableElement::PreviousElementSize() const
  381. {
  382. return previousElementSize;
  383. }
  384. template<class T, const size_t InitialPageCount>
  385. inline char* ContinuousPageStackOfVariableElements<T, InitialPageCount>::VariableElement::Data()
  386. {
  387. return data;
  388. }
  389. // -------------------------------------
  390. // ContinuousPageStackOfVariableElements
  391. // -------------------------------------
  392. template<class T, const size_t InitialPageCount>
  393. inline ContinuousPageStackOfVariableElements<T, InitialPageCount>::ContinuousPageStackOfVariableElements(
  394. PageAllocator *const pageAllocator,
  395. void (*const outOfMemoryFunc)())
  396. : ContinuousPageStack<InitialPageCount>(pageAllocator, outOfMemoryFunc)
  397. {
  398. }
  399. template<class T, const size_t InitialPageCount>
  400. template<class ActualT>
  401. inline char* ContinuousPageStackOfVariableElements<T, InitialPageCount>::Push()
  402. {
  403. TemplateParameter::SameOrDerivedFrom<ActualT, T>(); // ActualT must be the same type as, or a type derived from, T
  404. VariableElement *const element =
  405. new(ContinuousPageStack<InitialPageCount>::Push(VariableElement::template
  406. Size<ActualT>())) VariableElement(topElementSize);
  407. topElementSize = VariableElement::template Size<ActualT>();
  408. return element->Data();
  409. }
  410. template<class T, const size_t InitialPageCount>
  411. inline T* ContinuousPageStackOfVariableElements<T, InitialPageCount>::Top() const
  412. {
  413. VariableElement* const element = reinterpret_cast<VariableElement*>(ContinuousPageStack<InitialPageCount>::Top(topElementSize));
  414. return element == 0 ? 0 : reinterpret_cast<T*>(element->Data());
  415. }
  416. template<class T, const size_t InitialPageCount>
  417. inline T* ContinuousPageStackOfVariableElements<T, InitialPageCount>::Pop()
  418. {
  419. VariableElement *const element = reinterpret_cast<VariableElement*>(ContinuousPageStack<InitialPageCount>::Pop(topElementSize));
  420. if (element == 0)
  421. return 0;
  422. else
  423. {
  424. topElementSize = element->PreviousElementSize();
  425. return reinterpret_cast<T*>(element->Data());
  426. }
  427. }
  428. template<class T, const size_t InitialPageCount>
  429. template<class ActualT>
  430. inline void ContinuousPageStackOfVariableElements<T, InitialPageCount>::UnPop()
  431. {
  432. TemplateParameter::SameOrDerivedFrom<ActualT, T>(); // ActualT must be the same type as, or a type derived from, T
  433. ContinuousPageStack<InitialPageCount>::UnPop(VariableElement::template
  434. Size<ActualT>());
  435. Assert(reinterpret_cast<VariableElement*>(ContinuousPageStack<InitialPageCount>::Top(VariableElement::template
  436. Size<ActualT>()))->PreviousElementSize() == topElementSize);
  437. topElementSize = VariableElement::template Size<ActualT>();
  438. }
  439. template<class T, const size_t InitialPageCount>
  440. inline void ContinuousPageStackOfVariableElements<T, InitialPageCount>::PopTo(const size_t position)
  441. {
  442. Assert(position <= this->nextTop);
  443. if(position != this->nextTop)
  444. {
  445. Assert(position + sizeof(VariableElement) <= this->nextTop);
  446. topElementSize = reinterpret_cast<VariableElement *>(&this->Buffer()[position])->PreviousElementSize();
  447. }
  448. ContinuousPageStack<InitialPageCount>::PopTo(position);
  449. }