Skip to content

Instantly share code, notes, and snippets.

@hatahet
Forked from rmartinho/darray2d.h
Created April 7, 2014 04:53
Show Gist options
  • Save hatahet/10015001 to your computer and use it in GitHub Desktop.
Save hatahet/10015001 to your computer and use it in GitHub Desktop.
// Two-dimensional array with dimensions determined at runtime
//
// Written in 2012 by Martinho Fernandes
//
// To the extent possible under law, the author(s) have dedicated all copyright and related
// and neighboring rights to this software to the public domain worldwide. This software is
// distributed without any warranty.
//
// You should have received a copy of the CC0 Public Domain Dedication along with this software.
// If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
// Installation:
// Place this into a header file and #include it in your code. Done.
//
// Usage:
// so::darray2d<int> x(10, 10); // create a 10x10 array
// int x12 = x[1][2]; // access an element
// x[1][2] = 42; // modify an element
// int* all = x.data(); // get a pointer to the whole array
// int* row1p = x[1].data(); // get a pointer to a row
// std::sort(x.begin(), x.end()); // use the whole array in standard library algorithms
// std::sort(x[1].begin(), x[1].end()); // use a row in standard library algorithms
// so::darray2d<int> y = x; // copiable
// so::darray2d<int> z = std::move(x); // movable (C++11)
//
// This can also be easily and safely returned from functions by value, no need to use pointers or dynamic allocation:
// so::darray2d<int> get_an_array(int x) {
// so::darray2d<int> result(x, x);
// return result;
// }
//
// Only two-dimensional arrays are supported.
// If you think you need a three-dimensional array, you're probably doing
// it wrong. But if you really want to take a stab at doing so, you may use
// this code as a starting point.
//
// If you don't want any C++11 features #define SO_ARRAY2D_NO_CPP11 before #including.
//
// Now, go forth and stop newing up multidimensional arrays
#ifndef DARRAY2D_HPP_INCLUDED
#define DARRAY2D_HPP_INCLUDED
#include <cassert> // assert
#include <cstddef> // size_t, ptrdiff_t
#include <algorithm> // copy
#ifndef SO_ARRAY2D_NO_CPP11
#define SO_ARRAY2D_CPP11_DELETE = delete
#else
#define SO_ARRAY2D_CPP11_DELETE
#endif
#ifndef SO_ARRAY2D_NO_CPP11
# include <memory> // unique_ptr
#else
# include <utility> // swap
namespace so {
namespace detail {
template <typename T>
class array_ptr {
public:
array_ptr(T* ptr) : ptr(ptr) { assert(ptr); }
~array_ptr() { delete[] ptr; }
T* get() const { return ptr; }
T& operator[](std::ptrdiff_t index) const { return ptr[index]; }
void swap(array_ptr<T>& that) {
using std::swap;
swap(ptr, that.ptr);
}
private:
T* ptr;
array_ptr(array_ptr const&);
array_ptr& operator=(array_ptr const&);
};
template <typename T>
void swap(array_ptr<T>& x, array_ptr<T>& y) { x.swap(y); }
}
}
#endif
namespace so {
template <typename T>
class darray2d {
#ifndef SO_ARRAY2D_NO_CPP11
typedef std::unique_ptr<T[]> smart_ptr;
#else
typedef detail::array_ptr<T> smart_ptr;
#endif
public:
darray2d(std::size_t n, std::size_t m)
: storage(new T[n*m]), n(n), m(m) {}
darray2d(darray2d const& that)
: storage(new T[that.n*that.m]), n(that.n), m(that.m) {
std::copy(that.begin(), that.end(), this->begin());
}
#ifndef SO_ARRAY2D_NO_CPP11
darray2d(darray2d&& that)
: storage(std::move(that.storage)), n(that.n), m(that.m) {
that.n = that.m = 0;
}
#endif
darray2d& operator=(darray2d that) {
swap(*this, that);
return *this;
}
class proxy {
public:
T& operator[](std::ptrdiff_t index) {
assert(index >= 0 && index < m);
return storage[row * m + index];
}
T* begin() { return &storage[row * m]; }
T* end() { return &storage[row * m] + m; }
T* data() { return &storage[row * m]; }
private:
template <typename X>
void operator=(X const&) SO_ARRAY2D_CPP11_DELETE;
friend class darray2d<T>;
proxy(T* storage, std::ptrdiff_t row, std::size_t m)
: storage(storage), row(row), m(m) {}
T* storage;
std::ptrdiff_t row;
std::size_t m;
};
class const_proxy {
public:
T const& operator[](std::ptrdiff_t index) {
assert(index >= 0 && index < m);
return storage[row * m + index];
}
T const* begin() const { return &storage[row * m]; }
T const* end() const { return &storage[row * m] + m; }
T const* data() const { return &storage[row * m]; }
private:
template <typename X>
void operator=(X const&) SO_ARRAY2D_CPP11_DELETE;
friend class darray2d<T>;
const_proxy(T const* storage, std::ptrdiff_t row, std::size_t m)
: storage(storage), row(row), m(m) {}
T const* storage;
std::ptrdiff_t row;
std::size_t m;
};
proxy operator[](std::ptrdiff_t index) {
assert(index >= 0 && index < n);
return proxy(storage.get(), index, m);
}
const_proxy operator[](std::ptrdiff_t index) const {
assert(index >= 0 && index < n);
return const_proxy(storage.get(), index, m);
}
std::size_t rows() const { return n; }
std::size_t columns() const { return m; }
T* begin() { return &storage[0]; }
T* end() { return &storage[0] + n*m; }
T* data() { return &storage[0]; }
T const* begin() const { return &storage[0]; }
T const* end() const { return &storage[0] + n*m; }
T const* data() const { return &storage[0]; }
friend void swap(darray2d& x, darray2d& y) {
using std::swap;
swap(x.storage, y.storage);
swap(x.n, y.n);
swap(x.m, y.m);
}
private:
smart_ptr storage;
std::size_t n;
std::size_t m;
};
}
#undef SO_ARRAY2D_CPP11_DELETE
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment