Main.cpp 8.2 KB

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