Main.cpp 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345
  1. #include <cassert>
  2. #include <iostream>
  3. #include <vector>
  4. struct A {
  5. static int instances;
  6. int a;
  7. A(int a) : a(a) {
  8. // std::cout << "construct A " << a << "\n";
  9. instances += a;
  10. }
  11. A(const A& other) : a(other.a) {
  12. // std::cout << "copy construct A " << a << "\n";
  13. instances += a;
  14. }
  15. A(A&& other) : a(other.a) {
  16. // std::cout << "move construct A " << a << "\n";
  17. instances += a;
  18. }
  19. A& operator=(const A& other) {
  20. instances -= a;
  21. a = other.a;
  22. instances += a;
  23. // std::cout << "copy assignment A " << a << "\n";
  24. return *this;
  25. }
  26. A& operator=(A&& other) {
  27. instances -= a;
  28. a = other.a;
  29. instances += a;
  30. // std::cout << "move assignment A " << a << "\n";
  31. return *this;
  32. }
  33. ~A() {
  34. // std::cout << "destruct A " << a << "\n";
  35. instances -= a;
  36. }
  37. };
  38. int A::instances = 0;
  39. template<typename T>
  40. class Vector {
  41. T* data;
  42. int capacity;
  43. int elements;
  44. public:
  45. Vector() : data(nullptr), capacity(0), elements(0) {
  46. }
  47. ~Vector() {
  48. // placement new needs explicit destructor calling
  49. for(int i = 0; i < elements; i++) {
  50. data[i].~T();
  51. }
  52. delete[] reinterpret_cast<char*>(data);
  53. }
  54. // allocate new storage for copies
  55. Vector(const Vector& other)
  56. : data(allocate(other.capacity)), capacity(other.capacity),
  57. elements(other.elements) {
  58. // copy data into new storage
  59. for(int i = 0; i < elements; i++) {
  60. new(data + i) T(other.data[i]);
  61. }
  62. }
  63. // this handles copy and move assigment
  64. // copy: replace current resources with other made by the copy constructor
  65. // move: replace current resources with other made by the move constructor
  66. // other gets the old data and is destroyed by the destructor after going
  67. // out of scope
  68. Vector& operator=(Vector other) {
  69. swap(*this, other);
  70. return *this;
  71. }
  72. // construct a default vector so the other vector gets valid values from the
  73. // swap
  74. Vector(Vector&& other) : Vector() {
  75. swap(*this, other);
  76. }
  77. void reserve(int size) {
  78. if(size <= capacity) {
  79. return;
  80. }
  81. Vector v;
  82. v.capacity = size;
  83. v.data = allocate(size);
  84. for(int i = 0; i < elements; i++) {
  85. v.push_back(std::move(data[i]));
  86. }
  87. swap(*this, v);
  88. }
  89. void resize(int size, const T& t) {
  90. // elements will be equal to size after this call but not the capacity
  91. if(size > elements) {
  92. // fill until the given size is reached
  93. for(int i = elements; i < size; i++) {
  94. push_back(t);
  95. }
  96. } else if(size < elements) {
  97. // remove objects until the size matches
  98. for(int i = size; i < elements; i++) {
  99. data[i].~T();
  100. }
  101. elements = size;
  102. }
  103. }
  104. void resize(int size) {
  105. resize(size, T());
  106. }
  107. void push_back(const T& t) {
  108. ensureCapacity();
  109. new(data + elements++) T(t);
  110. }
  111. void push_back(T&& t) {
  112. ensureCapacity();
  113. // && would be lost without std::move
  114. new(data + elements++) T(std::move(t));
  115. }
  116. T& operator[](int index) {
  117. return data[index];
  118. }
  119. const T& operator[](int index) const {
  120. return data[index];
  121. }
  122. T& at(int index) {
  123. // std states "at" is [] with range check
  124. assert(index >= 0 && index < elements);
  125. return (*this)[index];
  126. }
  127. const T& at(int index) const {
  128. // std states "at" is [] with range check
  129. assert(index >= 0 && index < elements);
  130. return (*this)[index];
  131. }
  132. int size() const {
  133. return elements;
  134. }
  135. T* begin() {
  136. return data;
  137. }
  138. T* end() {
  139. return data + elements;
  140. }
  141. const T* begin() const {
  142. return data;
  143. }
  144. const T* end() const {
  145. return data + elements;
  146. }
  147. void erase(T* from, T* to) {
  148. T* remove = from;
  149. T* move = to;
  150. T* stop = end();
  151. // fill the hole by moving following objects as long as possible
  152. while(move != stop) {
  153. *remove = std::move(*move);
  154. remove++;
  155. move++;
  156. }
  157. // remove left over objects
  158. while(remove != stop) {
  159. remove->~T();
  160. remove++;
  161. elements--;
  162. }
  163. }
  164. void erase(T* start) {
  165. erase(start, start + 1);
  166. }
  167. T* as_array() {
  168. return begin();
  169. }
  170. const T* as_array() const {
  171. return begin();
  172. }
  173. void erase_by_swap(int index) {
  174. elements--;
  175. if(index != elements) {
  176. data[index] = std::move(data[elements]);
  177. }
  178. data[elements].~T();
  179. }
  180. private:
  181. static T* allocate(int length) {
  182. return reinterpret_cast<T*>(new char[sizeof(T) * length]);
  183. }
  184. static void swap(Vector& a, Vector& b) {
  185. std::swap(a.data, b.data);
  186. std::swap(a.capacity, b.capacity);
  187. std::swap(a.elements, b.elements);
  188. }
  189. void ensureCapacity() {
  190. if(elements >= capacity) {
  191. // doubling the size amortizes costs
  192. reserve(capacity == 0 ? 1 : capacity * 2);
  193. }
  194. }
  195. };
  196. void printError(int number) {
  197. std::cout << "\033[0;31mError " << number << "\033[0m\n";
  198. }
  199. template<typename V>
  200. void test() {
  201. {
  202. const int elements = 2;
  203. V v;
  204. for(int i = 0; i < elements; i++) {
  205. v.push_back(A(i));
  206. }
  207. const V& cv = v;
  208. for(int i = 0; i < elements; i++) {
  209. if(v[i].a != i || cv[i].a != i || v.at(i).a != i ||
  210. cv.at(i).a != i) {
  211. printError(1);
  212. }
  213. }
  214. if(v.size() != elements) {
  215. printError(2);
  216. }
  217. }
  218. {
  219. V v1;
  220. v1.push_back(A(10));
  221. V v2 = v1;
  222. V v3;
  223. v3.push_back(A(20));
  224. v3 = v1;
  225. if(v1[0].a != 10 || v2[0].a != 10 || v3[0].a != 10) {
  226. printError(3);
  227. }
  228. V v4 = std::move(v1);
  229. V v5(std::move(v2));
  230. V v6;
  231. v6 = std::move(v3);
  232. if(v1.size() != 0 || v2.size() != 0 || v3.size() != 0 ||
  233. v4.size() != 1 || v5.size() != 1 || v6.size() != 1) {
  234. printError(4);
  235. }
  236. }
  237. {
  238. V v;
  239. v.resize(1, A(8));
  240. v.resize(3, A(9));
  241. if(v.size() != 3 || v[0].a != 8 || v[1].a != 9 || v[2].a != 9) {
  242. printError(5);
  243. }
  244. v.resize(1, A(10));
  245. if(v.size() != 1 || v[0].a != 8) {
  246. printError(6);
  247. }
  248. }
  249. {
  250. std::vector<A> v1;
  251. V v2;
  252. for(int i = 0; i < 200; i++) {
  253. v1.push_back(A(i));
  254. v2.push_back(A(i));
  255. }
  256. v1.erase(v1.begin());
  257. v1.erase(v1.begin() + 4, v1.begin() + 8);
  258. v1.erase(v1.begin() + 30, v1.begin() + 56);
  259. v2.erase(v2.begin());
  260. v2.erase(v2.begin() + 4, v2.begin() + 8);
  261. v2.erase(v2.begin() + 30, v2.begin() + 56);
  262. if(static_cast<int>(v1.size()) != static_cast<int>(v2.size())) {
  263. printError(100);
  264. } else {
  265. for(unsigned int i = 0; i < v1.size(); i++) {
  266. if(v1[i].a != v2[i].a) {
  267. printError(200);
  268. }
  269. }
  270. }
  271. }
  272. if(A::instances != 0) {
  273. std::cout << "object counter is not 0: " << A::instances << "\n";
  274. }
  275. }
  276. void test() {
  277. {
  278. Vector<A> v;
  279. v.push_back(1);
  280. v.push_back(2);
  281. v.push_back(3);
  282. v.erase_by_swap(1);
  283. if(v.size() != 2 || v[0].a != 1 || v[1].a != 3) {
  284. printError(9);
  285. }
  286. v.erase_by_swap(1);
  287. if(v.size() != 1 || v[0].a != 1) {
  288. printError(10);
  289. }
  290. v.erase_by_swap(0);
  291. if(v.size() != 0) {
  292. printError(11);
  293. }
  294. }
  295. if(A::instances != 0) {
  296. std::cout << "object counter is not 0: " << A::instances << "\n";
  297. }
  298. }
  299. int main() {
  300. test<Vector<A>>();
  301. test();
  302. std::cout << "--------------------------\n";
  303. test<std::vector<A>>();
  304. }