Browse Source

working version

master
Joshua Moerman 13 years ago
parent
commit
9f0fae9640
  1. 14
      AwesomeAttractorND.xcodeproj/project.pbxproj
  2. 75
      AwesomeAttractorND/AttractorKernel.hpp
  3. 148
      AwesomeAttractorND/Image.hpp
  4. 159
      AwesomeAttractorND/ImageFormatBMP.hpp
  5. 107
      AwesomeAttractorND/ImageFormatPNG.hpp
  6. 133
      AwesomeAttractorND/Vectors.hpp
  7. 7
      AwesomeAttractorND/array.hpp
  8. 34
      AwesomeAttractorND/main.cpp
  9. 152
      AwesomeAttractorND/nd_array.hpp

14
AwesomeAttractorND.xcodeproj/project.pbxproj

@ -7,6 +7,7 @@
objects = {
/* Begin PBXBuildFile section */
42D0F93D146E8A95002B1025 /* libpng.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 42D0F93C146E8A95002B1025 /* libpng.dylib */; };
42D2E1221456175C00FBC16A /* main.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42D2E1211456175C00FBC16A /* main.cpp */; };
42D2E1241456175C00FBC16A /* AwesomeAttractorND.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = 42D2E1231456175C00FBC16A /* AwesomeAttractorND.1 */; };
/* End PBXBuildFile section */
@ -25,15 +26,19 @@
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
4235C47014655A4000C4E90F /* Vectors.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Vectors.hpp; sourceTree = "<group>"; };
424F11B914643DD5005B8843 /* AttractorKernel.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = AttractorKernel.hpp; sourceTree = "<group>"; };
428EFECF145AF6E0001DBE1B /* Canvas.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Canvas.hpp; sourceTree = "<group>"; };
428EFED4145AFAB4001DBE1B /* Tonemapper.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Tonemapper.hpp; sourceTree = "<group>"; };
42C2D1521461676B001BF28D /* Image.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Image.hpp; sourceTree = "<group>"; };
42C2D1611461894E001BF28D /* Logging.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Logging.hpp; sourceTree = "<group>"; };
42C2D1621461E562001BF28D /* array.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = array.hpp; sourceTree = "<group>"; };
42D0F939146E7F6A002B1025 /* ImageFormatBMP.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = ImageFormatBMP.hpp; sourceTree = "<group>"; };
42D0F93B146E805D002B1025 /* ImageFormatPNG.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = ImageFormatPNG.hpp; sourceTree = "<group>"; };
42D0F93C146E8A95002B1025 /* libpng.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libpng.dylib; path = usr/local/lib/libpng.dylib; sourceTree = SDKROOT; };
42D2E11D1456175C00FBC16A /* AwesomeAttractorND */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = AwesomeAttractorND; sourceTree = BUILT_PRODUCTS_DIR; };
42D2E1211456175C00FBC16A /* main.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = main.cpp; sourceTree = "<group>"; };
42D2E1231456175C00FBC16A /* AwesomeAttractorND.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = AwesomeAttractorND.1; sourceTree = "<group>"; };
42D2E12A1456176800FBC16A /* nd_array.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = nd_array.hpp; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@ -41,6 +46,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
42D0F93D146E8A95002B1025 /* libpng.dylib in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -50,6 +56,7 @@
42D2E1121456175C00FBC16A = {
isa = PBXGroup;
children = (
42D0F93C146E8A95002B1025 /* libpng.dylib */,
42D2E1201456175C00FBC16A /* AwesomeAttractorND */,
42D2E11E1456175C00FBC16A /* Products */,
);
@ -68,11 +75,14 @@
children = (
42D2E1211456175C00FBC16A /* main.cpp */,
42C2D1611461894E001BF28D /* Logging.hpp */,
42D2E12A1456176800FBC16A /* nd_array.hpp */,
428EFECF145AF6E0001DBE1B /* Canvas.hpp */,
42C2D1621461E562001BF28D /* array.hpp */,
424F11B914643DD5005B8843 /* AttractorKernel.hpp */,
4235C47014655A4000C4E90F /* Vectors.hpp */,
428EFED4145AFAB4001DBE1B /* Tonemapper.hpp */,
42C2D1521461676B001BF28D /* Image.hpp */,
42D0F939146E7F6A002B1025 /* ImageFormatBMP.hpp */,
42D0F93B146E805D002B1025 /* ImageFormatPNG.hpp */,
42D2E1231456175C00FBC16A /* AwesomeAttractorND.1 */,
);
path = AwesomeAttractorND;

75
AwesomeAttractorND/AttractorKernel.hpp

@ -0,0 +1,75 @@
//
// AttractorKernel.hpp
// AwesomeAttractorND
//
// Created by Joshua Moerman on 11/4/11.
// Copyright 2011 Vadovas. All rights reserved.
//
#ifndef AwesomeAttractorND_AttractorKernel_hpp
#define AwesomeAttractorND_AttractorKernel_hpp
#include "Vectors.hpp"
class AttractorKernel {
public:
virtual void iterate(VectorIterator begin, VectorIterator end, VectorIterator begin2) = 0;
};
template <typename T>
class StaticAttractorKernel : public AttractorKernel, public T {
public:
virtual void iterate(VectorIterator begin, VectorIterator end, VectorIterator begin2){
while (begin != end) {
T::calculate(*begin2, *begin);
++begin;
++begin2;
}
}
};
struct Unravel {
Unravel()
: parameters()
{
parameters[0] = 0.761090;
parameters[1] = 1.426758;
parameters[2] = 1.516635;
parameters[3] = -0.02366;
parameters[4] = 2.398894;
parameters[5] = -0.32422;
parameters[6] = -2.12839;
}
void calculate(VectorConstRef vectorOld, VectorRef vectorNew){
vectorNew[0] = parameters[0]*(vectorOld[2] + parameters[1]);
vectorNew[1] = parameters[2]*(vectorOld[0] + parameters[3]);
vectorNew[2] = parameters[4]*(vectorOld[1] + parameters[5]);
const double dist = vectorNew[0]*vectorNew[0] + vectorNew[1]*vectorNew[1] + vectorNew[2]*vectorNew[2];
if(dist > parameters[6]*parameters[6]) {
const double sqrtDist = std::sqrt(dist);
const double p = 1.0 - parameters[6] * (static_cast<int>(sqrtDist / parameters[6]) + 1.0) / sqrtDist;
vectorNew[0] *= p;
vectorNew[1] *= p;
vectorNew[2] *= p;
}
}
protected:
std::array<double, 7> parameters;
static const size_t dimension = 3;
};
struct Lorenz {
void calculate(VectorConstRef o, VectorRef n);
};
/*
IDEA: explicitly instantiate StaticAttractorKernel<Unravel>, StaticAttractorKernel<Lorenz>, ...
Thereby we have very little Unravel and Lorenz classes, which do only one thing.
And an abstract base-class. And only iterate() is virtual, thus calculate() can be inlined!
*/
#endif

148
AwesomeAttractorND/Image.hpp

@ -9,151 +9,7 @@
#ifndef AwesomeAttractorND_Image_hpp
#define AwesomeAttractorND_Image_hpp
#include <ostream>
#include <fstream>
#include <stdexcept>
#include <tr1/memory>
struct pixel {
pixel(double red, double green, double blue)
: red(clamp(255*red))
, green(clamp(255*green))
, blue(clamp(255*blue))
{}
pixel(int red, int green, int blue)
: red(clamp(red))
, green(clamp(green))
, blue(clamp(blue))
{}
void swapRB(){
std::swap(red, blue);
}
private:
uint8_t clamp(int n){
return std::min(255, std::max(0, n));
}
uint8_t red;
uint8_t green;
uint8_t blue;
};
namespace ImageFormats {
namespace bmp {
struct bitmap_file_header {
uint32_t filesize;
uint16_t creator1;
uint16_t creator2;
uint32_t bmp_offset;
template <typename DIBT>
bitmap_file_header(DIBT dib_header):
filesize(dib_header.bytes() + dib_header.header_sz + 12 + 2),
creator1(0),
creator2(0),
bmp_offset(dib_header.header_sz + 12 + 2){}
void write(std::ostream& out) const {
out << "BM";
out.write(reinterpret_cast<const char*>(this), 12);
}
};
struct bitmapcoreheader {
uint32_t header_sz;
uint16_t width;
uint16_t height;
uint16_t nplanes;
uint16_t bitspp;
bitmapcoreheader(uint16_t width, uint16_t height, uint16_t bitspp = 24):
header_sz(sizeof(bitmapcoreheader)),
width(width),
height(height),
nplanes(1),
bitspp(bitspp){}
void write(std::ostream& out) const {
out.write(reinterpret_cast<const char*>(this), header_sz);
}
uint32_t bytes(){
return width*height*bitspp/8;
}
};
template <typename P = pixel, typename DIBT = bitmapcoreheader>
struct bitmap {
typedef P pixel;
bitmap(uint16_t width, uint16_t height)
: dib_header(width, height, sizeof(pixel)*8)
, header(dib_header)
, data(0) {}
void write(std::string const & filename){
std::ofstream file(filename.c_str());
write(file);
}
void write(std::ostream& out){
header.write(out);
dib_header.write(out);
//std::copy_n((char const *)data, dib_header.bytes(), std::ostream_iterator<char>(out));
std::copy((char const *)data, (char const *)data + dib_header.bytes(), std::ostream_iterator<char>(out));
}
private:
DIBT dib_header;
bitmap_file_header header;
P const * data;
};
template <typename P = pixel, typename DIBT = bitmapcoreheader>
struct bitmap_stream {
typedef P pixel;
bitmap_stream(uint16_t width, uint16_t height, std::string filename)
: dib_header(width, height, sizeof(pixel)*8)
, header(dib_header)
, file(filename.c_str())
, x(0)
, y(0)
{
if(!file)
throw std::runtime_error("bitmap file could not be opened.");
header.write(file);
dib_header.write(file);
}
bitmap_stream& operator<<(pixel const & p){
if (y >= dib_header.height){
throw std::out_of_range("Writing BMP image out of bounds.");
}
pixel p2(p);
p2.swapRB();
file.write((char const *)&p2, sizeof(pixel));
++x;
if (x >= dib_header.width){
x = 0;
++y;
}
return *this;
}
private:
DIBT dib_header;
bitmap_file_header header;
std::ofstream file;
uint16_t x;
uint16_t y;
};
}
}
#include "ImageFormatBMP.hpp"
#include "ImageFormatPNG.hpp"
#endif

159
AwesomeAttractorND/ImageFormatBMP.hpp

@ -0,0 +1,159 @@
//
// ImageFormatBMP.hpp
// AwesomeAttractorND
//
// Created by Joshua Moerman on 11/12/11.
// Copyright 2011 Vadovas. All rights reserved.
//
#ifndef AwesomeAttractorND_ImageFormatBMP_hpp
#define AwesomeAttractorND_ImageFormatBMP_hpp
#include <ostream>
#include <fstream>
#include <stdexcept>
#include <algorithm>
namespace ImageFormats {
namespace bmp {
struct pixelBGR{
pixelBGR(double red, double green, double blue)
: blue(clamp(255*blue))
, green(clamp(255*green))
, red(clamp(255*red))
{}
pixelBGR(int red, int green, int blue)
: blue(clamp(blue))
, green(clamp(green))
, red(clamp(red))
{}
void swapRB(){
std::swap(red, blue);
}
private:
uint8_t clamp(int n){
return std::min(255, std::max(0, n));
}
uint8_t blue;
uint8_t green;
uint8_t red;
};
struct bitmap_file_header {
uint32_t filesize;
uint16_t creator1;
uint16_t creator2;
uint32_t bmp_offset;
template <typename DIBT>
bitmap_file_header(DIBT dib_header):
filesize(dib_header.bytes() + dib_header.header_sz + 12 + 2),
creator1(0),
creator2(0),
bmp_offset(dib_header.header_sz + 12 + 2){}
void write(std::ostream& out) const {
out << "BM";
out.write(reinterpret_cast<const char*>(this), 12);
}
};
struct bitmapcoreheader {
uint32_t header_sz;
uint16_t width;
uint16_t height;
uint16_t nplanes;
uint16_t bitspp;
bitmapcoreheader(uint16_t width, uint16_t height, uint16_t bitspp = 24):
header_sz(sizeof(bitmapcoreheader)),
width(width),
height(height),
nplanes(1),
bitspp(bitspp){}
void write(std::ostream& out) const {
out.write(reinterpret_cast<const char*>(this), header_sz);
}
uint32_t bytes(){
return width*height*bitspp/8;
}
};
template <typename P = pixelBGR, typename DIBT = bitmapcoreheader>
struct bitmap {
typedef P pixel;
bitmap(uint16_t width, uint16_t height)
: dib_header(width, height, sizeof(pixel)*8)
, header(dib_header)
, data(0) {}
void write(std::string const & filename){
std::ofstream file(filename.c_str());
write(file);
}
void write(std::ostream& out){
header.write(out);
dib_header.write(out);
//std::copy_n((char const *)data, dib_header.bytes(), std::ostream_iterator<char>(out));
std::copy((char const *)data, (char const *)data + dib_header.bytes(), std::ostream_iterator<char>(out));
}
private:
DIBT dib_header;
bitmap_file_header header;
P const * data;
};
template <typename P = pixelBGR, typename DIBT = bitmapcoreheader>
struct bitmap_stream {
typedef P pixel;
bitmap_stream(uint16_t width, uint16_t height, std::string filename)
: dib_header(width, height, sizeof(pixel)*8)
, header(dib_header)
, file(filename.c_str())
, x(0)
, y(0)
{
if(!file)
throw std::runtime_error("bitmap file could not be opened.");
header.write(file);
dib_header.write(file);
}
bitmap_stream& operator<<(pixel const & p){
if (y >= dib_header.height){
throw std::out_of_range("Writing BMP image out of bounds.");
}
pixel p2(p);
p2.swapRB();
file.write((char const *)&p2, sizeof(pixel));
++x;
if (x >= dib_header.width){
x = 0;
++y;
}
return *this;
}
private:
DIBT dib_header;
bitmap_file_header header;
std::ofstream file;
uint16_t x;
uint16_t y;
};
}
}
#endif

107
AwesomeAttractorND/ImageFormatPNG.hpp

@ -0,0 +1,107 @@
//
// ImageFormatPNG.hpp
// AwesomeAttractorND
//
// Created by Joshua Moerman on 11/12/11.
// Copyright 2011 Vadovas. All rights reserved.
//
#ifndef AwesomeAttractorND_ImageFormatPNG_hpp
#define AwesomeAttractorND_ImageFormatPNG_hpp
#include <stdio.h>
#include <stdexcept>
#include <png.h>
namespace ImageFormats {
namespace png{
struct pixel {
pixel()
: red(0)
, green(0)
, blue(0)
{}
pixel(double red, double green, double blue)
: red(clamp(255*red))
, green(clamp(255*green))
, blue(clamp(255*blue))
{}
pixel(int red, int green, int blue)
: red(clamp(red))
, green(clamp(green))
, blue(clamp(blue))
{}
void swapRB(){
std::swap(red, blue);
}
private:
uint8_t clamp(int n){
return std::min(255, std::max(0, n));
}
uint8_t red;
uint8_t green;
uint8_t blue;
};
struct png_stream{
typedef pixel pixel;
png_stream(uint32_t width, uint32_t height, std::string filename)
: fp(0)
, png_ptr(0)
, info_ptr(0)
, row(width)
, x(0)
{
fp = fopen(filename.c_str(), "wb");
if(!fp) throw std::runtime_error("Could not open file");
png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
if(!png_ptr) throw std::runtime_error("PNG structure could not be allocated");
info_ptr = png_create_info_struct(png_ptr);
if(!info_ptr) throw std::runtime_error("PNG information structure could not be allocated");
png_init_io(png_ptr, fp);
png_set_IHDR(png_ptr, info_ptr, width, height, 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
png_set_compression_level(png_ptr, 9);
png_write_info(png_ptr, info_ptr);
}
~png_stream(){
png_write_end(png_ptr, info_ptr);
png_destroy_info_struct(png_ptr, &info_ptr);
fclose(fp);
}
png_stream& operator<<(pixel const & p){
row[x] = p;
++x;
if(x >= row.size()){
png_write_row(png_ptr, reinterpret_cast<unsigned char const*>(row.data()));
x = 0;
}
return *this;
}
private:
FILE* fp;
png_structp png_ptr;
png_infop info_ptr;
std::vector<pixel> row;
uint32_t x;
};
}
}
#endif

133
AwesomeAttractorND/Vectors.hpp

@ -0,0 +1,133 @@
//
// Vectors.hpp
// AwesomeAttractorND
//
// Created by Joshua Moerman on 11/5/11.
// Copyright 2011 Vadovas. All rights reserved.
//
#ifndef AwesomeAttractorND_Vectors_hpp
#define AwesomeAttractorND_Vectors_hpp
#include <iterator>
typedef double* VectorRef;
typedef double const * VectorConstRef;
struct VectorIterator : public std::iterator<std::random_access_iterator_tag, double> {
template <size_t N>
static VectorIterator begin(std::array<double, N> & arr, size_t dimension){
return VectorIterator(arr.data(), dimension);
}
template <size_t N>
static VectorIterator end(std::array<double, N> & arr, size_t dimension){
size_t offset = N - (N % dimension);
return VectorIterator(arr.data() + offset, dimension);
}
VectorIterator(VectorIterator const & rh)
: data(rh.data)
, dimension(rh.dimension)
{}
VectorIterator & operator=(VectorIterator const & rh){
data = rh.data;
dimension = rh.dimension;
return *this;
}
bool operator==(VectorIterator const & rh) const {
return data == rh.data && dimension == rh.dimension;
}
bool operator!=(VectorIterator const & rh) const {
return data != rh.data || dimension != rh.dimension;
}
bool operator<(VectorIterator const & rh) const {
return data < rh.data;
}
bool operator<=(VectorIterator const & rh) const {
return data <= rh.data;
}
bool operator>(VectorIterator const & rh) const {
return data > rh.data;
}
bool operator>=(VectorIterator const & rh) const {
return data >= rh.data;
}
VectorRef operator*(){
return data;
}
VectorRef operator->(){
return data;
}
VectorIterator & operator++(){
data += dimension;
return *this;
}
VectorIterator operator++(int){
VectorIterator temp(*this);
++(*this);
return temp;
}
VectorIterator & operator--(){
data -= dimension;
return *this;
}
VectorIterator operator--(int){
VectorIterator temp(*this);
++(*this);
return temp;
}
VectorIterator & operator+=(int n){
data += n*dimension;
return *this;
}
VectorIterator operator+(int n){
VectorIterator temp(*this);
temp += n;
return temp;
}
VectorIterator & operator-=(int n){
data -= n*dimension;
return *this;
}
VectorIterator operator-(int n){
VectorIterator temp(*this);
temp -= n;
return temp;
}
VectorRef operator[](int n){
VectorIterator temp(*this);
return *(temp += n);
}
private:
VectorIterator(double * data, size_t dimension)
: data(data)
, dimension(dimension)
{}
VectorIterator();
double * data;
size_t dimension;
};
#endif

7
AwesomeAttractorND/array.hpp

@ -9,10 +9,15 @@
#ifndef AwesomeAttractorND_array_hpp
#define AwesomeAttractorND_array_hpp
#include <tr1/array>
// workaround to easily work in xcode :D
#ifndef __APPLE__
#include <array>
#else
#include <tr1/array>
namespace std {
using tr1::array;
}
#endif
#endif

34
AwesomeAttractorND/main.cpp

@ -7,33 +7,49 @@
//
#include <iostream>
#include "array.hpp"
#include "Logging.hpp"
#include "Canvas.hpp"
#include "Tonemapper.hpp"
#include "Image.hpp"
#include "Vectors.hpp"
#include "AttractorKernel.hpp"
typedef Canvas2D Canvas;
void fill(Canvas & canvas);
double unit_random(){
return rand()/ (double) RAND_MAX * 2.0 - 1.0;
}
void fill(Canvas & canvas){
const unsigned int it = 100000000;
std::array<double, 10000> vectors;
std::array<double, 10000> old_vectors;
std::generate(vectors.begin(), vectors.end(), unit_random);
std::generate(old_vectors.begin(), old_vectors.end(), unit_random);
StaticAttractorKernel<Unravel> magic;
const unsigned int it = 100000;
for (unsigned int i = 0; i < it; ++i){
double x = 2.0 * (rand() / (double) RAND_MAX - 0.5);
double y = 2.0 * (rand() / (double) RAND_MAX - 0.5);
double position[2] = {x*x*2.0 - 1.0, y};
canvas.plot(position);
std::array<double, 10000> & v = (i%2 == 1) ? vectors : old_vectors;
std::array<double, 10000> & vo = (i%2 == 0) ? vectors : old_vectors;
magic.iterate(VectorIterator::begin(v, 3), VectorIterator::end(v, 3), VectorIterator::begin(vo, 3));
for(VectorIterator it = VectorIterator::begin(v, 3); it != VectorIterator::end(v, 3); ++it)
canvas.plot(*it);
}
}
void output(Canvas const & canvas);
void output(Canvas const & canvas){
Tonemappers::GammaCorrector tonemapper;
tonemapper.analyse(canvas);
ImageFormats::bmp::bitmap_stream<> image(canvas.size<0>(), canvas.size<1>(), "test.bmp");
ImageFormats::png::png_stream image(canvas.size<0>(), canvas.size<1>(), "test.png");
tonemapper.process(canvas, image);
}
@ -42,7 +58,7 @@ int main (int, const char * []){
l.start("all");
l.log("creating canvas");
Canvas canvas(2048, 2048);
Canvas canvas(8000, 8000);
l.log("filling canvas");
fill(canvas);
l.log("outputting canvas");

152
AwesomeAttractorND/nd_array.hpp

@ -1,152 +0,0 @@
//
// nd_array.hpp
// AwesomeAttractorND
//
// Created by Joshua Moerman on 10/25/11.
// Copyright 2011 Vadovas. All rights reserved.
//
/*
Dynamic multi-dimensional array.
With the usual c-syntax: v[x][y][z].
Memory is allocated as one big block, instead of multiple smaller blocks (which is the case with std::vector<std::vector<...>>).
Showed no difference in speed compared to std::array<std::array<...>> (in release build).
it is not yet standard compliant.
*/
#ifndef AwesomeAttractorND_nd_array_hpp
#define AwesomeAttractorND_nd_array_hpp
#include <stdexcept>
#include <numeric>
#include <iterator>
#include "array.hpp"
template <typename T, size_t dimension>
class nd_array{
public:
typedef T & reference;
typedef T const & const_reference;
typedef T * iterator;
typedef T const * const_iterator;
typedef size_t size_type;
typedef ptrdiff_t difference_type;
typedef T value_type;
typedef T * pointer;
typedef T const * const_pointer;
typedef std::reverse_iterator<iterator> reverse_iterator;
typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
template <size_type N>
struct proxy {
nd_array * const data;
size_t const offset;
proxy(nd_array * const c, size_t o)
: data(c)
, offset(o)
{}
proxy<N-1> operator[](size_t y){
if (N == 0) throw std::logic_error("called operator[] on a value");
return proxy<N-1>(data, data->sizes[dimension - N]*offset + y);
}
operator reference(){
if (N != 0) throw std::logic_error("using a non-value");
return *(data->data + offset);
}
reference operator=(T const & n){
if (N != 0) throw std::logic_error("assignment to a non-value");
return *(data->data + offset) = n;
}
};
template <size_type N>
struct const_proxy {
nd_array const * const data;
size_t const offset;
const_proxy(nd_array const * const c, size_t o)
: data(c)
, offset(o)
{}
const_proxy<N-1> operator[](size_t y) const {
if (N == 0) throw std::logic_error("called operator[] on a value");
return const_proxy<N-1>(data, data->sizes[dimension - N]*offset + y);
}
operator const_reference() const {
if (N != 0) throw std::logic_error("using a non-value");
return *(data->data + offset);
}
};
nd_array(size_type width, size_type height)
: data(0)
, sizes()
{
if (dimension != 2) throw std::logic_error("wrong constructor");
sizes[0] = width;
sizes[1] = height;
data = new T[width*height];
}
nd_array(size_type width, size_type height, size_type depth)
: data(0)
, sizes()
{
if (dimension != 3) throw std::logic_error("wrong constructor");
sizes[0] = width;
sizes[1] = height;
sizes[2] = depth;
data = new T[width*height*depth];
}
~nd_array(){
delete[] data;
}
size_type get_size(size_type d) const {
return sizes[d];
}
size_type size() const {
return std::accumulate(sizes.begin(), sizes.end(), 1, std::multiplies<size_type>());
}
proxy<dimension-1> operator[](size_t x){
return proxy<dimension-1>(this, x);
}
const_proxy<dimension-1> operator[](size_t x) const {
return const_proxy<dimension-1>(this, x);
}
iterator begin(){
return data;
}
iterator end(){
size_type length = size();
return data + length;
}
const_iterator cbegin() const {
return data;
}
const_iterator cend() const {
size_type length = size();
return data + length;
}
private:
T * data;
std::array<size_type, dimension> sizes;
};
#endif