Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file removed week06/main
Binary file not shown.
307 changes: 204 additions & 103 deletions week06/main.cpp
Original file line number Diff line number Diff line change
@@ -1,188 +1,289 @@
#include <iostream>
#include <cassert>
#include <type_traits>

template <typename T, unsigned Dimension>
class Grid;

/* Specialization for 1-dim array */
template <typename T>
class Grid<T, 1>
template <typename T, unsigned Dimension> // 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<T, Dimension - 1> *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<Grid<T, Dimension - 1> *>(::operator new(sizeof(Grid<T, Dimension - 1>) * 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<T, Dimension - 1>();
}

::operator delete(m_subgrids);
}

public:
Grid<T, 1>(T &&value)
template <typename First, typename... Rest, std::enable_if_t<(sizeof...(Rest) > 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<T, Dimension - 1>(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<T, Dimension> 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<T, Dimension - 1>(other.m_subgrids[i]);
}
}

// Copy constructor
Grid(Grid<T, 1> const &other)
/** Move constructor (possibly takes rvalue as an argument) */
Grid(Grid<T, Dimension> &&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<T, Dimension> &operator=(const Grid<T, Dimension> &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<T, Dimension - 1>(rhs.m_subgrids[i]);
}
return *this;
}

/** Move assignment */
Grid<T, Dimension> &operator=(Grid<T, Dimension> &&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<T, Dimension - 1> &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<T, Dimension - 1> &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 First, typename... Rest>
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 First, typename... Rest>
typename std::enable_if<(Dimension > sizeof...(Rest) + 1), Grid<T, Dimension - sizeof...(Rest) - 1> &>::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 First>
typename std::enable_if<(Dimension > 1), Grid<T, Dimension - 1> &>::type
operator()(First first)
{
return this->m_subgrids[(size_type)first];
}

/** Template for functor op.: returning one of recursively obtained subgrids */
template <typename First, typename... Rest>
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 First, typename... Rest>
typename std::enable_if<(Dimension > sizeof...(Rest) + 1), const Grid<T, Dimension - sizeof...(Rest) - 1> &>::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 First>
typename std::enable_if<(Dimension > 1), const Grid<T, Dimension - 1> &>::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 <typename T, unsigned Dimension>
class Grid
/** Specialization for 1-dim array */
template <typename T>
class Grid<T, 1>
{
public:
static_assert(Dimension > 0, "Zero-dimensional array");
using value_type = T;
using size_type = unsigned;

private:
Grid<T, Dimension - 1> **m_subgrids;
T *data;
size_type dim_size;
void mem_allocate(size_type size)
{
data = new T[size];
}

public:
template <typename First, typename... Rest>
Grid(const First first, const Rest... rest) : dim_size{(size_type)first}
void mem_free()
{
m_subgrids = static_cast<Grid<T, Dimension - 1> **>(::operator new(sizeof(Grid<T, Dimension - 1>) * first));
for (size_type i = 0; i < first; i++)
{
m_subgrids[i] = new Grid<T, Dimension - 1>(rest...);
}
delete[] data;
}

// Copy constructor
Grid(Grid<T, Dimension> const &other)
public:
Grid(const T value)
{
size_type other_size = other.dim_size;
dim_size = other_size;
m_subgrids = static_cast<Grid<T, Dimension - 1> **>(::operator new(sizeof(Grid<T, Dimension - 1>) * 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<T, Dimension - 1>(*(other.m_subgrids[i]));
data[i] = fill_value;
}
}

// Move constructor
Grid(Grid<T, Dimension> &&other)
// Copy constructor
Grid(Grid<T, 1> const &other)
{
size_type other_size = other.dim_size;
dim_size = other_size;
m_subgrids = static_cast<Grid<T, Dimension - 1> **>(::operator new(sizeof(Grid<T, Dimension - 1>) * 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<T, Dimension - 1>(*(other.m_subgrids[i]));
data[i] = other.data[i];
}
}

Grid<T, Dimension> &operator=(Grid<T, Dimension> &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<T, Dimension> &operator=(Grid<T, Dimension> &&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 <typename First>
const T &operator()(First first) const
{
return this->data[(size_type)first];
}

Grid<T, Dimension - 1> &operator[] (size_type rhs) const
/** Template for functor op.: finalizing the recursion for value returning */
template <typename First>
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 <typename T>
// 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<T>(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<T> const &) = delete;

// // Move constructor
// Grid(Grid<T> &&) = delete;

// // Copy assginment
// Grid<T> &operator=(Grid<T> &) = delete;

// // Move assignment
// Grid<T> &operator=(Grid<T> &&) = delete;

int main()
{
Grid<float, 3> const g3(2, 3, 4, 1.00f);
Grid<float, 3> const g3(10, 10, 10, 1.00f);
assert(1.0f == g3[1][1][1]);

Grid<float, 2> 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<unsigned, 1>(1u);
return 0;
}