Vector.h 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. #ifndef VECTOR_H
  2. #define VECTOR_H
  3. #include <cassert>
  4. #include <new>
  5. #include <utility>
  6. template<typename T>
  7. class Vector {
  8. T* data;
  9. int capacity;
  10. int elements;
  11. public:
  12. Vector() : data(nullptr), capacity(0), elements(0) {
  13. }
  14. explicit Vector(int n, const T& t) : Vector() {
  15. for(int i = 0; i < n; i++) {
  16. push_back(t);
  17. }
  18. }
  19. explicit Vector(int n) : Vector() {
  20. // calling Vector(n, T()) would break structures which can be
  21. // default constructed but not copied e.g. unique pointers elements
  22. for(int i = 0; i < n; i++) {
  23. push_back(T());
  24. }
  25. }
  26. ~Vector() {
  27. // placement new needs explicit destructor calling
  28. for(int i = 0; i < elements; i++) {
  29. data[i].~T();
  30. }
  31. // casting this pointer not back to its origin type yields a crash
  32. delete[] reinterpret_cast<char*>(data);
  33. }
  34. // allocate new storage for copies
  35. Vector(const Vector& other)
  36. : data(allocate(other.capacity)), capacity(other.capacity),
  37. elements(other.elements) {
  38. // copy data into new storage
  39. for(int i = 0; i < elements; i++) {
  40. new(data + i) T(other.data[i]);
  41. }
  42. }
  43. // this handles copy and move assigment
  44. // copy: replace current resources with other made by the copy constructor
  45. // move: replace current resources with other made by the move constructor
  46. // other gets the old data and is destroyed by the destructor after going
  47. // out of scope
  48. Vector& operator=(Vector other) {
  49. swap(*this, other);
  50. return *this;
  51. }
  52. // construct a default vector so the other vector gets valid values from the
  53. // swap
  54. Vector(Vector&& other) : Vector() {
  55. swap(*this, other);
  56. }
  57. void reserve(int size) {
  58. if(size <= capacity) {
  59. return;
  60. }
  61. Vector v;
  62. v.capacity = size;
  63. v.data = allocate(size);
  64. for(int i = 0; i < elements; i++) {
  65. v.push_back(std::move(data[i]));
  66. }
  67. swap(*this, v);
  68. }
  69. void resize(int size, const T& t) {
  70. // elements will be equal to size after this call but not the capacity
  71. if(size > elements) {
  72. // fill until the given size is reached
  73. for(int i = elements; i < size; i++) {
  74. push_back(t);
  75. }
  76. } else if(size < elements) {
  77. // remove objects until the size matches
  78. for(int i = size; i < elements; i++) {
  79. data[i].~T();
  80. }
  81. elements = size;
  82. }
  83. }
  84. void resize(int size) {
  85. // calling resize(size, T()); would break structures which can be
  86. // default constructed but not copied e.g. unique pointers elements
  87. // will be equal to size after this call but not the capacity
  88. if(size > elements) {
  89. // fill until the given size is reached
  90. for(int i = elements; i < size; i++) {
  91. push_back(T());
  92. }
  93. } else if(size < elements) {
  94. // remove objects until the size matches
  95. for(int i = size; i < elements; i++) {
  96. data[i].~T();
  97. }
  98. elements = size;
  99. }
  100. }
  101. void push_back(const T& t) {
  102. ensureCapacity();
  103. new(data + elements++) T(t);
  104. }
  105. void push_back(T&& t) {
  106. ensureCapacity();
  107. // && would be lost without std::move
  108. new(data + elements++) T(std::move(t));
  109. }
  110. T& operator[](int index) {
  111. return data[index];
  112. }
  113. const T& operator[](int index) const {
  114. return data[index];
  115. }
  116. T& at(int index) {
  117. // std states "at" is [] with range check
  118. assert(index >= 0 && index < elements);
  119. return (*this)[index];
  120. }
  121. const T& at(int index) const {
  122. // std states "at" is [] with range check
  123. assert(index >= 0 && index < elements);
  124. return (*this)[index];
  125. }
  126. int size() const {
  127. return elements;
  128. }
  129. T* begin() {
  130. return data;
  131. }
  132. T* end() {
  133. return data + elements;
  134. }
  135. const T* begin() const {
  136. return data;
  137. }
  138. const T* end() const {
  139. return data + elements;
  140. }
  141. void erase(T* from, T* to) {
  142. T* remove = from;
  143. T* move = to;
  144. T* stop = end();
  145. // fill the hole by moving following objects as long as possible
  146. while(move != stop) {
  147. *remove = std::move(*move);
  148. remove++;
  149. move++;
  150. }
  151. // remove left over objects
  152. while(remove != stop) {
  153. remove->~T();
  154. remove++;
  155. elements--;
  156. }
  157. }
  158. void erase(T* start) {
  159. erase(start, start + 1);
  160. }
  161. T* as_array() {
  162. return begin();
  163. }
  164. const T* as_array() const {
  165. return begin();
  166. }
  167. void erase_by_swap(int index) {
  168. elements--;
  169. if(index != elements) {
  170. data[index] = std::move(data[elements]);
  171. }
  172. data[elements].~T();
  173. }
  174. int length() const {
  175. return capacity;
  176. }
  177. private:
  178. static T* allocate(int length) {
  179. return reinterpret_cast<T*>(new char[sizeof(T) * length]);
  180. }
  181. static void swap(Vector& a, Vector& b) {
  182. std::swap(a.data, b.data);
  183. std::swap(a.capacity, b.capacity);
  184. std::swap(a.elements, b.elements);
  185. }
  186. void ensureCapacity() {
  187. if(elements >= capacity) {
  188. // doubling the size amortizes costs
  189. reserve(capacity == 0 ? 1 : capacity * 2);
  190. }
  191. }
  192. };
  193. #endif