Created
September 26, 2016 07:53
-
-
Save ktnyt/eb9cae607dc7e34b2fc12b510fbc7ec3 to your computer and use it in GitHub Desktop.
high functionality array prototype
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 <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