diff --git a/week06/main b/week06/main deleted file mode 100755 index 0be4fb1..0000000 Binary files a/week06/main and /dev/null differ diff --git a/week06/main.cpp b/week06/main.cpp index eae8dbe..cd84904 100644 --- a/week06/main.cpp +++ b/week06/main.cpp @@ -1,188 +1,289 @@ #include #include +#include template class Grid; -/* Specialization for 1-dim array */ -template -class Grid +template // Todo operator skobochki +class Grid { public: + static_assert(Dimension > 0, "Zero-dimensional array"); using value_type = T; using size_type = unsigned; private: - T *data; + Grid *m_subgrids; size_type dim_size; + /** Allocating a buffer of a specific size for subgrids of inferior dimensions */ + void mem_allocate(size_type size) + { + m_subgrids = static_cast *>(::operator new(sizeof(Grid) * size)); + } + + /** Deleting the buffer: firstly recursively remove objects placed into the buffer via + * placement news (by manually calling destructors), then freeing the buffer itself. */ + void mem_free() + { + for (size_type i = 0; i < dim_size; i++) + { + (m_subgrids + i)->~Grid(); + } + + ::operator delete(m_subgrids); + } + public: - Grid(T &&value) + template 0), bool> = true> + Grid(const First first, const Rest... rest) : dim_size{(size_type)first} { - data = new T[1]; - dim_size = 1; - data[0] = value; + mem_allocate(dim_size); + + for (size_type i = 0; i < first; i++) + { + new (m_subgrids + i) Grid(rest...); + } } - Grid(size_type size, T const &fill_value) : dim_size{size} + /** Copy constructor (does not mutate the argument as may be seen from the signature) */ + Grid(Grid const &other) { - data = new T[size]; - for (size_type i = 0; i < size; i++) + dim_size = other.dim_size; + mem_allocate(dim_size); + + for (size_type i = 0; i < dim_size; i++) { - data[i] = fill_value; + m_subgrids[i] = Grid(other.m_subgrids[i]); } } - // Copy constructor - Grid(Grid const &other) + /** Move constructor (possibly takes rvalue as an argument) */ + Grid(Grid &&other) { - size_type other_size = other.dim_size; - data = new T[other_size]; - dim_size = other_size; - for (size_type i = 0; i < other_size; i++) + dim_size = other.dim_size; + mem_allocate(dim_size); + + for (size_type i = 0; i < dim_size; i++) { - data[i] = other.data[i]; + std::swap(m_subgrids[i], other.m_subgrids[i]); } } - const T &operator[](size_type rhs) + /** Copy assignment */ + Grid &operator=(const Grid &rhs) + { + // Self-assignment check + if (this == &rhs) + { + return *this; + } + // Reallocating the buffer if only dim-sizes do not correspond + if (this->dim_size != rhs.dim_size) + { + this->mem_free(); + this->dim_size = rhs.dim_size; + this->mem_allocate(this->dim_size); + } + // Utilizing copy-construction [recursively] + for (size_type i = 0; i < this->dim_size; i++) + { + new (m_subgrids + i) Grid(rhs.m_subgrids[i]); + } + return *this; + } + + /** Move assignment */ + Grid &operator=(Grid &&rhs) + { + // Self-assignment check + if (this == &rhs) + return *this; + // Reallocating the buffer if only dim-sizes do not correspond + if (this->dim_size != rhs.dim_size) + { + this->mem_free(); + this->dim_size = rhs.dim_size; + this->mem_allocate(this->dim_size); + } + // Merely swapping the contents + std::swap(this->m_subgrids, rhs.m_subgrids); + return *this; + } + + const Grid &operator[](size_type rhs) const { if ((rhs < 0) || (rhs >= dim_size)) throw std::out_of_range("Out of bounds"); - return data[rhs]; + return m_subgrids[rhs]; + } + + Grid &operator[](size_type rhs) + { + if ((rhs < 0) || (rhs >= dim_size)) + throw std::out_of_range("Out of bounds"); + return m_subgrids[rhs]; + } + + /** Template for functor op.: returning one of recursively obtained subgrids */ + template + typename std::enable_if<(Dimension == sizeof...(Rest) + 1), T &>::type + operator()(First first, Rest... rest) + { + return this->m_subgrids[(size_type)first](rest...); + } + + /** Template for functor op.: returning value of the lowest-level subgrid */ + template + typename std::enable_if<(Dimension > sizeof...(Rest) + 1), Grid &>::type + operator()(First first, Rest... rest) + { + return this->m_subgrids[(size_type)first](rest...); + } + + /** Template for functor op.: finalizing the recursion for subgrid returning */ + template + typename std::enable_if<(Dimension > 1), Grid &>::type + operator()(First first) + { + return this->m_subgrids[(size_type)first]; + } + + /** Template for functor op.: returning one of recursively obtained subgrids */ + template + typename std::enable_if<(Dimension == sizeof...(Rest) + 1), const T &>::type + operator()(First first, Rest... rest) const + { + return this->m_subgrids[(size_type)first](rest...); + } + + /** Template for functor op.: returning value of the lowest-level subgrid */ + template + typename std::enable_if<(Dimension > sizeof...(Rest) + 1), const Grid &>::type + operator()(First first, Rest... rest) const + { + return this->m_subgrids[(size_type)first](rest...); + } + + /** Template for functor op.: finalizing the recursion for subgrid returning */ + template + typename std::enable_if<(Dimension > 1), const Grid &>::type + operator()(First first) const + { + return this->m_subgrids[(size_type)first]; } ~Grid() { - // std::cout << "trying" << std::endl; - delete[] data; - // std::cout << "del data (Dim=1), size = " << dim_size << std::endl; + mem_free(); // #TODO почему не delete[]? (тогда в valgrind будет mismatch) } }; -template -class Grid +/** Specialization for 1-dim array */ +template +class Grid { public: - static_assert(Dimension > 0, "Zero-dimensional array"); using value_type = T; using size_type = unsigned; private: - Grid **m_subgrids; + T *data; size_type dim_size; + void mem_allocate(size_type size) + { + data = new T[size]; + } -public: - template - Grid(const First first, const Rest... rest) : dim_size{(size_type)first} + void mem_free() { - m_subgrids = static_cast **>(::operator new(sizeof(Grid) * first)); - for (size_type i = 0; i < first; i++) - { - m_subgrids[i] = new Grid(rest...); - } + delete[] data; } - // Copy constructor - Grid(Grid const &other) +public: + Grid(const T value) { - size_type other_size = other.dim_size; - dim_size = other_size; - m_subgrids = static_cast **>(::operator new(sizeof(Grid) * other_size)); + data = new T[1]; + dim_size = 1; + data[0] = value; + } - for (size_type i = 0; i < other_size; i++) + Grid(size_type size, T const &fill_value) : dim_size{size} + { + mem_allocate(size); + for (size_type i = 0; i < size; i++) { - m_subgrids[i] = new Grid(*(other.m_subgrids[i])); + data[i] = fill_value; } } - // Move constructor - Grid(Grid &&other) + // Copy constructor + Grid(Grid const &other) { - size_type other_size = other.dim_size; - dim_size = other_size; - m_subgrids = static_cast **>(::operator new(sizeof(Grid) * other_size)); + dim_size = other.dim_size; + mem_allocate(dim_size); - for (size_type i = 0; i < other_size; i++) + for (size_type i = 0; i < dim_size; i++) { - m_subgrids[i] = new Grid(*(other.m_subgrids[i])); + data[i] = other.data[i]; } } - Grid &operator=(Grid &rhs) + const T &operator[](size_type rhs) const { - return rhs; + if ((rhs < 0) || (rhs >= dim_size)) + throw std::out_of_range("Out of bounds"); + return data[rhs]; } - Grid &operator=(Grid &&rhs) + + T &operator[](size_type rhs) { - return rhs; + if ((rhs < 0) || (rhs >= dim_size)) + throw std::out_of_range("Out of bounds"); + return data[rhs]; } - // Copying operator + /** Template for functor op.: finalizing the recursion for value returning */ + template + const T &operator()(First first) const + { + return this->data[(size_type)first]; + } - Grid &operator[] (size_type rhs) const + /** Template for functor op.: finalizing the recursion for value returning */ + template + T &operator()(First first) { - if ((rhs < 0) || (rhs >= dim_size)) - throw std::out_of_range("Out of bounds"); - return *m_subgrids[rhs]; + return this->data[(size_type)first]; } ~Grid() { - for (size_type i = 0; i < dim_size; i++) - { - delete m_subgrids[i]; - } - // std::cout << "Subgrids of dim " << Dimension - 1 << " del'd, proceeding to this of dim " - // << Dimension << " with " << dim_size << " subgrids." << std::endl; - - delete m_subgrids; // #TODO почему не delete[]? (тогда в valgrind будет mismatch) + // std::cout << "trying" << std::endl; + mem_free(); + // std::cout << "del data (Dim=1), size = " << dim_size << std::endl; } }; -// template -// class Grid final -// { -// public: -// using value_type = T; -// using size_type = unsigned; - -// private: -// T *data; -// size_type const m_y_size, m_x_size; - -// public: -// Grid(size_type y_size, size_type x_size) : m_y_size(y_size), m_x_size(x_size), data(new T[x_size * y_size]) -// { -// } - -// Grid(T const &t) -// { -// data = new T[1]; -// data[0] = t; -// } - -// // Copy constructor -// Grid(Grid const &) = delete; - -// // Move constructor -// Grid(Grid &&) = delete; - -// // Copy assginment -// Grid &operator=(Grid &) = delete; - -// // Move assignment -// Grid &operator=(Grid &&) = delete; - int main() { - Grid const g3(2, 3, 4, 1.00f); + Grid const g3(10, 10, 10, 1.00f); assert(1.0f == g3[1][1][1]); Grid g2(2, 5, 2.0f); assert(2.0f == g2[1][1]); + std::cout << g3(1, 1, 1) << std::endl; + + g2(1, 1) = 2.5; + assert(g2(1, 1) == g2[1][1]); // Operator skokbochka (_, _, ... _) working same as [][] ... [] + assert(g2(1, 1) != g2(1, 0)); // [g2(1,1)=__2.5f__] != [g2(1,0)=__2.0f__] g2 = g3[1]; - assert(2.0f == g2[1][1]); + assert(1.0f == g2[1][1]); // g2(1,1) rewritten + + assert(&g3[1] != &g2); // g2 was copied properly + + auto g1 = Grid(1u); return 0; } \ No newline at end of file