|
@@ -0,0 +1,352 @@
|
|
|
|
+#include <cassert>
|
|
|
|
+#include <iostream>
|
|
|
|
+#include <vector>
|
|
|
|
+
|
|
|
|
+struct A {
|
|
|
|
+ static int instances;
|
|
|
|
+ int a;
|
|
|
|
+ A(int a) : a(a) {
|
|
|
|
+
|
|
|
|
+ instances += a;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ A(const A& other) : a(other.a) {
|
|
|
|
+
|
|
|
|
+ instances += a;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ A(A&& other) : a(other.a) {
|
|
|
|
+
|
|
|
|
+ instances += a;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ A& operator=(const A& other) {
|
|
|
|
+ instances -= a;
|
|
|
|
+ a = other.a;
|
|
|
|
+ instances += a;
|
|
|
|
+
|
|
|
|
+ return *this;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ A& operator=(A&& other) {
|
|
|
|
+ instances -= a;
|
|
|
|
+ a = other.a;
|
|
|
|
+ instances += a;
|
|
|
|
+
|
|
|
|
+ return *this;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ ~A() {
|
|
|
|
+
|
|
|
|
+ instances -= a;
|
|
|
|
+ }
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+int A::instances = 0;
|
|
|
|
+
|
|
|
|
+template<typename T>
|
|
|
|
+class Vector {
|
|
|
|
+ char* data;
|
|
|
|
+ int capacity;
|
|
|
|
+ int elements;
|
|
|
|
+
|
|
|
|
+public:
|
|
|
|
+ Vector() : data(nullptr), capacity(0), elements(0) {
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ ~Vector() {
|
|
|
|
+ destroy();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ Vector(const Vector& other) : data(allocate(other.capacity)), capacity(other.capacity), elements(other.elements) {
|
|
|
|
+
|
|
|
|
+ other.copyTo(data);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ Vector& operator=(const Vector& other) {
|
|
|
|
+ if(this != &other) {
|
|
|
|
+
|
|
|
|
+ destroy();
|
|
|
|
+
|
|
|
|
+ data = allocate(other.capacity);
|
|
|
|
+ capacity = other.capacity;
|
|
|
|
+ elements = other.elements;
|
|
|
|
+
|
|
|
|
+ other.copyTo(data);
|
|
|
|
+ }
|
|
|
|
+ return *this;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ Vector(Vector&& other) : data(other.data), capacity(other.capacity), elements(other.elements) {
|
|
|
|
+
|
|
|
|
+ other.reset();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ Vector& operator=(Vector&& other) {
|
|
|
|
+ if(this != &other) {
|
|
|
|
+
|
|
|
|
+ destroy();
|
|
|
|
+
|
|
|
|
+ data = other.data;
|
|
|
|
+ capacity = other.capacity;
|
|
|
|
+ elements = other.elements;
|
|
|
|
+
|
|
|
|
+ other.reset();
|
|
|
|
+ }
|
|
|
|
+ return *this;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ void reserve(int size) {
|
|
|
|
+ if(size <= capacity) {
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ capacity = size;
|
|
|
|
+ char* newData = allocate(capacity);
|
|
|
|
+
|
|
|
|
+ if(data == nullptr) {
|
|
|
|
+ data = newData;
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ moveTo(newData);
|
|
|
|
+ destroy();
|
|
|
|
+ data = newData;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ void resize(int size, const T& t) {
|
|
|
|
+ if(size > elements) {
|
|
|
|
+
|
|
|
|
+ char* newData = allocate(size);
|
|
|
|
+ moveTo(newData);
|
|
|
|
+ destroy();
|
|
|
|
+ data = newData;
|
|
|
|
+ capacity = size;
|
|
|
|
+
|
|
|
|
+ for(int i = elements; i < size; i++) {
|
|
|
|
+ push_back(t);
|
|
|
|
+ }
|
|
|
|
+ } else if(size < elements) {
|
|
|
|
+
|
|
|
|
+ for(int i = size; i < elements; i++) {
|
|
|
|
+ (*pointer(data, i)).~T();
|
|
|
|
+ }
|
|
|
|
+ elements = size;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ void resize(int size) {
|
|
|
|
+ resize(size, T());
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ void push_back(const T& t) {
|
|
|
|
+ ensureCapacity();
|
|
|
|
+ new(pointer(data, elements++)) T(t);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ void push_back(T&& t) {
|
|
|
|
+ ensureCapacity();
|
|
|
|
+
|
|
|
|
+ new(pointer(data, elements++)) T(std::move(t));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ T& operator[](int index) {
|
|
|
|
+ return *pointer(data, index);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ const T& operator[](int index) const {
|
|
|
|
+ return *pointer(data, index);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ T& at(int index) {
|
|
|
|
+
|
|
|
|
+ assert(index >= 0 && index < elements);
|
|
|
|
+ return (*this)[index];
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ const T& at(int index) const {
|
|
|
|
+
|
|
|
|
+ assert(index >= 0 && index < elements);
|
|
|
|
+ return (*this)[index];
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ int size() const {
|
|
|
|
+ return elements;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ T* begin() {
|
|
|
|
+ return pointer(data, 0);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ T* end() {
|
|
|
|
+ return pointer(data, elements);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ const T* begin() const {
|
|
|
|
+ return pointer(data, 0);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ const T* end() const {
|
|
|
|
+ return pointer(data, elements);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ void erase(T* from, T* to) {
|
|
|
|
+ T* remove = from;
|
|
|
|
+ T* move = to;
|
|
|
|
+ T* stop = end();
|
|
|
|
+
|
|
|
|
+ while(remove != to && move != stop) {
|
|
|
|
+ *remove = std::move(*move);
|
|
|
|
+ remove++;
|
|
|
|
+ move++;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ while(remove != stop) {
|
|
|
|
+ remove->~T();
|
|
|
|
+ remove++;
|
|
|
|
+ elements--;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ void erase(T* start) {
|
|
|
|
+ erase(start, start + 1);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ T* as_array() {
|
|
|
|
+ return begin();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ const T* as_array() const {
|
|
|
|
+ return begin();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+private:
|
|
|
|
+ static char* allocate(int length) {
|
|
|
|
+ return new char[sizeof(T) * length];
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ static T* pointer(char* data, int index) {
|
|
|
|
+ return reinterpret_cast<T*>(data) + index;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ static const T* pointer(const char* data, int index) {
|
|
|
|
+ return reinterpret_cast<const T*>(data) + index;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ void ensureCapacity() {
|
|
|
|
+ if(elements >= capacity) {
|
|
|
|
+
|
|
|
|
+ reserve(capacity == 0 ? 1 : capacity * 2);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ void copyTo(char* newData) const {
|
|
|
|
+ for(int i = 0; i < elements; i++) {
|
|
|
|
+ new(pointer(newData, i)) T(*pointer(data, i));
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ void moveTo(char* newData) {
|
|
|
|
+ for(int i = 0; i < elements; i++) {
|
|
|
|
+ new(pointer(newData, i)) T(std::move(*pointer(data, i)));
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ void destroy() {
|
|
|
|
+ callDestructors();
|
|
|
|
+ delete[] data;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ void reset() {
|
|
|
|
+ data = nullptr;
|
|
|
|
+ capacity = 0;
|
|
|
|
+ elements = 0;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ void callDestructors() {
|
|
|
|
+
|
|
|
|
+ for(int i = 0; i < elements; i++) {
|
|
|
|
+ (*pointer(data, i)).~T();
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+void printError(int number) {
|
|
|
|
+ std::cout << "\033[0;31mError " << number << "\033[0m\n";
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+template<typename V>
|
|
|
|
+void test() {
|
|
|
|
+ {
|
|
|
|
+ const int elements = 2;
|
|
|
|
+ V v;
|
|
|
|
+ for(int i = 0; i < elements; i++) {
|
|
|
|
+ v.push_back(A(i));
|
|
|
|
+ }
|
|
|
|
+ const V& cv = v;
|
|
|
|
+ for(int i = 0; i < elements; i++) {
|
|
|
|
+ if(v[i].a != i || cv[i].a != i || v.at(i).a != i || cv.at(i).a != i) {
|
|
|
|
+ printError(1);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ if(v.size() != elements) {
|
|
|
|
+ printError(2);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ {
|
|
|
|
+ V v1;
|
|
|
|
+ v1.push_back(A(10));
|
|
|
|
+ V v2 = v1;
|
|
|
|
+ V v3;
|
|
|
|
+ v3.push_back(A(20));
|
|
|
|
+ v3 = v1;
|
|
|
|
+ if(v1[0].a != 10 || v2[0].a != 10 || v3[0].a != 10) {
|
|
|
|
+ printError(3);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ V v4 = std::move(v1);
|
|
|
|
+ V v5(std::move(v2));
|
|
|
|
+ V v6;
|
|
|
|
+ v6 = std::move(v3);
|
|
|
|
+
|
|
|
|
+ if(v1.size() != 0 || v2.size() != 0 || v3.size() != 0 || v4.size() != 1 || v5.size() != 1 || v6.size() != 1) {
|
|
|
|
+ printError(4);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ {
|
|
|
|
+ V v;
|
|
|
|
+ v.resize(1, A(8));
|
|
|
|
+ v.resize(3, A(9));
|
|
|
|
+ if(v.size() != 3 || v[0].a != 8 || v[1].a != 9 || v[2].a != 9) {
|
|
|
|
+ printError(5);
|
|
|
|
+ }
|
|
|
|
+ v.resize(1, A(10));
|
|
|
|
+ if(v.size() != 1 || v[0].a != 8) {
|
|
|
|
+ printError(6);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ {
|
|
|
|
+ V v;
|
|
|
|
+ v.push_back(A(20));
|
|
|
|
+ v.push_back(A(21));
|
|
|
|
+ v.push_back(A(22));
|
|
|
|
+ v.erase(v.begin() + 1);
|
|
|
|
+ if(v.size() != 2 || v[0].a != 20 || v[1].a != 22) {
|
|
|
|
+ printError(7);
|
|
|
|
+ }
|
|
|
|
+ v.erase(v.begin(), v.end());
|
|
|
|
+ if(v.size() != 0) {
|
|
|
|
+ printError(8);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ if(A::instances != 0) {
|
|
|
|
+ std::cout << "object counter is not 0: " << A::instances << "\n";
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+int main() {
|
|
|
|
+ test<Vector<A>>();
|
|
|
|
+ std::cout << "--------------------------\n";
|
|
|
|
+ test<std::vector<A>>();
|
|
|
|
+}
|