Skip to content

Instantly share code, notes, and snippets.

@ktnyt
Created September 26, 2016 07:53
Show Gist options
  • Save ktnyt/eb9cae607dc7e34b2fc12b510fbc7ec3 to your computer and use it in GitHub Desktop.
Save ktnyt/eb9cae607dc7e34b2fc12b510fbc7ec3 to your computer and use it in GitHub Desktop.
high functionality array prototype
#include <iostream>
#include <functional>
#include <array>
#include <vector>
template<std::size_t... S>
struct accumulator;
template<std::size_t R, std::size_t... S>
struct accumulator<R, S...> {
static constexpr std::size_t product = R * accumulator<S...>::product;
};
template<>
struct accumulator<> {
static constexpr std::size_t product = 1;
};
class ArrayBase {
public:
ArrayBase(std::size_t size) : self(std::make_shared<impl>(size)) {}
ArrayBase(const ArrayBase& other) : self(other.self) {}
ArrayBase(ArrayBase&& other) noexcept : self(other.self) {other.self = nullptr;}
ArrayBase& operator=(const ArrayBase& other) {
ArrayBase another(other);
*this = std::move(another);
return *this;
}
ArrayBase& operator=(ArrayBase&& other) {
swap(*this, other);
return *this;
}
friend void swap(ArrayBase& a , ArrayBase& b) {
std::swap(a.self, b.self);
}
template<typename T>
T* cast_buffer() const {
return reinterpret_cast<T*>(self->buffer);
}
private:
struct impl {
impl(std::size_t size) : buffer(new char[size]) {}
~impl() {delete[] buffer;}
char* buffer;
}; std::shared_ptr<impl> self;
};
template<typename T, std::size_t R>
struct Dtype {
static constexpr std::size_t size = sizeof(T) / sizeof(char) * R;
};
template<typename T, std::size_t... S>
class Array;
template<typename T, std::size_t R, std::size_t... S>
class Array<T, R, S...> : public ArrayBase {
template<typename U, std::size_t ...V>
friend class Array;
public:
static constexpr std::size_t length = R;
static constexpr std::size_t rank = sizeof...(S) + 1;
static constexpr std::array<std::size_t, rank> shape = {R, S...};
static constexpr std::size_t size = accumulator<R, S...>::product;
Array() : ArrayBase(Dtype<T, size>::size) {
values = cast_buffer<T>();
for(std::size_t i = 0; i < rank; ++i) {
strides[i] = 1;
for(std::size_t j = i + 1; j < rank; ++j) {
strides[i] *= shape[j];
}
}
for(std::size_t i = 0; i < size; ++i) {
values[i] = i;
}
}
Array(const Array& other) : ArrayBase(other), values(other.values) {}
Array(Array&& other) noexcept : ArrayBase(other), values(other.values) {other.values = nullptr;}
Array& operator=(const Array& other) {
Array another(other);
*this = std::move(another);
return *this;
}
Array& operator=(Array&& other) {
swap(*this, other);
return *this;
}
friend void swap(Array& a , Array& b) {
std::swap(dynamic_cast<ArrayBase&>(a), dynamic_cast<ArrayBase&>(b));
std::swap(a.values, b.values);
}
template<std::size_t Q>
Array(const Array<T, Q, R, S...>& other, std::size_t index) : ArrayBase(other) {
std::size_t stride = other.strides[0];
for(std::size_t i = 0; i < rank; ++i) {
strides[i] = other.strides[i + 1];
}
values = other.values + (index * stride);
}
Array<T, S...> operator[](std::size_t index) const {
return Array<T, S...>(*this, index);
}
std::ostream& format(std::ostream& ostream, std::size_t depth=0, bool first=false) const {
if(!first) {
for(std::size_t i = 0; i < depth; ++i) {
ostream << " ";
}
}
ostream << "[";
for(std::size_t i = 0; i < length; ++i) {
(*this)[i].format(ostream, depth + 1, i == 0);
if(length - i > 1) {
for(std::size_t i = 0; i < rank - 1; ++i) {
ostream << std::endl;
}
}
}
return ostream << "]";
}
friend std::ostream& operator <<(std::ostream& ostream, const Array& a) {
return a.format(ostream);
}
private:
std::array<std::size_t, rank> strides;
std::vector<Array<T, S...> > subarrays;
T* values;
};
template<typename T, std::size_t R, std::size_t... S>
constexpr std::size_t Array<T, R, S...>::length;
template<typename T, std::size_t R, std::size_t... S>
constexpr std::size_t Array<T, R, S...>::rank;
template<typename T, std::size_t R, std::size_t... S>
constexpr std::array<std::size_t, Array<T, R, S...>::rank> Array<T, R, S...>::shape;
template<typename T, std::size_t R, std::size_t... S>
constexpr std::size_t Array<T, R, S...>::size;
template<typename T, std::size_t R>
class Array<T, R> : public ArrayBase {
template<typename U, std::size_t ...V>
friend class Array;
public:
static constexpr std::size_t length = R;
static constexpr std::size_t rank = 1;
static constexpr std::array<std::size_t, rank> shape = {R};
static constexpr std::size_t size = R;
Array() : ArrayBase(Dtype<T, size>::size) {
values = cast_buffer();
for(std::size_t i = 0; i < size; ++i) {
values[i] = i;
}
}
Array(const Array& other) : ArrayBase(other), values(other.values) {}
Array(Array&& other) noexcept : ArrayBase(other), values(other.values) {other.values = nullptr;}
Array& operator=(const Array& other) {
Array another(other);
*this = std::move(another);
return *this;
}
Array& operator=(Array&& other) {
swap(*this, other);
return *this;
}
friend void swap(Array& a , Array& b) {
std::swap(dynamic_cast<ArrayBase&>(a), dynamic_cast<ArrayBase&>(b));
std::swap(a.values, b.values);
}
template<std::size_t Q>
Array(const Array<T, Q, R>& other, std::size_t index) : ArrayBase(other) {
std::size_t stride = other.strides[0];
for(std::size_t i = 0; i < rank; ++i) {
strides[i] = other.strides[i + 1];
}
values = other.values + (index * stride);
}
T& operator[](std::size_t index) const {
return values[index];
}
std::ostream& format(std::ostream& ostream, std::size_t depth=0, bool first=false) const {
if(!first) {
for(std::size_t i = 0; i < depth; ++i) {
ostream << " ";
}
}
ostream << "[";
for(std::size_t i = 0; i < length; ++i) {
ostream << (*this)[i];
if(length - i > 1) {
ostream << " ";
}
}
return ostream << "]";
}
friend std::ostream& operator <<(std::ostream& ostream, const Array& a) {
return a.format(ostream);
}
private:
std::array<std::size_t, rank> strides;
T* values;
};
template<typename T, std::size_t R>
constexpr std::size_t Array<T, R>::length;
template<typename T, std::size_t R>
constexpr std::size_t Array<T, R>::rank;
template<typename T, std::size_t R>
constexpr std::array<std::size_t, Array<T, R>::rank> Array<T, R>::shape;
template<typename T, std::size_t R>
constexpr std::size_t Array<T, R>::size;
int main() {
Array<int, 2, 3, 4> t0;
Array<int, 2, 3, 4> t1;
t0[0] = t1[1];
//for(std::size_t i = 0; i < 2; ++i)
// for(std::size_t j = 0; j < 3; ++j)
// for(std::size_t k = 0; k < 4; ++k)
// std::cout << t0[i][j][k] << std::endl;
std::cout << t0 << std::endl;
// std::cout << t1[1][0][0] << std::endl;
// std::cout << t1[1][0][1] << std::endl;
// std::cout << t1[1][0][2] << std::endl;
// std::cout << t1[1][0][3] << std::endl;
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment