Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

209 lines
4.4 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //
  7. //=============================================================================//
  8. /*
  9. *
  10. * Copyright (c) 1998-9
  11. * Dr John Maddock
  12. *
  13. * Permission to use, copy, modify, distribute and sell this software
  14. * and its documentation for any purpose is hereby granted without fee,
  15. * provided that the above copyright notice appear in all copies and
  16. * that both that copyright notice and this permission notice appear
  17. * in supporting documentation. Dr John Maddock makes no representations
  18. * about the suitability of this software for any purpose.
  19. * It is provided "as is" without express or implied warranty.
  20. *
  21. */
  22. /*
  23. * FILE jstack.h
  24. * VERSION 2.12
  25. */
  26. #ifndef __JSTACH_H
  27. #define __JSTACK_H
  28. #ifndef JM_CFG_H
  29. #include <jm/jm_cfg.h>
  30. #endif
  31. JM_NAMESPACE(__JM)
  32. //
  33. // class jstack
  34. // simplified stack optimised for push/peek/pop
  35. // operations, we could use std::stack<std::vector<T>> instead...
  36. //
  37. template <class T, class Allocator JM_DEF_ALLOC_PARAM(T) >
  38. class jstack
  39. {
  40. private:
  41. typedef JM_MAYBE_TYPENAME REBIND_TYPE(unsigned char, Allocator) alloc_type;
  42. typedef typename REBIND_TYPE(T, Allocator)::size_type size_type;
  43. struct node
  44. {
  45. node* next;
  46. T* start; // first item
  47. T* end; // last item
  48. T* last; // end of storage
  49. };
  50. //
  51. // empty base member optimisation:
  52. struct data : public alloc_type
  53. {
  54. unsigned char buf[sizeof(T)*16];
  55. data(const Allocator& a) : alloc_type(a){}
  56. };
  57. data alloc_inst;
  58. mutable node* stack;
  59. mutable node* unused;
  60. node base;
  61. size_type block_size;
  62. void RE_CALL pop_aux()const;
  63. void RE_CALL push_aux();
  64. public:
  65. jstack(size_type n = 64, const Allocator& a = Allocator());
  66. ~jstack();
  67. node* RE_CALL get_node()
  68. {
  69. node* new_stack = (node*)alloc_inst.allocate(sizeof(node) + sizeof(T) * block_size);
  70. new_stack->last = (T*)(new_stack+1);
  71. new_stack->start = new_stack->end = new_stack->last + block_size;
  72. new_stack->next = 0;
  73. return new_stack;
  74. }
  75. bool RE_CALL empty()
  76. {
  77. return (stack->start == stack->end) && (stack->next == 0);
  78. }
  79. bool RE_CALL good()
  80. {
  81. return (stack->start != stack->end) || (stack->next != 0);
  82. }
  83. T& RE_CALL peek()
  84. {
  85. if(stack->start == stack->end)
  86. pop_aux();
  87. return *stack->end;
  88. }
  89. const T& RE_CALL peek()const
  90. {
  91. if(stack->start == stack->end)
  92. pop_aux();
  93. return *stack->end;
  94. }
  95. void RE_CALL pop()
  96. {
  97. if(stack->start == stack->end)
  98. pop_aux();
  99. jm_destroy(stack->end);
  100. ++(stack->end);
  101. }
  102. void RE_CALL pop(T& t)
  103. {
  104. if(stack->start == stack->end)
  105. pop_aux();
  106. t = *stack->end;
  107. jm_destroy(stack->end);
  108. ++(stack->end);
  109. }
  110. void RE_CALL push(const T& t)
  111. {
  112. if(stack->end == stack->last)
  113. push_aux();
  114. --(stack->end);
  115. jm_construct(stack->end, t);
  116. }
  117. };
  118. template <class T, class Allocator>
  119. jstack<T, Allocator>::jstack(size_type n, const Allocator& a)
  120. : alloc_inst(a)
  121. {
  122. unused = 0;
  123. block_size = n;
  124. stack = &base;
  125. base.last = (T*)alloc_inst.buf;
  126. base.end = base.start = base.last + 16;
  127. base.next = 0;
  128. }
  129. template <class T, class Allocator>
  130. void RE_CALL jstack<T, Allocator>::push_aux()
  131. {
  132. // make sure we have spare space on TOS:
  133. register node* new_node;
  134. if(unused)
  135. {
  136. new_node = unused;
  137. unused = new_node->next;
  138. new_node->next = stack;
  139. stack = new_node;
  140. }
  141. else
  142. {
  143. new_node = get_node();
  144. new_node->next = stack;
  145. stack = new_node;
  146. }
  147. }
  148. template <class T, class Allocator>
  149. void RE_CALL jstack<T, Allocator>::pop_aux()const
  150. {
  151. // make sure that we have a valid item
  152. // on TOS:
  153. jm_assert(stack->next);
  154. register node* p = stack;
  155. stack = p->next;
  156. p->next = unused;
  157. unused = p;
  158. }
  159. template <class T, class Allocator>
  160. jstack<T, Allocator>::~jstack()
  161. {
  162. node* condemned;
  163. while(good())
  164. pop();
  165. while(unused)
  166. {
  167. condemned = unused;
  168. unused = unused->next;
  169. alloc_inst.deallocate((unsigned char*)condemned, sizeof(node) + sizeof(T) * block_size);
  170. }
  171. while(stack != &base)
  172. {
  173. condemned = stack;
  174. stack = stack->next;
  175. alloc_inst.deallocate((unsigned char*)condemned, sizeof(node) + sizeof(T) * block_size);
  176. }
  177. }
  178. JM_END_NAMESPACE
  179. #endif