git.haldean.org plotter / master lib / array2d.hpp
master

Tree @master (Download .tar.gz)

array2d.hpp @masterraw · history · blame

#pragma once

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <stdexcept>
#include <string>
#include <vector>

#include "lodepng.h"

using namespace std;

template<typename T>
struct array2d {
  T *values;
  size_t w;
  size_t h;

  array2d() : array2d(0, 0) {};

  array2d(const size_t w, const size_t h) noexcept : w(w), h(h) {
    values = (T*) calloc(w * h, sizeof(T));
  }

  array2d(const array2d<T> &o) : w(o.w), h(o.h) {
    values = (T*) calloc(w * h, sizeof(T));
    memcpy(values, o.values, w * h * sizeof(T));
  }

  array2d(array2d<T> &&o) : w(o.w), h(o.h), values(o.values) {
    o.values = nullptr;
  }

  ~array2d() noexcept {
    if (values != nullptr) free(values);
  }

  array2d<T>& operator=(const array2d<T> &o) = delete;

  array2d<T>& operator=(array2d<T> &&o) {
    w = o.w;
    h = o.h;
    T *t = values;
    values = o.values;
    o.values = t;
    return *this;
  }

  T& operator()(size_t i) noexcept {
    return values[i];
  }

  const T& operator()(size_t i) const noexcept {
    return values[i];
  }

  T& operator()(size_t i, size_t j) {
    if (__builtin_expect(i > w or j > h, 0)) {
      char *msg;
      asprintf(&msg, "bad access in array2d: i=%llu j=%llu, w=%llu h=%llu",
               i, j, w, h);
      throw out_of_range(msg);
    }
    return values[w * j + i];
  }

  const T& operator()(size_t i, size_t j) const {
    if (__builtin_expect(i > w or j > h, 0)) {
      char *msg;
      asprintf(&msg, "bad access in array2d: i=%llu j=%llu, w=%llu h=%llu",
               i, j, w, h);
      throw out_of_range(msg);
    }
    return values[w * j + i];
  }

  T* data() noexcept {
    return values;
  }

  const T* data() const noexcept {
    return values;
  }

  void fill(T val) {
    const size_t n = w * h;
    for (size_t i = 0; i < n; i++) {
      values[i] = val;
    }
  }

  array2d<T> transposed() const {
    array2d<T> res(h, w);
    for (size_t i = 0; i < w; i++) {
      for (size_t j = 0; j < h; j++) {
        res(j, i) = operator()(i, j);
      }
    }
    return res;
  }
};

bool to_png(string fname, const array2d<double> &grays) {
  vector<uint8_t> normed;
  const size_t n = grays.w * grays.h;
  normed.reserve(n);
  for (size_t i = 0; i < n; i++) {
    double clamped = grays(i);
    clamped = clamped > 1 ? 1 : clamped < 0 ? 0 : clamped;
    normed.push_back((uint8_t) (clamped * 255));
  }
  auto err = lodepng::encode(fname, normed.data(), grays.w, grays.h, LCT_GREY);
  if (err) {
    cout << "failed to write png: " << err << endl;
    return false;
  }
  return true;
}

bool to_png(string fname, const array2d<uint8_t> &vals) {
  auto err = lodepng::encode(fname, vals.data(), vals.w, vals.h, LCT_GREY);
  if (err) {
    cout << "failed to write png: " << err << endl;
    return false;
  }
  return true;
}