Last active
March 30, 2021 12:50
-
-
Save grayed/be8dd3b827b300226cee388f93b63f09 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "stdafx.h" | |
#include <array> | |
#include <exception> | |
#include <iostream> | |
#include <climits> | |
#include <cstdint> | |
#include <string.h> | |
// AUTORESIZE как... | |
// 1. Параметр шаблона | |
// 2. Изменение поведения при наследовании | |
// 3. Переменная в самом классе Array | |
// AUTORESIZE == true -> при обращении за пределами size() дополнительное место выделяется | |
// AUTORESIZE == false -> при обращении за пределами size() кидается исключение | |
template<class T, bool AUTORESIZE = false, class SIZE = size_t> | |
class Array { | |
class ArrayData { | |
public: | |
ArrayData(SIZE size_) : size(size_), capacity(size_), refcnt(1) { p = new T[size]; } | |
~ArrayData() { delete[] p; } | |
T *p; | |
SIZE size, capacity, refcnt; | |
}; | |
ArrayData *d; | |
public: | |
Array(SIZE size_ = 0) : d(new ArrayData(size_)) { } | |
Array(const Array<T, AUTORESIZE, SIZE> &other) : d(other.d) { | |
d->refcnt++; | |
} | |
~Array() { | |
d->refcnt -= 1; | |
if (d->refcnt == 0) | |
delete d; | |
} | |
SIZE getSize() const { return d->size; } | |
const T *getData() const { return d->p; } | |
T *getData() { return d->p; } | |
T operator[](SIZE idx) const { | |
if (idx >= d->size) { | |
if (AUTORESIZE) | |
resize(idx + 1); | |
else | |
throw std::invalid_argument("invalid index"); | |
} | |
return d->p[idx]; | |
} | |
T& operator[](SIZE idx) { | |
if (idx >= d->size) { | |
if (AUTORESIZE) | |
resize(idx + 1); | |
else | |
throw std::invalid_argument("invalid index"); | |
} | |
return d->p[idx]; | |
} | |
void resize(SIZE newSize) { | |
if (newSize <= d->capacity && d->refcnt == 1) { | |
d->size = newSize; | |
return; | |
} | |
if (d->refcnt == 1) { | |
T *newp = new T[newSize]; | |
memcpy(newp, d->p, ((newSize < d->size) ? newSize : d->size) * sizeof(T)); | |
delete[] d->p; | |
d->p = newp; | |
d->capacity = d->size = newSize; | |
} else { | |
ArrayData *tmp = new ArrayData(newSize); | |
memcpy(tmp->p, d->p, ((newSize < d->size) ? newSize : d->size) * sizeof(T)); | |
d->refcnt--; | |
d = tmp; | |
} | |
} | |
}; | |
template<class T, class SIZE = size_t> | |
class Array2 { | |
protected: | |
class ArrayData { | |
public: | |
ArrayData(SIZE size_) : size(size_), capacity(size_), refcnt(1) { p = new T[size]; } | |
~ArrayData() { delete[] p; } | |
T *p; | |
SIZE size, capacity, refcnt; | |
}; | |
ArrayData *d; | |
public: | |
Array2(SIZE size_ = 0) : d(new ArrayData(size_)) { } | |
Array2(const Array2<T, SIZE> &other) : d(other.d) { | |
d->refcnt++; | |
} | |
~Array2() { | |
d->refcnt -= 1; | |
if (d->refcnt == 0) | |
delete d; | |
} | |
SIZE getSize() const { return d->size; } | |
const T *getData() const { return d->p; } | |
T *getData() { return d->p; } | |
virtual T operator[](SIZE idx) const { | |
if (idx >= d->size) | |
throw std::invalid_argument("invalid index"); | |
return d->p[idx]; | |
} | |
virtual T& operator[](SIZE idx) { | |
if (idx >= d->size) | |
throw std::invalid_argument("invalid index"); | |
return d->p[idx]; | |
} | |
void resize(SIZE newSize) { | |
if (newSize <= d->capacity && d->refcnt == 1) { | |
d->size = newSize; | |
return; | |
} | |
if (d->refcnt == 1) { | |
T *newp = new T[newSize]; | |
memcpy(newp, d->p, ((newSize < d->size) ? newSize : d->size) * sizeof(T)); | |
delete[] d->p; | |
d->p = newp; | |
d->capacity = d->size = newSize; | |
} else { | |
ArrayData *tmp = new ArrayData(newSize); | |
memcpy(tmp->p, d->p, ((newSize < d->size) ? newSize : d->size) * sizeof(T)); | |
d->refcnt--; | |
d = tmp; | |
} | |
} | |
}; | |
template<class T, class SIZE = size_t> | |
class Array2AutoResize : public Array2<T, SIZE> { | |
public: | |
Array2AutoResize(SIZE size_ = 0) : Array2<T, SIZE>(size_) { } | |
Array2AutoResize(const Array2AutoResize<T, SIZE> &other) : Array2<T, SIZE>(other) { } | |
virtual T operator[](SIZE idx) const { | |
if (idx >= this->d->size) | |
const_cast<Array2AutoResize<T, SIZE>*>(this)->resize(idx + 1); | |
return this->d->p[idx]; | |
} | |
virtual T& operator[](SIZE idx) { | |
if (idx >= this->d->size) | |
this->resize(idx + 1); | |
return this->d->p[idx]; | |
} | |
}; | |
template<class T, class SIZE = size_t> | |
class Array3 { | |
class ArrayData { | |
public: | |
ArrayData(SIZE size_) : size(size_), capacity(size_), refcnt(1) { p = new T[size]; } | |
~ArrayData() { delete[] p; } | |
T *p; | |
SIZE size, capacity, refcnt; | |
}; | |
ArrayData *d; | |
bool autoresize; | |
public: | |
Array3(SIZE size_ = 0, bool autoresize_ = false) : d(new ArrayData(size_)), autoresize(autoresize_) { } | |
Array3(const Array3<T, SIZE> &other) : d(other.d), autoresize(other.autoresize) { | |
d->refcnt++; | |
} | |
~Array3() { | |
d->refcnt -= 1; | |
if (d->refcnt == 0) | |
delete d; | |
} | |
SIZE getSize() const { return d->size; } | |
const T *getData() const { return d->p; } | |
T *getData() { return d->p; } | |
bool getAutoresize() const { return autoresize; } | |
void setAutoresize(bool newAutoresize = true) { autoresize = newAutoresize; } | |
T operator[](SIZE idx) const { | |
if (idx >= d->size) { | |
if (autoresize) | |
resize(idx + 1); | |
else | |
throw std::invalid_argument("invalid index"); | |
} | |
return d->p[idx]; | |
} | |
T& operator[](SIZE idx) { | |
if (idx >= d->size) { | |
if (autoresize) | |
resize(idx + 1); | |
else | |
throw std::invalid_argument("invalid index"); | |
} | |
return d->p[idx]; | |
} | |
void resize(SIZE newSize) { | |
if (newSize <= d->capacity && d->refcnt == 1) { | |
d->size = newSize; | |
return; | |
} | |
if (d->refcnt == 1) { | |
T *newp = new T[newSize]; | |
memcpy(newp, d->p, ((newSize < d->size) ? newSize : d->size) * sizeof(T)); | |
delete[] d->p; | |
d->p = newp; | |
d->capacity = d->size = newSize; | |
} else { | |
ArrayData *tmp = new ArrayData(newSize); | |
memcpy(tmp->p, d->p, ((newSize < d->size) ? newSize : d->size) * sizeof(T)); | |
d->refcnt--; | |
d = tmp; | |
} | |
} | |
}; | |
template<typename T> | |
class Matrix { | |
public: | |
class Row { | |
T *p; | |
size_t size; | |
Row(T *p_, size_t size_) : size(size_), p(p_) { } | |
friend Matrix<T>; | |
public: | |
size_t getSize() const { return size; } | |
T operator[](size_t col) const { return p[col]; } | |
T& operator[](size_t col) { return p[col]; } | |
}; | |
private: | |
T *data; | |
size_t nrows, ncols; | |
// https://gist.github.com/grayed/ arr3.cpp | |
public: | |
Matrix(size_t nrows_, size_t ncols_) : nrows(nrows_), ncols(ncols_) { | |
if (nrows == 0 || ncols == 0) | |
throw std::invalid_argument("zero-sized matrix creation is prohibited"); | |
// a * b = c a>=1, b>=1 -> c/a>=b, c/b>=a c<=SIZE_MAX SIZE_MAX/a>=b | |
if (SIZE_MAX / nrows < ncols) | |
throw std::invalid_argument("too large matrix requested"); | |
data = new T[nrows * ncols]; | |
} | |
Matrix(const Matrix<T> &other) : data(new T[other.nrows * other.ncols]), nrows(other.nrows), ncols(other.ncols) | |
{ for (size_t i = 0; i < nrows * ncols; i++) data[i] = other.data[i]; } | |
~Matrix() { delete[] data; } | |
size_t rowCount() const { return nrows; } | |
size_t columnCount() const { return ncols; } | |
// [ 1, 2, 3, 4, 10, 20, 30, 40, 100, 200, 300, 400 ] 4 столбца, 3 строки | |
const Row operator[](size_t row) const { return Row(data + (row * ncols), ncols); } | |
Row operator[](size_t row) { return Row(data + (row * ncols), ncols); } | |
Matrix<T> transponded() const { | |
Matrix<T> result(ncols, nrows); // 3 столбца, 4 строки | |
for (size_t i = 0; i < ncols; i++) | |
for (size_t j = 0; j < nrows; j++) | |
result.data[(i * result.ncols) + j] = this->data[(j * ncols) + i]; | |
return result; | |
} | |
// TODO: реализовать умножение матрицы на число и на другую матрицу | |
Matrix<T> operator *(T multiplier) const { | |
Matrix<T> result(/* ... */); | |
// ... | |
return result; | |
} | |
Matrix<T>& operator *=(T multiplier) { | |
// ... | |
return *this; | |
} | |
Matrix<T> operator *(const Matrix<T> &other) const { | |
Matrix<T> result(/* ... */); | |
// ... | |
return result; | |
} | |
}; | |
template<typename T> | |
std::ostream& operator <<(std::ostream& os, Matrix<T> matrix) { | |
for (size_t row = 0; row < matrix.rowCount(); row++) { | |
for (size_t col = 0; col < matrix.columnCount(); col++) | |
os << matrix[row][col] << '\t'; | |
os << std::endl; | |
} | |
return os; | |
} | |
// https://clck.ru/TsNVM | |
int main(int argc, char* argv[]) | |
{ | |
try { | |
Matrix<int> matrix(2, 3); | |
matrix[0][0] = 1; | |
matrix[0][1] = 2; | |
matrix[0][2] = 3; | |
matrix[1][0] = 4; | |
matrix[1][1] = 5; | |
matrix[1][2] = 6; | |
std::cout << "Source:" << std::endl << matrix << std::endl; | |
Matrix<int> t = matrix.transponded(); | |
std::cout << "Transponded:" << std::endl << t << std::endl; | |
matrix = matrix * 7; | |
std::cout << "Multiplied:" << std::endl << matrix << std::endl; | |
matrix *= 7; | |
std::cout << "Multiplied twice:" << std::endl << matrix << std::endl; | |
} | |
catch (std::invalid_argument ex) { | |
std::cerr << ex.what() << std::endl; | |
} | |
{ char ch; std::cin >> ch; } | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment