<commit_before>//=======================================================================
// Copyright (c) 2020 Baptiste Wicht
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

#include <complex>
#include <iostream>

#include "cuda.h"
#include "cuda_runtime.h"
#include "cuda_runtime_api.h"

#include "egblas.hpp"
#include "test.hpp"

#include "catch.hpp"

TEST_CASE("bce/loss/s/0", "[float][bce]") {
    const size_t N = 137;

    float* x_cpu = new float[N];
    float* y_cpu = new float[N];

    for (size_t i = 0; i < N; ++i) {
        x_cpu[i] = 0.9 / (i + 1);
        y_cpu[i] = (i + 1);
    }

    float* x_gpu;
    float* y_gpu;
    cuda_check(cudaMalloc((void**)&x_gpu, N * sizeof(float)));
    cuda_check(cudaMalloc((void**)&y_gpu, N * sizeof(float)));

    cuda_check(cudaMemcpy(x_gpu, x_cpu, N * sizeof(float), cudaMemcpyHostToDevice));
    cuda_check(cudaMemcpy(y_gpu, y_cpu, N * sizeof(float), cudaMemcpyHostToDevice));

    float loss = egblas_bce_sloss(N, 1.1f, x_gpu, 1, y_gpu, 1);

    REQUIRE(loss == Approx(46962.207));

    cuda_check(cudaFree(x_gpu));
    cuda_check(cudaFree(y_gpu));

    delete[] x_cpu;
    delete[] y_cpu;
}

TEST_CASE("bce/loss/d/0", "[double][bce]") {
    const size_t N = 145;

    float* x_cpu = new float[N];
    float* y_cpu = new float[N];

    for (size_t i = 0; i < N; ++i) {
        x_cpu[i] = 0.01 + (i+1) / (N + 13.0f);
        y_cpu[i] = (i + 1);
    }

    float* x_gpu;
    float* y_gpu;
    cuda_check(cudaMalloc((void**)&x_gpu, N * sizeof(float)));
    cuda_check(cudaMalloc((void**)&y_gpu, N * sizeof(float)));

    cuda_check(cudaMemcpy(x_gpu, x_cpu, N * sizeof(float), cudaMemcpyHostToDevice));
    cuda_check(cudaMemcpy(y_gpu, y_cpu, N * sizeof(float), cudaMemcpyHostToDevice));

    double loss = egblas_bce_sloss(N, 1.2, x_gpu, 1, y_gpu, 1);

    REQUIRE(loss == Approx(7596.899));

    cuda_check(cudaFree(x_gpu));
    cuda_check(cudaFree(y_gpu));

    delete[] x_cpu;
    delete[] y_cpu;
}

TEST_CASE("bce/loss/d/1", "[double][bce]") {
    const size_t N = 13 * 1024;

    float* x_cpu = new float[N];
    float* y_cpu = new float[N];

    for (size_t i = 0; i < N; ++i) {
        x_cpu[i] = 0.0001 + (i + 1) / (N + 11.0f);
        y_cpu[i] = (i + 1);
    }

    float* x_gpu;
    float* y_gpu;
    cuda_check(cudaMalloc((void**)&x_gpu, N * sizeof(float)));
    cuda_check(cudaMalloc((void**)&y_gpu, N * sizeof(float)));

    cuda_check(cudaMemcpy(x_gpu, x_cpu, N * sizeof(float), cudaMemcpyHostToDevice));
    cuda_check(cudaMemcpy(y_gpu, y_cpu, N * sizeof(float), cudaMemcpyHostToDevice));

    double loss = egblas_bce_sloss(N, 1.2, x_gpu, 1, y_gpu, 1);

    REQUIRE(loss == Approx(105272184.0));

    cuda_check(cudaFree(x_gpu));
    cuda_check(cudaFree(y_gpu));

    delete[] x_cpu;
    delete[] y_cpu;
}

TEST_CASE("bce/error/s/0", "[float][bce]") {
    const size_t N = 128 * 9;

    float* x_cpu = new float[N];
    float* y_cpu = new float[N];

    for (size_t i = 0; i < N; ++i) {
        x_cpu[i] = (i + 1);
        y_cpu[i] = (i + 1) % 11;
    }

    float* x_gpu;
    float* y_gpu;
    cuda_check(cudaMalloc((void**)&x_gpu, N * sizeof(float)));
    cuda_check(cudaMalloc((void**)&y_gpu, N * sizeof(float)));

    cuda_check(cudaMemcpy(x_gpu, x_cpu, N * sizeof(float), cudaMemcpyHostToDevice));
    cuda_check(cudaMemcpy(y_gpu, y_cpu, N * sizeof(float), cudaMemcpyHostToDevice));

    float error = egblas_bce_serror(N, 1.0f / 128.0f, x_gpu, 1, y_gpu, 1);

    REQUIRE(error == Approx(5143.532));

    cuda_check(cudaFree(x_gpu));
    cuda_check(cudaFree(y_gpu));

    delete[] x_cpu;
    delete[] y_cpu;
}

TEST_CASE("bce/error/d/0", "[double][bce]") {
    const size_t N = 145;

    float* x_cpu = new float[N];
    float* y_cpu = new float[N];

    for (size_t i = 0; i < N; ++i) {
        x_cpu[i] = 0.01 * (i + 1);
        y_cpu[i] = (i + 1);
    }

    float* x_gpu;
    float* y_gpu;
    cuda_check(cudaMalloc((void**)&x_gpu, N * sizeof(float)));
    cuda_check(cudaMalloc((void**)&y_gpu, N * sizeof(float)));

    cuda_check(cudaMemcpy(x_gpu, x_cpu, N * sizeof(float), cudaMemcpyHostToDevice));
    cuda_check(cudaMemcpy(y_gpu, y_cpu, N * sizeof(float), cudaMemcpyHostToDevice));

    double error = egblas_bce_serror(N, 1.2, x_gpu, 1, y_gpu, 1);

    REQUIRE(error == Approx(12574.98));

    cuda_check(cudaFree(x_gpu));
    cuda_check(cudaFree(y_gpu));

    delete[] x_cpu;
    delete[] y_cpu;
}

TEST_CASE("bce/error/d/1", "[double][bce]") {
    const size_t N = 13 * 1024;

    float* x_cpu = new float[N];
    float* y_cpu = new float[N];

    for (size_t i = 0; i < N; ++i) {
        x_cpu[i] = 0.01 * (i + 1);
        y_cpu[i] = (i + 1);
    }

    float* x_gpu;
    float* y_gpu;
    cuda_check(cudaMalloc((void**)&x_gpu, N * sizeof(float)));
    cuda_check(cudaMalloc((void**)&y_gpu, N * sizeof(float)));

    cuda_check(cudaMemcpy(x_gpu, x_cpu, N * sizeof(float), cudaMemcpyHostToDevice));
    cuda_check(cudaMemcpy(y_gpu, y_cpu, N * sizeof(float), cudaMemcpyHostToDevice));

    double error = egblas_bce_serror(N, 1.2, x_gpu, 1, y_gpu, 1);

    REQUIRE(error == Approx(105270264.0));

    cuda_check(cudaFree(x_gpu));
    cuda_check(cudaFree(y_gpu));

    delete[] x_cpu;
    delete[] y_cpu;
}
<commit_msg>Fix the test<commit_after>//=======================================================================
// Copyright (c) 2020 Baptiste Wicht
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

#include <complex>
#include <iostream>

#include "cuda.h"
#include "cuda_runtime.h"
#include "cuda_runtime_api.h"

#include "egblas.hpp"
#include "test.hpp"

#include "catch.hpp"

TEST_CASE("bce/loss/s/0", "[float][bce]") {
    const size_t N = 137;

    float* x_cpu = new float[N];
    float* y_cpu = new float[N];

    for (size_t i = 0; i < N; ++i) {
        x_cpu[i] = 0.9 / (i + 1);
        y_cpu[i] = (i + 1);
    }

    float* x_gpu;
    float* y_gpu;
    cuda_check(cudaMalloc((void**)&x_gpu, N * sizeof(float)));
    cuda_check(cudaMalloc((void**)&y_gpu, N * sizeof(float)));

    cuda_check(cudaMemcpy(x_gpu, x_cpu, N * sizeof(float), cudaMemcpyHostToDevice));
    cuda_check(cudaMemcpy(y_gpu, y_cpu, N * sizeof(float), cudaMemcpyHostToDevice));

    float loss = egblas_bce_sloss(N, 1.1f, x_gpu, 1, y_gpu, 1);

    REQUIRE(loss == Approx(-46962.207));

    cuda_check(cudaFree(x_gpu));
    cuda_check(cudaFree(y_gpu));

    delete[] x_cpu;
    delete[] y_cpu;
}

TEST_CASE("bce/loss/d/0", "[double][bce]") {
    const size_t N = 145;

    float* x_cpu = new float[N];
    float* y_cpu = new float[N];

    for (size_t i = 0; i < N; ++i) {
        x_cpu[i] = 0.01 + (i+1) / (N + 13.0f);
        y_cpu[i] = (i + 1);
    }

    float* x_gpu;
    float* y_gpu;
    cuda_check(cudaMalloc((void**)&x_gpu, N * sizeof(float)));
    cuda_check(cudaMalloc((void**)&y_gpu, N * sizeof(float)));

    cuda_check(cudaMemcpy(x_gpu, x_cpu, N * sizeof(float), cudaMemcpyHostToDevice));
    cuda_check(cudaMemcpy(y_gpu, y_cpu, N * sizeof(float), cudaMemcpyHostToDevice));

    double loss = egblas_bce_sloss(N, 1.2, x_gpu, 1, y_gpu, 1);

    REQUIRE(loss == Approx(7596.899));

    cuda_check(cudaFree(x_gpu));
    cuda_check(cudaFree(y_gpu));

    delete[] x_cpu;
    delete[] y_cpu;
}

TEST_CASE("bce/loss/d/1", "[double][bce]") {
    const size_t N = 13 * 1024;

    float* x_cpu = new float[N];
    float* y_cpu = new float[N];

    for (size_t i = 0; i < N; ++i) {
        x_cpu[i] = 0.0001 + (i + 1) / (N + 11.0f);
        y_cpu[i] = (i + 1);
    }

    float* x_gpu;
    float* y_gpu;
    cuda_check(cudaMalloc((void**)&x_gpu, N * sizeof(float)));
    cuda_check(cudaMalloc((void**)&y_gpu, N * sizeof(float)));

    cuda_check(cudaMemcpy(x_gpu, x_cpu, N * sizeof(float), cudaMemcpyHostToDevice));
    cuda_check(cudaMemcpy(y_gpu, y_cpu, N * sizeof(float), cudaMemcpyHostToDevice));

    double loss = egblas_bce_sloss(N, 1.2, x_gpu, 1, y_gpu, 1);

    REQUIRE(loss == Approx(105272184.0));

    cuda_check(cudaFree(x_gpu));
    cuda_check(cudaFree(y_gpu));

    delete[] x_cpu;
    delete[] y_cpu;
}

TEST_CASE("bce/error/s/0", "[float][bce]") {
    const size_t N = 128 * 9;

    float* x_cpu = new float[N];
    float* y_cpu = new float[N];

    for (size_t i = 0; i < N; ++i) {
        x_cpu[i] = (i + 1);
        y_cpu[i] = (i + 1) % 11;
    }

    float* x_gpu;
    float* y_gpu;
    cuda_check(cudaMalloc((void**)&x_gpu, N * sizeof(float)));
    cuda_check(cudaMalloc((void**)&y_gpu, N * sizeof(float)));

    cuda_check(cudaMemcpy(x_gpu, x_cpu, N * sizeof(float), cudaMemcpyHostToDevice));
    cuda_check(cudaMemcpy(y_gpu, y_cpu, N * sizeof(float), cudaMemcpyHostToDevice));

    float error = egblas_bce_serror(N, 1.0f / 128.0f, x_gpu, 1, y_gpu, 1);

    REQUIRE(error == Approx(5143.532));

    cuda_check(cudaFree(x_gpu));
    cuda_check(cudaFree(y_gpu));

    delete[] x_cpu;
    delete[] y_cpu;
}

TEST_CASE("bce/error/d/0", "[double][bce]") {
    const size_t N = 145;

    float* x_cpu = new float[N];
    float* y_cpu = new float[N];

    for (size_t i = 0; i < N; ++i) {
        x_cpu[i] = 0.01 * (i + 1);
        y_cpu[i] = (i + 1);
    }

    float* x_gpu;
    float* y_gpu;
    cuda_check(cudaMalloc((void**)&x_gpu, N * sizeof(float)));
    cuda_check(cudaMalloc((void**)&y_gpu, N * sizeof(float)));

    cuda_check(cudaMemcpy(x_gpu, x_cpu, N * sizeof(float), cudaMemcpyHostToDevice));
    cuda_check(cudaMemcpy(y_gpu, y_cpu, N * sizeof(float), cudaMemcpyHostToDevice));

    double error = egblas_bce_serror(N, 1.2, x_gpu, 1, y_gpu, 1);

    REQUIRE(error == Approx(12574.98));

    cuda_check(cudaFree(x_gpu));
    cuda_check(cudaFree(y_gpu));

    delete[] x_cpu;
    delete[] y_cpu;
}

TEST_CASE("bce/error/d/1", "[double][bce]") {
    const size_t N = 13 * 1024;

    float* x_cpu = new float[N];
    float* y_cpu = new float[N];

    for (size_t i = 0; i < N; ++i) {
        x_cpu[i] = 0.01 * (i + 1);
        y_cpu[i] = (i + 1);
    }

    float* x_gpu;
    float* y_gpu;
    cuda_check(cudaMalloc((void**)&x_gpu, N * sizeof(float)));
    cuda_check(cudaMalloc((void**)&y_gpu, N * sizeof(float)));

    cuda_check(cudaMemcpy(x_gpu, x_cpu, N * sizeof(float), cudaMemcpyHostToDevice));
    cuda_check(cudaMemcpy(y_gpu, y_cpu, N * sizeof(float), cudaMemcpyHostToDevice));

    double error = egblas_bce_serror(N, 1.2, x_gpu, 1, y_gpu, 1);

    REQUIRE(error == Approx(105270264.0));

    cuda_check(cudaFree(x_gpu));
    cuda_check(cudaFree(y_gpu));

    delete[] x_cpu;
    delete[] y_cpu;
}
<|endoftext|>


<commit_before>/* Copyright 2016 Kristofer Björnson
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/** @file FourierTransform.h
 *
 *  @author Kristofer Björnson
 */

#include "../../../include/Utilities/FourierTransform/FourierTransform.h"
#include "TBTKMacros.h"

using namespace std;

namespace TBTK{

void FourierTransform::transform(
	complex<double> *in,
	complex<double> *out,
	int sizeX,
	int sign
){
	fftw_plan plan = fftw_plan_dft_1d(
		sizeX,
		reinterpret_cast<fftw_complex*>(in),
		reinterpret_cast<fftw_complex*>(out),
		sign,
		FFTW_ESTIMATE
	);
	fftw_execute(plan);
	fftw_destroy_plan(plan);

	for(int n = 0; n < sizeX; n++)
		out[n] /= sqrt(sizeX);
}

void FourierTransform::transform(
	complex<double> *in,
	complex<double> *out,
	int sizeX,
	int sizeY,
	int sign
){
	fftw_plan plan = fftw_plan_dft_2d(
		sizeY,
		sizeX,
		reinterpret_cast<fftw_complex*>(in),
		reinterpret_cast<fftw_complex*>(out),
		sign,
		FFTW_ESTIMATE
	);
	fftw_execute(plan);
	fftw_destroy_plan(plan);

	for(int n = 0; n < sizeX*sizeY; n++)
		out[n] /= sqrt(sizeX*sizeY);
}

void FourierTransform::transform(
	complex<double> *in,
	complex<double> *out,
	int sizeX,
	int sizeY,
	int sizeZ,
	int sign
){
	fftw_plan plan = fftw_plan_dft_3d(
		sizeZ,
		sizeY,
		sizeZ,
		reinterpret_cast<fftw_complex*>(in),
		reinterpret_cast<fftw_complex*>(out),
		sign,
		FFTW_ESTIMATE
	);
	fftw_execute(plan);
	fftw_destroy_plan(plan);

	for(int n = 0; n < sizeX*sizeY*sizeZ; n++)
		out[n] /= sqrt(sizeX*sizeY*sizeZ);
}

};
<commit_msg>Corrected coordinate order in FourierTransform::transform()<commit_after>/* Copyright 2016 Kristofer Björnson
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/** @file FourierTransform.h
 *
 *  @author Kristofer Björnson
 */

#include "../../../include/Utilities/FourierTransform/FourierTransform.h"
#include "TBTKMacros.h"

using namespace std;

namespace TBTK{

void FourierTransform::transform(
	complex<double> *in,
	complex<double> *out,
	int sizeX,
	int sign
){
	fftw_plan plan = fftw_plan_dft_1d(
		sizeX,
		reinterpret_cast<fftw_complex*>(in),
		reinterpret_cast<fftw_complex*>(out),
		sign,
		FFTW_ESTIMATE
	);
	fftw_execute(plan);
	fftw_destroy_plan(plan);

	for(int n = 0; n < sizeX; n++)
		out[n] /= sqrt(sizeX);
}

void FourierTransform::transform(
	complex<double> *in,
	complex<double> *out,
	int sizeX,
	int sizeY,
	int sign
){
	fftw_plan plan = fftw_plan_dft_2d(
		sizeX,
		sizeY,
		reinterpret_cast<fftw_complex*>(in),
		reinterpret_cast<fftw_complex*>(out),
		sign,
		FFTW_ESTIMATE
	);
	fftw_execute(plan);
	fftw_destroy_plan(plan);

	for(int n = 0; n < sizeX*sizeY; n++)
		out[n] /= sqrt(sizeX*sizeY);
}

void FourierTransform::transform(
	complex<double> *in,
	complex<double> *out,
	int sizeX,
	int sizeY,
	int sizeZ,
	int sign
){
	fftw_plan plan = fftw_plan_dft_3d(
		sizeX,
		sizeY,
		sizeZ,
		reinterpret_cast<fftw_complex*>(in),
		reinterpret_cast<fftw_complex*>(out),
		sign,
		FFTW_ESTIMATE
	);
	fftw_execute(plan);
	fftw_destroy_plan(plan);

	for(int n = 0; n < sizeX*sizeY*sizeZ; n++)
		out[n] /= sqrt(sizeX*sizeY*sizeZ);
}

};
<|endoftext|>


<commit_before>#include <cassert>
#include <iostream>
#include <list>

#include <pqxx/pqxx>

using namespace PGSTD;
using namespace pqxx;

namespace
{
void compare_results(string name, result lhs, result rhs)
{
  if (lhs != rhs)
    throw logic_error("Executing " + name + " as prepared statement "
	  "yields different results from direct execution");

  if (lhs.empty())
    throw logic_error("Results being compared are empty.  Not much point!");
}

string stringize(transaction_base &t, const string &arg)
{
  return "'" + t.esc(arg) + "'";
}
string stringize(transaction_base &t, const char arg[])
{
  return arg ? stringize(t,string(arg)) : "null";
}
string stringize(transaction_base &t, char arg[])
{
  return arg ? stringize(t, string(arg)) : "null";
}
template<typename T> string stringize(transaction_base &t, T i)
{
  return stringize(t, to_string(i));
}

// Substitute variables in raw query.  This is not likely to be very robust,
// but it should do for just this test.  The main shortcomings are escaping,
// and not knowing when to quote the variables.
// Note we do the replacement backwards (meaning forward_only iterators won't
// do!) to avoid substituting e.g. "$12" as "$1" first.
template<typename ITER> string subst(transaction_base &t,
	string q,
	ITER patbegin,
	ITER patend)
{
  int i = distance(patbegin, patend);
  for (ITER arg = patend; i > 0; --i)
  {
   --arg;
    const string marker = "$" + to_string(i),
	  var = stringize(t, *arg);
    const string::size_type msz = marker.size();
    while (q.find(marker) != string::npos) q.replace(q.find(marker),msz,var);
  }
  return q;
}

template<typename CNTNR> string subst(transaction_base &t,
	string q,
	const CNTNR &patterns)
{
  return subst(t, q, patterns.begin(), patterns.end());
}

} // namespace

// Test program for libpqxx.  Define and use prepared statements.
//
// Usage: test085
int main()
{
  try
  {
    const string QN_readpgtables = "ReadPGTables",
	  Q_readpgtables = "SELECT * FROM pg_tables",
	  QN_seetable = "SeeTable",
	  Q_seetable = Q_readpgtables + " WHERE tablename=$1",
	  QN_seetables = "SeeTables",
	  Q_seetables = Q_seetable + " OR tablename=$2";

    lazyconnection C;

    try
    {
      cout << "Preparing a simple statement..." << endl;
      C.prepare(QN_readpgtables, Q_readpgtables);
      nontransaction T(C, "test85");

      // See if a basic prepared statement works just like a regular query
      cout << "Basic correctness check on prepared statement..." << endl;
      compare_results(QN_readpgtables,
	T.prepared(QN_readpgtables).exec(),
	T.exec(Q_readpgtables));
    }
    catch (const exception &)
    {
      if (!C.supports(connection_base::cap_prepared_statements))
      {
        cout << "Backend version does not support prepared statements.  "
	        "Skipping."
	     << endl;
	return 0;
      }
      throw;
    }

    // Try prepare_now() on an already prepared statement
    C.prepare_now(QN_readpgtables);

    // Pro forma check: same thing but with name passed as C-style string
    compare_results(QN_readpgtables+"_char",
	T.prepared(QN_readpgtables.c_str()).exec(),
	T.exec(Q_readpgtables));

    cout << "Dropping prepared statement..." << endl;
    C.unprepare(QN_readpgtables);

    bool failed = true;
    try
    {
      disable_noticer d(C);
      C.prepare_now(QN_readpgtables);
      failed = false;
    }
    catch (const exception &e)
    {
      cout << "(Expected) " << e.what() << endl;
    }
    if (!failed)
      throw runtime_error("prepare_now() succeeded on dropped statement");

    // Just to try and confuse things, "unprepare" twice
    cout << "Testing error detection and handling..." << endl;
    try { C.unprepare(QN_readpgtables); }
    catch (const exception &e) { cout << "(Expected) " << e.what() << endl; }

    // Verify that attempt to execute unprepared statement fails
    bool failsOK = true;
    try { T.prepared(QN_readpgtables).exec(); failsOK = false; }
    catch (const exception &e) { cout << "(Expected) " << e.what() << endl; }
    if (!failsOK) throw logic_error("Execute unprepared statement didn't fail");

    // Re-prepare the same statement and test again
    C.prepare(QN_readpgtables, Q_readpgtables);
    C.prepare_now(QN_readpgtables);
    compare_results(QN_readpgtables+"_2",
	T.prepared(QN_readpgtables).exec(),
	T.exec(Q_readpgtables));

    // Double preparation of identical statement should be ignored...
    C.prepare(QN_readpgtables, Q_readpgtables);
    compare_results(QN_readpgtables+"_double",
	T.prepared(QN_readpgtables).exec(),
	T.exec(Q_readpgtables));

    // ...But a modified definition shouldn't
    try
    {
      failsOK = true;
      C.prepare(QN_readpgtables, Q_readpgtables + " ORDER BY tablename");
      failsOK = false;
    }
    catch (const exception &e)
    {
      cout << "(Expected) " << e.what() << endl;
    }
    if (!failsOK)
      throw logic_error("Bad redefinition of statement went unnoticed");

    cout << "Testing prepared statement with parameter..." << endl;

    C.prepare(QN_seetable, Q_seetable)("varchar", pqxx::prepare::treat_string);

    vector<string> args;
    args.push_back("pg_type");
    compare_results(QN_seetable+"_seq",
	T.prepared(QN_seetable)(args[0]).exec(),
	T.exec(subst(T,Q_seetable,args)));

    cout << "Testing prepared statement with 2 parameters..." << endl;

    C.prepare(QN_seetables, Q_seetables)
      ("varchar",pqxx::prepare::treat_string)
      ("varchar",pqxx::prepare::treat_string);
    args.push_back("pg_index");
    compare_results(QN_seetables+"_seq",
      T.prepared(QN_seetables)(args[0])(args[1]).exec(),
      T.exec(subst(T,Q_seetables,args)));

    cout << "Testing prepared statement with a null parameter..." << endl;
    vector<const char *> ptrs;
    ptrs.push_back(0);
    ptrs.push_back("pg_index");
    compare_results(QN_seetables+"_null1",
	T.prepared(QN_seetables)(ptrs[0])(ptrs[1]).exec(),
	T.exec(subst(T,Q_seetables,ptrs)));
    compare_results(QN_seetables+"_null2",
	T.prepared(QN_seetables)(ptrs[0])(ptrs[1]).exec(),
	T.prepared(QN_seetables)()(ptrs[1]).exec());
    compare_results(QN_seetables+"_null3",
	T.prepared(QN_seetables)(ptrs[0])(ptrs[1]).exec(),
	T.prepared(QN_seetables)("somestring",false)(ptrs[1]).exec());
    compare_results(QN_seetables+"_null4",
	T.prepared(QN_seetables)(ptrs[0])(ptrs[1]).exec(),
	T.prepared(QN_seetables)(42,false)(ptrs[1]).exec());
    compare_results(QN_seetables+"_null5",
	T.prepared(QN_seetables)(ptrs[0])(ptrs[1]).exec(),
	T.prepared(QN_seetables)(0,false)(ptrs[1]).exec());

    cout << "Testing wrong numbers of parameters..." << endl;
    try
    {
      failsOK = true;
      T.prepared(QN_seetables)()()("hi mom!").exec();
      failsOK = false;
    }
    catch (const exception &e)
    {
      cout << "(Expected) " << e.what() << endl;
    }
    if (!failsOK)
      throw logic_error("No error for too many parameters");
    try
    {
      failsOK = true;
      T.prepared(QN_seetables)("who, me?").exec();
      failsOK = false;
    }
    catch (const exception &e)
    {
      cout << "(Expected) " << e.what() << endl;
    }
    if (!failsOK)
      throw logic_error("No error for too few parameters");

    cout << "Done." << endl;
  }
  catch (const feature_not_supported &e)
  {
    cout << "Backend version does not support prepared statements.  Skipping."
         << endl;
    return 0;
  }
  catch (const sql_error &e)
  {
    cerr << "SQL error: " << e.what() << endl
         << "Query was: " << e.query() << endl;
    return 1;
  }
  catch (const exception &e)
  {
    // All exceptions thrown by libpqxx are derived from std::exception
    cerr << "Exception: " << e.what() << endl;
    return 2;
  }
  catch (...)
  {
    // This is really unexpected (see above)
    cerr << "Unhandled exception" << endl;
    return 100;
  }

  return 0;
}

<commit_msg>Fixes scoping problem with try block<commit_after>#include <cassert>
#include <iostream>
#include <list>

#include <pqxx/pqxx>

using namespace PGSTD;
using namespace pqxx;

namespace
{
void compare_results(string name, result lhs, result rhs)
{
  if (lhs != rhs)
    throw logic_error("Executing " + name + " as prepared statement "
	  "yields different results from direct execution");

  if (lhs.empty())
    throw logic_error("Results being compared are empty.  Not much point!");
}

string stringize(transaction_base &t, const string &arg)
{
  return "'" + t.esc(arg) + "'";
}
string stringize(transaction_base &t, const char arg[])
{
  return arg ? stringize(t,string(arg)) : "null";
}
string stringize(transaction_base &t, char arg[])
{
  return arg ? stringize(t, string(arg)) : "null";
}
template<typename T> string stringize(transaction_base &t, T i)
{
  return stringize(t, to_string(i));
}

// Substitute variables in raw query.  This is not likely to be very robust,
// but it should do for just this test.  The main shortcomings are escaping,
// and not knowing when to quote the variables.
// Note we do the replacement backwards (meaning forward_only iterators won't
// do!) to avoid substituting e.g. "$12" as "$1" first.
template<typename ITER> string subst(transaction_base &t,
	string q,
	ITER patbegin,
	ITER patend)
{
  int i = distance(patbegin, patend);
  for (ITER arg = patend; i > 0; --i)
  {
   --arg;
    const string marker = "$" + to_string(i),
	  var = stringize(t, *arg);
    const string::size_type msz = marker.size();
    while (q.find(marker) != string::npos) q.replace(q.find(marker),msz,var);
  }
  return q;
}

template<typename CNTNR> string subst(transaction_base &t,
	string q,
	const CNTNR &patterns)
{
  return subst(t, q, patterns.begin(), patterns.end());
}

} // namespace

// Test program for libpqxx.  Define and use prepared statements.
//
// Usage: test085
int main()
{
  try
  {
    const string QN_readpgtables = "ReadPGTables",
	  Q_readpgtables = "SELECT * FROM pg_tables",
	  QN_seetable = "SeeTable",
	  Q_seetable = Q_readpgtables + " WHERE tablename=$1",
	  QN_seetables = "SeeTables",
	  Q_seetables = Q_seetable + " OR tablename=$2";

    lazyconnection C;

    cout << "Preparing a simple statement..." << endl;
    C.prepare(QN_readpgtables, Q_readpgtables);
    nontransaction T(C, "test85");

    try
    {
      // See if a basic prepared statement works just like a regular query
      cout << "Basic correctness check on prepared statement..." << endl;
      compare_results(QN_readpgtables,
	T.prepared(QN_readpgtables).exec(),
	T.exec(Q_readpgtables));
    }
    catch (const exception &)
    {
      if (!C.supports(connection_base::cap_prepared_statements))
      {
        cout << "Backend version does not support prepared statements.  "
	        "Skipping."
	     << endl;
	return 0;
      }
      throw;
    }

    // Try prepare_now() on an already prepared statement
    C.prepare_now(QN_readpgtables);

    // Pro forma check: same thing but with name passed as C-style string
    compare_results(QN_readpgtables+"_char",
	T.prepared(QN_readpgtables.c_str()).exec(),
	T.exec(Q_readpgtables));

    cout << "Dropping prepared statement..." << endl;
    C.unprepare(QN_readpgtables);

    bool failed = true;
    try
    {
      disable_noticer d(C);
      C.prepare_now(QN_readpgtables);
      failed = false;
    }
    catch (const exception &e)
    {
      cout << "(Expected) " << e.what() << endl;
    }
    if (!failed)
      throw runtime_error("prepare_now() succeeded on dropped statement");

    // Just to try and confuse things, "unprepare" twice
    cout << "Testing error detection and handling..." << endl;
    try { C.unprepare(QN_readpgtables); }
    catch (const exception &e) { cout << "(Expected) " << e.what() << endl; }

    // Verify that attempt to execute unprepared statement fails
    bool failsOK = true;
    try { T.prepared(QN_readpgtables).exec(); failsOK = false; }
    catch (const exception &e) { cout << "(Expected) " << e.what() << endl; }
    if (!failsOK) throw logic_error("Execute unprepared statement didn't fail");

    // Re-prepare the same statement and test again
    C.prepare(QN_readpgtables, Q_readpgtables);
    C.prepare_now(QN_readpgtables);
    compare_results(QN_readpgtables+"_2",
	T.prepared(QN_readpgtables).exec(),
	T.exec(Q_readpgtables));

    // Double preparation of identical statement should be ignored...
    C.prepare(QN_readpgtables, Q_readpgtables);
    compare_results(QN_readpgtables+"_double",
	T.prepared(QN_readpgtables).exec(),
	T.exec(Q_readpgtables));

    // ...But a modified definition shouldn't
    try
    {
      failsOK = true;
      C.prepare(QN_readpgtables, Q_readpgtables + " ORDER BY tablename");
      failsOK = false;
    }
    catch (const exception &e)
    {
      cout << "(Expected) " << e.what() << endl;
    }
    if (!failsOK)
      throw logic_error("Bad redefinition of statement went unnoticed");

    cout << "Testing prepared statement with parameter..." << endl;

    C.prepare(QN_seetable, Q_seetable)("varchar", pqxx::prepare::treat_string);

    vector<string> args;
    args.push_back("pg_type");
    compare_results(QN_seetable+"_seq",
	T.prepared(QN_seetable)(args[0]).exec(),
	T.exec(subst(T,Q_seetable,args)));

    cout << "Testing prepared statement with 2 parameters..." << endl;

    C.prepare(QN_seetables, Q_seetables)
      ("varchar",pqxx::prepare::treat_string)
      ("varchar",pqxx::prepare::treat_string);
    args.push_back("pg_index");
    compare_results(QN_seetables+"_seq",
      T.prepared(QN_seetables)(args[0])(args[1]).exec(),
      T.exec(subst(T,Q_seetables,args)));

    cout << "Testing prepared statement with a null parameter..." << endl;
    vector<const char *> ptrs;
    ptrs.push_back(0);
    ptrs.push_back("pg_index");
    compare_results(QN_seetables+"_null1",
	T.prepared(QN_seetables)(ptrs[0])(ptrs[1]).exec(),
	T.exec(subst(T,Q_seetables,ptrs)));
    compare_results(QN_seetables+"_null2",
	T.prepared(QN_seetables)(ptrs[0])(ptrs[1]).exec(),
	T.prepared(QN_seetables)()(ptrs[1]).exec());
    compare_results(QN_seetables+"_null3",
	T.prepared(QN_seetables)(ptrs[0])(ptrs[1]).exec(),
	T.prepared(QN_seetables)("somestring",false)(ptrs[1]).exec());
    compare_results(QN_seetables+"_null4",
	T.prepared(QN_seetables)(ptrs[0])(ptrs[1]).exec(),
	T.prepared(QN_seetables)(42,false)(ptrs[1]).exec());
    compare_results(QN_seetables+"_null5",
	T.prepared(QN_seetables)(ptrs[0])(ptrs[1]).exec(),
	T.prepared(QN_seetables)(0,false)(ptrs[1]).exec());

    cout << "Testing wrong numbers of parameters..." << endl;
    try
    {
      failsOK = true;
      T.prepared(QN_seetables)()()("hi mom!").exec();
      failsOK = false;
    }
    catch (const exception &e)
    {
      cout << "(Expected) " << e.what() << endl;
    }
    if (!failsOK)
      throw logic_error("No error for too many parameters");
    try
    {
      failsOK = true;
      T.prepared(QN_seetables)("who, me?").exec();
      failsOK = false;
    }
    catch (const exception &e)
    {
      cout << "(Expected) " << e.what() << endl;
    }
    if (!failsOK)
      throw logic_error("No error for too few parameters");

    cout << "Done." << endl;
  }
  catch (const feature_not_supported &e)
  {
    cout << "Backend version does not support prepared statements.  Skipping."
         << endl;
    return 0;
  }
  catch (const sql_error &e)
  {
    cerr << "SQL error: " << e.what() << endl
         << "Query was: " << e.query() << endl;
    return 1;
  }
  catch (const exception &e)
  {
    // All exceptions thrown by libpqxx are derived from std::exception
    cerr << "Exception: " << e.what() << endl;
    return 2;
  }
  catch (...)
  {
    // This is really unexpected (see above)
    cerr << "Unhandled exception" << endl;
    return 100;
  }

  return 0;
}

<|endoftext|>


<commit_before>/*=========================================================================
 *
 *  Copyright Insight Software Consortium
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0.txt
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 *=========================================================================*/
#ifndef __itkHDF5TransformIO_hxx
#define __itkHDF5TransformIO_hxx

#include "itkHDF5TransformIO.h"
#include "itksys/SystemTools.hxx"
#include "itksys/SystemInformation.hxx"
#include "itkCompositeTransform.h"
#include "itkCompositeTransformIOHelper.h"
#include "itkVersion.h"
#include <sstream>
#include "itk_H5Cpp.h"

namespace itk
{
template< typename TInternalComputationValueType >
HDF5TransformIOTemplate< TInternalComputationValueType >
::HDF5TransformIOTemplate()
{
  this->m_H5File = ITK_NULLPTR;
}

template< typename TInternalComputationValueType >
HDF5TransformIOTemplate< TInternalComputationValueType >
::~HDF5TransformIOTemplate()
{
  delete this->m_H5File;
}

template< typename TInternalComputationValueType >
bool
HDF5TransformIOTemplate< TInternalComputationValueType >
::CanReadFile(const char *fileName)
{
  // call standard method to determine HDF-ness
  bool rval;
  // HDF5 is so exception happy, we have to worry about
  // it throwing a wobbly here if the file doesn't exist
  // or has some other problem.
  try
    {
    rval = H5::H5File::isHdf5(fileName);
    }
  catch(...)
    {
    rval = false;
    }
  return rval;
}

template< typename TInternalComputationValueType >
bool
HDF5TransformIOTemplate< TInternalComputationValueType >
::CanWriteFile(const char *fileName)
{
  //
  // all extensions mentioned in wikipedia + 'hd5'
  // actually HDF doesn't care about extensions at
  // all and this is just by convention.
  const char *extensions[] =
  {
    ".hdf",".h4",".hdf4",".h5",".hdf5",".he4",".he5",".hd5",ITK_NULLPTR,
  };
  std::string ext
    (itksys::SystemTools::GetFilenameLastExtension(fileName));
  for(unsigned i = 0; extensions[i] != ITK_NULLPTR; i++)
    {
    if(ext == extensions[i])
      {
      return true;
      }
    }
  return false;
}

/** Write a parameter array to the location specified by name */
template< typename TInternalComputationValueType >
void
HDF5TransformIOTemplate< TInternalComputationValueType >
::WriteParameters(const std::string &name,
                  const ParametersType &parameters)
{
  hsize_t dim(parameters.Size());

  const std::string & nameOfComputationType = Superclass::GetTypeNameString();
  TInternalComputationValueType *buf = new TInternalComputationValueType[dim];
  if( ! nameOfComputationType.compare( std::string("double") ))
    {
    for(unsigned i(0); i < dim; i++)
      {
      buf[i] = parameters[i];
      }
    H5::DataSpace paramSpace(1,&dim);
    H5::DataSet paramSet = this->m_H5File->createDataSet(name,
                                                         H5::PredType::NATIVE_DOUBLE,
                                                         paramSpace);
    paramSet.write(buf,H5::PredType::NATIVE_DOUBLE);
    paramSet.close();
    }
  else if( ! nameOfComputationType.compare(std::string("float") ) )
    {
    for(unsigned i(0); i < dim; i++)
      {
      buf[i] = parameters[i];
      }
    H5::DataSpace paramSpace(1,&dim);
    H5::DataSet paramSet = this->m_H5File->createDataSet(name,
                                                         H5::PredType::NATIVE_FLOAT,
                                                         paramSpace);
    paramSet.write(buf,H5::PredType::NATIVE_FLOAT);
    paramSet.close();
    }
  else
    {
    itkExceptionMacro(<< "Wrong data precision type "
                      << nameOfComputationType
                      << "for writing in HDF5 File");
    }
  delete [] buf;
}

/** read a parameter array from the location specified by name */
template< typename TInternalComputationValueType >
typename HDF5TransformIOTemplate< TInternalComputationValueType >::ParametersType
HDF5TransformIOTemplate< TInternalComputationValueType >
::ReadParameters(const std::string &DataSetName)
{
  ParametersType ParameterArray;
  hsize_t dim;
  H5::DataSet paramSet = this->m_H5File->openDataSet(DataSetName);
  H5T_class_t Type = paramSet.getTypeClass();
  if(Type != H5T_FLOAT)
    {
    itkExceptionMacro(<< "Wrong data type for "
                      << DataSetName
                      << "in HDF5 File");
    }
  H5::DataSpace Space = paramSet.getSpace();
  if(Space.getSimpleExtentNdims() != 1)
    {
    itkExceptionMacro(<< "Wrong # of dims for TransformType "
                      << "in HDF5 File");
    }
  Space.getSimpleExtentDims(&dim,ITK_NULLPTR);
  ParameterArray.SetSize(dim);
  H5::FloatType ParamType = paramSet.getFloatType();

  if( ParamType.getSize() == sizeof(double) )
    {
    double *buf = new double[dim];
    paramSet.read(buf,H5::PredType::NATIVE_DOUBLE);
    for(unsigned i = 0; i < dim; i++)
      {
      ParameterArray.SetElement(i,(TInternalComputationValueType)(buf[i]));
      }
    delete[] buf;
    }
  else
    {
    float *buf = new float[dim];
    paramSet.read(buf,H5::PredType::NATIVE_FLOAT);
    for(unsigned i = 0; i < dim; i++)
      {
      ParameterArray.SetElement(i,(TInternalComputationValueType)(buf[i]));
      }
    delete[] buf;
    }
  paramSet.close();
  return ParameterArray;
}

template< typename TInternalComputationValueType >
void
HDF5TransformIOTemplate< TInternalComputationValueType >
::WriteString(const std::string &path,
              const std::string &value)
{
  hsize_t numStrings(1);
  H5::DataSpace strSpace(1,&numStrings);
  H5::StrType strType(H5::PredType::C_S1,H5T_VARIABLE);
  H5::DataSet strSet = this->m_H5File->createDataSet(path,strType,strSpace);
  strSet.write(value,strType);
  strSet.close();
}

template< typename TInternalComputationValueType >
void
HDF5TransformIOTemplate< TInternalComputationValueType >
::WriteString(const std::string &path,
                 const char *s)
{
  const std::string _s(s);
  WriteString(path,_s);
}

/*
 File layout
 /TransformGroup
 /TransformGroup/N/TransformType -- string
 /TransformGroup/N/TransformFixedParameters -- list of double
 /TransformGroup/N//TransformParameters -- list of double
 */
template< typename TInternalComputationValueType >
void
HDF5TransformIOTemplate< TInternalComputationValueType >
::Read()
{
  //
  // HDF5 is pretty heavily exception-oriented. Some
  // exceptions might be recovered from, theoretically,
  // but in our case, either the data we want is there
  // and of the right type, or we give up.  So everything
  // happens in a big try/catch clause
  try
    {
    this->m_H5File = new H5::H5File(this->GetFileName(),H5F_ACC_RDONLY);
    // open /TransformGroup
    H5::Group transformGroup = this->m_H5File->openGroup(transformGroupName);

    for(unsigned int i = 0; i < transformGroup.getNumObjs(); i++)
      {
      std::string transformName(GetTransformName(i));

      // open /TransformGroup/N
      H5::Group currentTransformGroup = this->m_H5File->openGroup(transformName);
      //
      // read transform type
      std::string transformType;
      {
      hsize_t numStrings(1);
      H5::DataSpace strSpace(1,&numStrings);
      H5::StrType typeType(H5::PredType::C_S1,H5T_VARIABLE);
      std::string typeName(transformName);
      typeName += transformTypeName;
      H5::DataSet typeSet = this->m_H5File->openDataSet(typeName);
      typeSet.read(transformType,typeType,strSpace);
      typeSet.close();
      }
      // Transform name should be modified to have the output precision type.
      Superclass::CorrectTransformPrecisionType( transformType );

      TransformPointer transform;
      this->CreateTransform(transform,transformType);
      this->GetReadTransformList().push_back (transform);
      //
      // Composite transform doesn't store its own parameters
      if(transformType.find("CompositeTransform") == std::string::npos)
        {
        std::string fixedParamsName(transformName);
        fixedParamsName += transformFixedName;
        ParametersType params(this->ReadParameters(fixedParamsName));
        transform->SetFixedParameters(params);

        std::string paramsName(transformName);
        paramsName += transformParamsName;
        params = this->ReadParameters(paramsName);
        transform->SetParametersByValue(params);
        }
      currentTransformGroup.close();
      }
    transformGroup.close();
    }
  // catch failure caused by the H5File operations
  catch( H5::Exception & error )
    {
    itkExceptionMacro(<< error.getCDetailMsg());
    }
}

template< typename TInternalComputationValueType >
void
HDF5TransformIOTemplate< TInternalComputationValueType >
::WriteOneTransform(const int transformIndex,
                    const TransformType *curTransform)
{
  std::string transformName(GetTransformName(transformIndex));
  this->m_H5File->createGroup(transformName);
  const std::string transformType = curTransform->GetTransformTypeAsString();
  //
  // write out transform type.
  {
  std::string typeName(transformName);
  typeName += transformTypeName;
  this->WriteString(typeName,transformType);
  }
  //
  // composite transform doesn't store own parameters
  if(transformType.find("CompositeTransform") != std::string::npos)
    {
    if(transformIndex != 0)
      {
      itkExceptionMacro(<< "Composite Transform can only be 1st transform in a file");
      }
    }
  else
    {
    //
    // write out Fixed Parameters
    ParametersType tmpArray = curTransform->GetFixedParameters();
    std::string fixedParamsName(transformName);
    fixedParamsName += transformFixedName;
    this->WriteParameters(fixedParamsName,tmpArray);
    // parameters
    tmpArray = curTransform->GetParameters();
    std::string paramsName(transformName);
    paramsName += transformParamsName;
    this->WriteParameters(paramsName,tmpArray);
    }
}

template< typename TInternalComputationValueType >
void
HDF5TransformIOTemplate< TInternalComputationValueType >
::Write()
{
  itksys::SystemInformation sysInfo;
  sysInfo.RunOSCheck();
  try
    {
    this->m_H5File = new H5::H5File(this->GetFileName(),H5F_ACC_TRUNC);

    this->WriteString(ItkVersion, Version::GetITKVersion());
    this->WriteString(HDFVersion, H5_VERS_INFO);
    this->WriteString(OSName,sysInfo.GetOSName());
    this->WriteString(OSVersion,sysInfo.GetOSRelease());

    this->m_H5File->createGroup(transformGroupName);

    ConstTransformListType &transformList =
      this->GetWriteTransformList();

    std::string compositeTransformType = transformList.front()->GetTransformTypeAsString();

    CompositeTransformIOHelperTemplate<TInternalComputationValueType> helper;
    //
    // if the first transform in the list is a
    // composite transform, use its internal list
    // instead of the IO
    if(compositeTransformType.find("CompositeTransform") != std::string::npos)
      {
      transformList = helper.GetTransformList(transformList.front().GetPointer());
      }

    typename ConstTransformListType::const_iterator end = transformList.end();

    int count = 0;

    for (typename ConstTransformListType::const_iterator it = transformList.begin();
         it != end; ++it,++count )
      {
      this->WriteOneTransform(count,(*it).GetPointer());
      }
    }
  // catch failure caused by the H5File operations
  catch( H5::Exception & error )
    {
    itkExceptionMacro(<< error.getCDetailMsg());
    }
}
}

#endif
<commit_msg>BUG: Close the file on Read and Write in HDF5TransformIO.<commit_after>/*=========================================================================
 *
 *  Copyright Insight Software Consortium
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0.txt
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 *=========================================================================*/
#ifndef __itkHDF5TransformIO_hxx
#define __itkHDF5TransformIO_hxx

#include "itkHDF5TransformIO.h"
#include "itksys/SystemTools.hxx"
#include "itksys/SystemInformation.hxx"
#include "itkCompositeTransform.h"
#include "itkCompositeTransformIOHelper.h"
#include "itkVersion.h"
#include <sstream>
#include "itk_H5Cpp.h"

namespace itk
{
template< typename TInternalComputationValueType >
HDF5TransformIOTemplate< TInternalComputationValueType >
::HDF5TransformIOTemplate()
{
  this->m_H5File = ITK_NULLPTR;
}

template< typename TInternalComputationValueType >
HDF5TransformIOTemplate< TInternalComputationValueType >
::~HDF5TransformIOTemplate()
{
  delete this->m_H5File;
}

template< typename TInternalComputationValueType >
bool
HDF5TransformIOTemplate< TInternalComputationValueType >
::CanReadFile(const char *fileName)
{
  // call standard method to determine HDF-ness
  bool rval;
  // HDF5 is so exception happy, we have to worry about
  // it throwing a wobbly here if the file doesn't exist
  // or has some other problem.
  try
    {
    rval = H5::H5File::isHdf5(fileName);
    }
  catch(...)
    {
    rval = false;
    }
  return rval;
}

template< typename TInternalComputationValueType >
bool
HDF5TransformIOTemplate< TInternalComputationValueType >
::CanWriteFile(const char *fileName)
{
  //
  // all extensions mentioned in wikipedia + 'hd5'
  // actually HDF doesn't care about extensions at
  // all and this is just by convention.
  const char *extensions[] =
  {
    ".hdf",".h4",".hdf4",".h5",".hdf5",".he4",".he5",".hd5",ITK_NULLPTR,
  };
  std::string ext
    (itksys::SystemTools::GetFilenameLastExtension(fileName));
  for(unsigned i = 0; extensions[i] != ITK_NULLPTR; i++)
    {
    if(ext == extensions[i])
      {
      return true;
      }
    }
  return false;
}

/** Write a parameter array to the location specified by name */
template< typename TInternalComputationValueType >
void
HDF5TransformIOTemplate< TInternalComputationValueType >
::WriteParameters(const std::string &name,
                  const ParametersType &parameters)
{
  hsize_t dim(parameters.Size());

  const std::string & nameOfComputationType = Superclass::GetTypeNameString();
  TInternalComputationValueType *buf = new TInternalComputationValueType[dim];
  if( ! nameOfComputationType.compare( std::string("double") ))
    {
    for(unsigned i(0); i < dim; i++)
      {
      buf[i] = parameters[i];
      }
    H5::DataSpace paramSpace(1,&dim);
    H5::DataSet paramSet = this->m_H5File->createDataSet(name,
                                                         H5::PredType::NATIVE_DOUBLE,
                                                         paramSpace);
    paramSet.write(buf,H5::PredType::NATIVE_DOUBLE);
    paramSet.close();
    }
  else if( ! nameOfComputationType.compare(std::string("float") ) )
    {
    for(unsigned i(0); i < dim; i++)
      {
      buf[i] = parameters[i];
      }
    H5::DataSpace paramSpace(1,&dim);
    H5::DataSet paramSet = this->m_H5File->createDataSet(name,
                                                         H5::PredType::NATIVE_FLOAT,
                                                         paramSpace);
    paramSet.write(buf,H5::PredType::NATIVE_FLOAT);
    paramSet.close();
    }
  else
    {
    itkExceptionMacro(<< "Wrong data precision type "
                      << nameOfComputationType
                      << "for writing in HDF5 File");
    }
  delete [] buf;
}

/** read a parameter array from the location specified by name */
template< typename TInternalComputationValueType >
typename HDF5TransformIOTemplate< TInternalComputationValueType >::ParametersType
HDF5TransformIOTemplate< TInternalComputationValueType >
::ReadParameters(const std::string &DataSetName)
{
  ParametersType ParameterArray;
  hsize_t dim;
  H5::DataSet paramSet = this->m_H5File->openDataSet(DataSetName);
  H5T_class_t Type = paramSet.getTypeClass();
  if(Type != H5T_FLOAT)
    {
    itkExceptionMacro(<< "Wrong data type for "
                      << DataSetName
                      << "in HDF5 File");
    }
  H5::DataSpace Space = paramSet.getSpace();
  if(Space.getSimpleExtentNdims() != 1)
    {
    itkExceptionMacro(<< "Wrong # of dims for TransformType "
                      << "in HDF5 File");
    }
  Space.getSimpleExtentDims(&dim,ITK_NULLPTR);
  ParameterArray.SetSize(dim);
  H5::FloatType ParamType = paramSet.getFloatType();

  if( ParamType.getSize() == sizeof(double) )
    {
    double *buf = new double[dim];
    paramSet.read(buf,H5::PredType::NATIVE_DOUBLE);
    for(unsigned i = 0; i < dim; i++)
      {
      ParameterArray.SetElement(i,(TInternalComputationValueType)(buf[i]));
      }
    delete[] buf;
    }
  else
    {
    float *buf = new float[dim];
    paramSet.read(buf,H5::PredType::NATIVE_FLOAT);
    for(unsigned i = 0; i < dim; i++)
      {
      ParameterArray.SetElement(i,(TInternalComputationValueType)(buf[i]));
      }
    delete[] buf;
    }
  paramSet.close();
  return ParameterArray;
}

template< typename TInternalComputationValueType >
void
HDF5TransformIOTemplate< TInternalComputationValueType >
::WriteString(const std::string &path,
              const std::string &value)
{
  hsize_t numStrings(1);
  H5::DataSpace strSpace(1,&numStrings);
  H5::StrType strType(H5::PredType::C_S1,H5T_VARIABLE);
  H5::DataSet strSet = this->m_H5File->createDataSet(path,strType,strSpace);
  strSet.write(value,strType);
  strSet.close();
}

template< typename TInternalComputationValueType >
void
HDF5TransformIOTemplate< TInternalComputationValueType >
::WriteString(const std::string &path,
                 const char *s)
{
  const std::string _s(s);
  WriteString(path,_s);
}

/*
 File layout
 /TransformGroup
 /TransformGroup/N/TransformType -- string
 /TransformGroup/N/TransformFixedParameters -- list of double
 /TransformGroup/N//TransformParameters -- list of double
 */
template< typename TInternalComputationValueType >
void
HDF5TransformIOTemplate< TInternalComputationValueType >
::Read()
{
  //
  // HDF5 is pretty heavily exception-oriented. Some
  // exceptions might be recovered from, theoretically,
  // but in our case, either the data we want is there
  // and of the right type, or we give up.  So everything
  // happens in a big try/catch clause
  try
    {
    delete this->m_H5File;
    this->m_H5File = new H5::H5File(this->GetFileName(),H5F_ACC_RDONLY);
    // open /TransformGroup
    H5::Group transformGroup = this->m_H5File->openGroup(transformGroupName);

    for(unsigned int i = 0; i < transformGroup.getNumObjs(); i++)
      {
      std::string transformName(GetTransformName(i));

      // open /TransformGroup/N
      H5::Group currentTransformGroup = this->m_H5File->openGroup(transformName);
      //
      // read transform type
      std::string transformType;
      {
      hsize_t numStrings(1);
      H5::DataSpace strSpace(1,&numStrings);
      H5::StrType typeType(H5::PredType::C_S1,H5T_VARIABLE);
      std::string typeName(transformName);
      typeName += transformTypeName;
      H5::DataSet typeSet = this->m_H5File->openDataSet(typeName);
      typeSet.read(transformType,typeType,strSpace);
      typeSet.close();
      }
      // Transform name should be modified to have the output precision type.
      Superclass::CorrectTransformPrecisionType( transformType );

      TransformPointer transform;
      this->CreateTransform(transform,transformType);
      this->GetReadTransformList().push_back (transform);
      //
      // Composite transform doesn't store its own parameters
      if(transformType.find("CompositeTransform") == std::string::npos)
        {
        std::string fixedParamsName(transformName);
        fixedParamsName += transformFixedName;
        ParametersType params(this->ReadParameters(fixedParamsName));
        transform->SetFixedParameters(params);

        std::string paramsName(transformName);
        paramsName += transformParamsName;
        params = this->ReadParameters(paramsName);
        transform->SetParametersByValue(params);
        }
      currentTransformGroup.close();
      }
    transformGroup.close();
    this->m_H5File->close();
    }
  // catch failure caused by the H5File operations
  catch( H5::Exception & error )
    {
    itkExceptionMacro(<< error.getCDetailMsg());
    }
}

template< typename TInternalComputationValueType >
void
HDF5TransformIOTemplate< TInternalComputationValueType >
::WriteOneTransform(const int transformIndex,
                    const TransformType *curTransform)
{
  std::string transformName(GetTransformName(transformIndex));
  this->m_H5File->createGroup(transformName);
  const std::string transformType = curTransform->GetTransformTypeAsString();
  //
  // write out transform type.
  {
  std::string typeName(transformName);
  typeName += transformTypeName;
  this->WriteString(typeName,transformType);
  }
  //
  // composite transform doesn't store own parameters
  if(transformType.find("CompositeTransform") != std::string::npos)
    {
    if(transformIndex != 0)
      {
      itkExceptionMacro(<< "Composite Transform can only be 1st transform in a file");
      }
    }
  else
    {
    //
    // write out Fixed Parameters
    ParametersType tmpArray = curTransform->GetFixedParameters();
    std::string fixedParamsName(transformName);
    fixedParamsName += transformFixedName;
    this->WriteParameters(fixedParamsName,tmpArray);
    // parameters
    tmpArray = curTransform->GetParameters();
    std::string paramsName(transformName);
    paramsName += transformParamsName;
    this->WriteParameters(paramsName,tmpArray);
    }
}

template< typename TInternalComputationValueType >
void
HDF5TransformIOTemplate< TInternalComputationValueType >
::Write()
{
  itksys::SystemInformation sysInfo;
  sysInfo.RunOSCheck();
  try
    {
    delete this->m_H5File;
    this->m_H5File = new H5::H5File(this->GetFileName(),H5F_ACC_TRUNC);

    this->WriteString(ItkVersion, Version::GetITKVersion());
    this->WriteString(HDFVersion, H5_VERS_INFO);
    this->WriteString(OSName,sysInfo.GetOSName());
    this->WriteString(OSVersion,sysInfo.GetOSRelease());

    this->m_H5File->createGroup(transformGroupName);

    ConstTransformListType &transformList =
      this->GetWriteTransformList();

    std::string compositeTransformType = transformList.front()->GetTransformTypeAsString();

    CompositeTransformIOHelperTemplate<TInternalComputationValueType> helper;
    //
    // if the first transform in the list is a
    // composite transform, use its internal list
    // instead of the IO
    if(compositeTransformType.find("CompositeTransform") != std::string::npos)
      {
      transformList = helper.GetTransformList(transformList.front().GetPointer());
      }

    typename ConstTransformListType::const_iterator end = transformList.end();

    int count = 0;

    for (typename ConstTransformListType::const_iterator it = transformList.begin();
         it != end; ++it,++count )
      {
      this->WriteOneTransform(count,(*it).GetPointer());
      }
    this->m_H5File->close();
    }
  // catch failure caused by the H5File operations
  catch( H5::Exception & error )
    {
    itkExceptionMacro(<< error.getCDetailMsg());
    }
}

} // end namespace itk

#endif
<|endoftext|>


<commit_before>// The MIT License (MIT)
//
// Copyright (c) 2015 Relja Ljubobratovic, ljubobratovic.relja@gmail.com
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

#include "../include/image.hpp"

namespace cv {

namespace internal {
template<typename _Tp>
void cv_to_gray(const image_array &source, image_array &target) {
    for (unsigned i = 0; i < source.rows(); ++i) {
        for (unsigned j = 0; j < source.cols(); ++j) {
            target.at<_Tp>(i, j) = static_cast<_Tp>((source.at<_Tp>(i, j, 0) +
                                                    source.at<_Tp>(i, j, 1) +
                                                    source.at<_Tp>(i, j, 2)) / 3.);
        }
    }
}

template<typename _Tp>
void cv_to_rgb(const image_array &source, image_array &target) {
    if (source.channels() == 1) {
        for (unsigned i = 0; i < source.rows(); ++i) {
            for (unsigned j = 0; j < source.cols(); ++j) {
                target.at<_Tp>(i, j, 0) = source.at<_Tp>(i, j);
                target.at<_Tp>(i, j, 1) = source.at<_Tp>(i, j);
                target.at<_Tp>(i, j, 2) = source.at<_Tp>(i, j);
            }
        }
    } else if (source.channels() == 4) {
        for (unsigned i = 0; i < source.rows(); ++i) {
            for (unsigned j = 0; j < source.cols(); ++j) {
                target.at<_Tp>(i, j, 0) = source.at<_Tp>(i, j, 0);
                target.at<_Tp>(i, j, 1) = source.at<_Tp>(i, j, 1);
                target.at<_Tp>(i, j, 2) = source.at<_Tp>(i, j, 2);
            }
        }
    } else {
        std::cerr << "Invalid source image!~ image should be a RGB, or RGBA to be converted to gray.\n";
    }
}

template<typename _Tp>
void cv_to_rgba(const image_array &source, image_array &target) {
    if (source.channels() == 1) {
        for (unsigned i = 0; i < source.rows(); ++i) {
            for (unsigned j = 0; j < source.cols(); ++j) {
                target.at<_Tp>(i, j, 0) = source.at<_Tp>(i, j);
                target.at<_Tp>(i, j, 1) = source.at<_Tp>(i, j);
                target.at<_Tp>(i, j, 2) = source.at<_Tp>(i, j);
                target.at<_Tp>(i, j, 3) = 255;
            }
        }
    } else if (source.channels() == 3) {
        for (unsigned i = 0; i < source.rows(); ++i) {
            for (unsigned j = 0; j < source.cols(); ++j) {
                target.at<_Tp>(i, j, 0) = source.at<_Tp>(i, j, 0);
                target.at<_Tp>(i, j, 1) = source.at<_Tp>(i, j, 1);
                target.at<_Tp>(i, j, 2) = source.at<_Tp>(i, j, 2);
                target.at<_Tp>(i, j, 3) = 255;
            }
        }
    }
}
}

///////////////////////////////////////////////////////////////////////////////
/// class: image_array

image_array::image_array(): super_type(), _dtype(NONE) {
}

image_array::image_array(unsigned rows, unsigned cols, unsigned channels, data_type dtype) : super_type(), _dtype(dtype) {
    ASSERT(dtype != NONE);
    this->_refcount = REF_NEW;
    this->allocate({rows, cols, channels}, internal::data_size[dtype]);
}

image_array::image_array(const vector<image_array> &channels) : super_type() {
	this->merge(channels);
}

image_array::image_array(const image_array &cpy, bool deep_copy) : super_type(cpy, deep_copy), _dtype(cpy._dtype) {
}

image_array::image_array(image_array &&move) {
    this->move(std::move(move));
    this->_dtype = move._dtype;
    move._dtype = NONE;
}

image_array::~image_array() {
}

image_array &image_array::operator=(image_array &&rhs) {
    if (this != &rhs) {
        super_type::operator=(std::move(rhs));
        this->_dtype = rhs._dtype;
        rhs._dtype = NONE;
    }
    return *this;
}

void image_array::create(unsigned rows, unsigned cols, unsigned channels, data_type dtype) {
    this->release();
    this->_dtype = dtype;
    ASSERT(dtype != NONE);
    this->allocate({rows, cols, channels}, internal::data_size[dtype]);
}

image_array image_array::clone() const {
    return image_array(*this, true);
}

unsigned image_array::rows() const {
    return this->_shape[0];
}

unsigned image_array::cols() const {
    return this->_shape[1];
}

unsigned image_array::channels() const {
    return this->_shape[2];
}

void image_array::release() {
    super_type::release();
    this->_dtype = NONE;
}

vec3i image_array::size() const {
    return vec3i(this->rows(), this->cols(), this->channels());
}

data_type image_array::dtype() const {
    return this->_dtype;
}

unsigned image_array::row_stride() const {
    return this->_strides[0];
}

unsigned image_array::depth() const {
    return internal::data_size[this->_dtype];
}

vector<image_array> image_array::split() {
	ASSERT(*this);

	if (this->channels() == 1)
		return {*this};

	vector<image_array> channels(this->channels());

	for (unsigned i = 0; i < this->channels(); ++i) {
		channels[i] = this->get_channel(i);
	}

	return channels;
}

void image_array::merge( const vector<image_array> &channels) {
	ASSERT(channels.length() > 0 && channels.length() < 5);
	if (channels.length() == 1) {
		*this = channels[0].clone();
		return;
	}

	auto rows = channels[0].rows();
	auto cols = channels[0].cols();
	auto ch_count = channels.length();
	auto dtype = channels[0].dtype();

	for (auto c : channels) {
		ASSERT(c.rows() == rows && c.cols() == cols && c.channels() == 1 && c.dtype() == dtype);
	}

	this->create(rows, cols, ch_count, dtype);
	auto item_stride = this->strides()[2];

	for (unsigned i = 0; i < rows; ++i) {
		for (unsigned j = 0; j < cols; ++j) {
			for (unsigned k = 0; k < ch_count; ++k) {
				std::memcpy(
						reinterpret_cast<void*>(&this->at_index(i, j, k)),
						reinterpret_cast<void*>(const_cast<unsigned char*>(&(channels[k].at_index(i, j, 0)))),
						item_stride);
			}
		}
	}
}

image_array image_array::get_channel(unsigned channel) {
	ASSERT(*this && channel < this->channels());

	image_array c_i;

	c_i._data = this->_data;
	c_i._begin = this->_begin + channel*this->_strides[2];
	c_i._strides = {this->_strides[0], this->_strides[1], this->_strides[2]*this->channels()};
	c_i._shape = {this->rows(), this->cols(), 1};
	c_i._refcount = this->_refcount;
	c_i._dtype = this->_dtype;

	REF_INCREMENT(c_i._refcount);

	return c_i;
}

const image_array image_array::get_channel(unsigned channel) const {
	ASSERT(*this && channel < this->channels());

	image_array c_i;

	c_i._data = this->_data;
	c_i._begin = this->_begin + channel*this->_strides[2];
	c_i._strides = {this->_strides[0], this->_strides[1], this->_strides[2]*this->channels()};
	c_i._shape = {this->rows(), this->cols(), 1};
	c_i._refcount = this->_refcount;

	REF_INCREMENT(c_i._refcount);

	return c_i;
}

void image_array::to_gray() {
    ASSERT(this->is_valid());
    if (this->channels() == 1) {
        return;
    }
    image_array tgt_img(this->rows(), this->cols(), 1, this->dtype());
    if (this->channels() >= 3) {
        // TODO: support all other types here as well.
        switch (this->dtype()) {
        case UINT8:
            internal::cv_to_gray<byte>(*this, tgt_img);
            break;
        case UINT16:
            internal::cv_to_gray<unsigned short>(*this, tgt_img);
            break;
        case FLOAT32:
            internal::cv_to_gray<float>(*this, tgt_img);
            break;
        case FLOAT64:
            internal::cv_to_gray<double>(*this, tgt_img);
            break;
        default:
            throw std::runtime_error("Type convertion not supported");
        }
    } else {
        throw std::runtime_error("Invalid source image!~ image should be a RGB, or RGBA to be converted to gray");
    }
    *this = std::move(tgt_img);
}

void image_array::to_rgb() {
    ASSERT(this->is_valid());
    if (this->channels() == 3) {
        return;
    }
    image_array tgt_img(this->rows(), this->cols(), 3, this->dtype());
    switch (this->dtype()) {
    case UINT8:
        internal::cv_to_rgb<byte>(*this, tgt_img);
        break;
    case UINT16:
        internal::cv_to_rgb<unsigned short>(*this, tgt_img);
        break;
    case FLOAT32:
        internal::cv_to_rgb<float>(*this, tgt_img);
        break;
    case FLOAT64:
        internal::cv_to_rgb<double>(*this, tgt_img);
        break;
    default:
        throw std::runtime_error("Type not supported");
    }
    *this = std::move(tgt_img);
}

void image_array::to_rgba() {
    ASSERT(this->is_valid());
    if (this->channels() == 4) {
        return;
    }
    image_array tgt_img(this->rows(), this->cols(), 4, this->dtype());
    switch (this->dtype()) {
    case UINT8:
		internal::cv_to_rgba<byte>(*this, tgt_img);
        break;
    case UINT16:
		internal::cv_to_rgba<unsigned short>(*this, tgt_img);
        break;
    case FLOAT32:
		internal::cv_to_rgba<float>(*this, tgt_img);
        break;
    case FLOAT64:
		internal::cv_to_rgba<double>(*this, tgt_img);
        break;
    default:
        throw std::runtime_error("Type not supported");
    }
    *this = std::move(tgt_img);
}

}

<commit_msg>bugfix: image memory copy<commit_after>// The MIT License (MIT)
//
// Copyright (c) 2015 Relja Ljubobratovic, ljubobratovic.relja@gmail.com
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

#include "../include/image.hpp"

namespace cv {

namespace internal {
template<typename _Tp>
void cv_to_gray(const image_array &source, image_array &target) {
    for (unsigned i = 0; i < source.rows(); ++i) {
        for (unsigned j = 0; j < source.cols(); ++j) {
            target.at<_Tp>(i, j) = static_cast<_Tp>((source.at<_Tp>(i, j, 0) +
                                                    source.at<_Tp>(i, j, 1) +
                                                    source.at<_Tp>(i, j, 2)) / 3.);
        }
    }
}

template<typename _Tp>
void cv_to_rgb(const image_array &source, image_array &target) {
    if (source.channels() == 1) {
        for (unsigned i = 0; i < source.rows(); ++i) {
            for (unsigned j = 0; j < source.cols(); ++j) {
                target.at<_Tp>(i, j, 0) = source.at<_Tp>(i, j);
                target.at<_Tp>(i, j, 1) = source.at<_Tp>(i, j);
                target.at<_Tp>(i, j, 2) = source.at<_Tp>(i, j);
            }
        }
    } else if (source.channels() == 4) {
        for (unsigned i = 0; i < source.rows(); ++i) {
            for (unsigned j = 0; j < source.cols(); ++j) {
                target.at<_Tp>(i, j, 0) = source.at<_Tp>(i, j, 0);
                target.at<_Tp>(i, j, 1) = source.at<_Tp>(i, j, 1);
                target.at<_Tp>(i, j, 2) = source.at<_Tp>(i, j, 2);
            }
        }
    } else {
        std::cerr << "Invalid source image!~ image should be a RGB, or RGBA to be converted to gray.\n";
    }
}

template<typename _Tp>
void cv_to_rgba(const image_array &source, image_array &target) {
    if (source.channels() == 1) {
        for (unsigned i = 0; i < source.rows(); ++i) {
            for (unsigned j = 0; j < source.cols(); ++j) {
                target.at<_Tp>(i, j, 0) = source.at<_Tp>(i, j);
                target.at<_Tp>(i, j, 1) = source.at<_Tp>(i, j);
                target.at<_Tp>(i, j, 2) = source.at<_Tp>(i, j);
                target.at<_Tp>(i, j, 3) = 255;
            }
        }
    } else if (source.channels() == 3) {
        for (unsigned i = 0; i < source.rows(); ++i) {
            for (unsigned j = 0; j < source.cols(); ++j) {
                target.at<_Tp>(i, j, 0) = source.at<_Tp>(i, j, 0);
                target.at<_Tp>(i, j, 1) = source.at<_Tp>(i, j, 1);
                target.at<_Tp>(i, j, 2) = source.at<_Tp>(i, j, 2);
                target.at<_Tp>(i, j, 3) = 255;
            }
        }
    }
}
}

///////////////////////////////////////////////////////////////////////////////
/// class: image_array

image_array::image_array(): super_type(), _dtype(NONE) {
}

image_array::image_array(unsigned rows, unsigned cols, unsigned channels, data_type dtype) : super_type(), _dtype(dtype) {
    ASSERT(dtype != NONE);
    this->_refcount = REF_NEW;
    this->allocate({rows, cols, channels}, internal::data_size[dtype]);
}

image_array::image_array(const vector<image_array> &channels) : super_type() {
	this->merge(channels);
}

image_array::image_array(const image_array &cpy, bool deep_copy) : super_type(), _dtype(cpy._dtype) {
	if (!cpy)
		return;
	else {
		if (deep_copy) {
			auto dt_size = internal::data_size[cpy.dtype()];
			this->allocate(cpy.shape(), dt_size);
			if (cpy.is_contiguous()) {
				std::memcpy(reinterpret_cast<void*>(this->_begin), reinterpret_cast<void*>(cpy._begin),
						cpy.shape().product()*dt_size);
			} else {
				for(unsigned i = 0; i < cpy.rows(); ++i) {
					for(unsigned j = 0; j < cpy.cols(); ++j) {
						for (unsigned k = 0; k < cpy.channels(); ++k) {
							std::memcpy(reinterpret_cast<void*>(&this->at_index(i, j, k)),
									reinterpret_cast<void*>(const_cast<byte*>(&cpy.at_index(i, j, k))),
									dt_size);
						}
					}
				}
			}
		} else {
			this->copy(cpy, false);
		}
	}

}

image_array::image_array(image_array &&move) {
    this->move(std::move(move));
    this->_dtype = move._dtype;
    move._dtype = NONE;
}

image_array::~image_array() {
}

image_array &image_array::operator=(image_array &&rhs) {
    if (this != &rhs) {
        super_type::operator=(std::move(rhs));
        this->_dtype = rhs._dtype;
        rhs._dtype = NONE;
    }
    return *this;
}

void image_array::create(unsigned rows, unsigned cols, unsigned channels, data_type dtype) {
    this->release();
    this->_dtype = dtype;
    ASSERT(dtype != NONE);
    this->allocate({rows, cols, channels}, internal::data_size[dtype]);
}

image_array image_array::clone() const {
    return image_array(*this, true);
}

unsigned image_array::rows() const {
    return this->_shape[0];
}

unsigned image_array::cols() const {
    return this->_shape[1];
}

unsigned image_array::channels() const {
    return this->_shape[2];
}

void image_array::release() {
    super_type::release();
    this->_dtype = NONE;
}

vec3i image_array::size() const {
    return vec3i(this->rows(), this->cols(), this->channels());
}

data_type image_array::dtype() const {
    return this->_dtype;
}

unsigned image_array::row_stride() const {
    return this->_strides[0];
}

unsigned image_array::depth() const {
    return internal::data_size[this->_dtype];
}

vector<image_array> image_array::split() {
	ASSERT(*this);

	if (this->channels() == 1)
		return {*this};

	vector<image_array> channels(this->channels());

	for (unsigned i = 0; i < this->channels(); ++i) {
		channels[i] = this->get_channel(i);
	}

	return channels;
}

void image_array::merge( const vector<image_array> &channels) {
	ASSERT(channels.length() > 0 && channels.length() < 5);
	if (channels.length() == 1) {
		*this = channels[0].clone();
		return;
	}

	auto rows = channels[0].rows();
	auto cols = channels[0].cols();
	auto ch_count = channels.length();
	auto dtype = channels[0].dtype();

	for (auto c : channels) {
		ASSERT(c.rows() == rows && c.cols() == cols && c.channels() == 1 && c.dtype() == dtype);
	}

	this->create(rows, cols, ch_count, dtype);
	auto item_stride = this->strides()[2];

	for (unsigned i = 0; i < rows; ++i) {
		for (unsigned j = 0; j < cols; ++j) {
			for (unsigned k = 0; k < ch_count; ++k) {
				std::memcpy(
						reinterpret_cast<void*>(&this->at_index(i, j, k)),
						reinterpret_cast<void*>(const_cast<unsigned char*>(&(channels[k].at_index(i, j, 0)))),
						item_stride);
			}
		}
	}
}

image_array image_array::get_channel(unsigned channel) {
	ASSERT(*this && channel < this->channels());

	image_array c_i;

	c_i._data = this->_data;
	c_i._begin = this->_begin + channel*this->_strides[2];
	c_i._strides = {this->_strides[0], this->_strides[1], this->_strides[2]*this->channels()};
	c_i._shape = {this->rows(), this->cols(), 1};
	c_i._refcount = this->_refcount;
	c_i._dtype = this->_dtype;

	REF_INCREMENT(c_i._refcount);

	return c_i;
}

const image_array image_array::get_channel(unsigned channel) const {
	ASSERT(*this && channel < this->channels());

	image_array c_i;

	c_i._data = this->_data;
	c_i._begin = this->_begin + channel*this->_strides[2];
	c_i._strides = {this->_strides[0], this->_strides[1], this->_strides[2]*this->channels()};
	c_i._shape = {this->rows(), this->cols(), 1};
	c_i._refcount = this->_refcount;

	REF_INCREMENT(c_i._refcount);

	return c_i;
}

void image_array::to_gray() {
    ASSERT(this->is_valid());
    if (this->channels() == 1) {
        return;
    }
    image_array tgt_img(this->rows(), this->cols(), 1, this->dtype());
    if (this->channels() >= 3) {
        // TODO: support all other types here as well.
        switch (this->dtype()) {
        case UINT8:
            internal::cv_to_gray<byte>(*this, tgt_img);
            break;
        case UINT16:
            internal::cv_to_gray<unsigned short>(*this, tgt_img);
            break;
        case FLOAT32:
            internal::cv_to_gray<float>(*this, tgt_img);
            break;
        case FLOAT64:
            internal::cv_to_gray<double>(*this, tgt_img);
            break;
        default:
            throw std::runtime_error("Type convertion not supported");
        }
    } else {
        throw std::runtime_error("Invalid source image!~ image should be a RGB, or RGBA to be converted to gray");
    }
    *this = std::move(tgt_img);
}

void image_array::to_rgb() {
    ASSERT(this->is_valid());
    if (this->channels() == 3) {
        return;
    }
    image_array tgt_img(this->rows(), this->cols(), 3, this->dtype());
    switch (this->dtype()) {
    case UINT8:
        internal::cv_to_rgb<byte>(*this, tgt_img);
        break;
    case UINT16:
        internal::cv_to_rgb<unsigned short>(*this, tgt_img);
        break;
    case FLOAT32:
        internal::cv_to_rgb<float>(*this, tgt_img);
        break;
    case FLOAT64:
        internal::cv_to_rgb<double>(*this, tgt_img);
        break;
    default:
        throw std::runtime_error("Type not supported");
    }
    *this = std::move(tgt_img);
}

void image_array::to_rgba() {
    ASSERT(this->is_valid());
    if (this->channels() == 4) {
        return;
    }
    image_array tgt_img(this->rows(), this->cols(), 4, this->dtype());
    switch (this->dtype()) {
    case UINT8:
		internal::cv_to_rgba<byte>(*this, tgt_img);
        break;
    case UINT16:
		internal::cv_to_rgba<unsigned short>(*this, tgt_img);
        break;
    case FLOAT32:
		internal::cv_to_rgba<float>(*this, tgt_img);
        break;
    case FLOAT64:
		internal::cv_to_rgba<double>(*this, tgt_img);
        break;
    default:
        throw std::runtime_error("Type not supported");
    }
    *this = std::move(tgt_img);
}

}

<|endoftext|>


<commit_before>/* Copyright 1994, 1995 by Abacus Research and
 * Development, Inc.  All rights reserved.
 */

#include "rsys/common.h"
#include "QuickDraw.h"
#include "MemoryMgr.h"

#include "rsys/cquick.h"
#include "rsys/mman.h"

#include "rsys/image.h"
#include <algorithm>

using namespace Executor;

#define MAX_ROWBYTES_FOR_WIDTH(w) ((((w)*32 + 31) / 32) * 4)

pixel_image_t *
Executor::image_init(pixel_image_desc_t *image_desc)
{
    pixel_image_t *retval;
    int i;

    TheZoneGuard guard(LM(SysZone));

    retval = (pixel_image_t *)NewPtr(sizeof *retval);

    for(i = 0; i < 2; i++)
    {
        PixMapHandle bits;
        PixMapHandle x_bits;
        int x_row_bytes;
        Rect bounds;
        int bpp;
        Ptr p;

        IMAGE_BITS(retval, i) = bits = NewPixMap();
        IMAGE_X_BITS(retval, i) = x_bits = NewPixMap();
        IMAGE_X_BITS_VALID(retval, i) = -1;

        PIXMAP_BASEADDR_X(bits) = RM((Ptr)image_desc->bits[i].raw_bits);
        PIXMAP_SET_ROWBYTES_X(bits, CW(image_desc->bits[i].row_bytes));
        bounds.top = CW(image_desc->bounds.top);
        bounds.left = CW(image_desc->bounds.left);
        bounds.bottom = CW(image_desc->bounds.bottom);
        bounds.right = CW(image_desc->bounds.right);
        retval->bounds = bounds;
        PIXMAP_BOUNDS(bits) = bounds;
        bpp = image_desc->bits[i].bpp;
        PIXMAP_CMP_SIZE_X(bits) = PIXMAP_PIXEL_SIZE_X(bits) = CW(bpp);
        if(i == 0)
        {
            /* the `zero' image is simply a 1bbp black and white image */
            gui_assert(bpp == 1);
            ROMlib_copy_ctab(ROMlib_bw_ctab,
                             PIXMAP_TABLE(bits));
        }
        else
        {
            CTabHandle bits_ctab;
            ColorSpec *bits_ctab_table;
            int j;

            bits_ctab = PIXMAP_TABLE(bits);
            SetHandleSize((Handle)bits_ctab,
                          CTAB_STORAGE_FOR_SIZE((1 << bpp) - 1));
            CTAB_SIZE_X(bits_ctab) = CW((1 << bpp) - 1);
            bits_ctab_table = CTAB_TABLE(bits_ctab);
            for(j = 0; j <= (1 << bpp) - 1; j++)
            {
                bits_ctab_table[j].value = CW(j);
                bits_ctab_table[j].rgb = {};
            }
            CTAB_FLAGS_X(bits_ctab) = CWC(0);
            CTAB_SEED_X(bits_ctab) = CL(GetCTSeed());
        }

        {
            int width;
            int height;

            width = RECT_WIDTH(&bounds);
            height = RECT_HEIGHT(&bounds);

            x_row_bytes = MAX_ROWBYTES_FOR_WIDTH(width);
            p = NewPtr(x_row_bytes * height);
            memset(p, 0, x_row_bytes * height);
            PIXMAP_BASEADDR_X(x_bits) = RM(p);
            PIXMAP_SET_ROWBYTES_X(x_bits, CW(x_row_bytes));
        }
    }

    return retval;
}

/* all image_... functions assume MR(qdGlobals().thePort) as target */
void Executor::image_copy(pixel_image_t *image, int color_p /* visual */,
                          Rect *dst_rect, int mode)
{
    WRAPPER_PIXMAP_FOR_COPY(wrapper);
    PixMapHandle x_bits;
    Rect x_bits_bounds;

    image_validate_x_bits(image, color_p);

    x_bits = IMAGE_X_BITS(image, color_p);
    WRAPPER_SET_PIXMAP_X(wrapper, RM(x_bits));
    x_bits_bounds = PIXMAP_BOUNDS(x_bits);

#if 0
  RGBForeColor (&ROMlib_black_rgb_color);
  RGBBackColor (&ROMlib_white_rgb_color);
#endif

    CopyBits(wrapper, PORT_BITS_FOR_COPY(MR(qdGlobals().thePort)),
             &x_bits_bounds, dst_rect, mode, NULL);
}

void Executor::image_validate_x_bits(pixel_image_t *image, int color_p /* visual */)
{
    GDHandle gdev;
    PixMapHandle bits, x_bits;
    PixMapHandle gd_pixmap;
    CTabHandle gd_pixmap_ctab;
    GUEST<INTEGER> gd_bpp_x;
    int bits_ctab_seed_x;

    gdev = MR(LM(TheGDevice));
    gd_pixmap = GD_PMAP(gdev);
    gd_pixmap_ctab = PIXMAP_TABLE(gd_pixmap);
    gd_bpp_x = PIXMAP_PIXEL_SIZE_X(gd_pixmap);

    bits = IMAGE_BITS(image, color_p);
    bits_ctab_seed_x = CTAB_SEED_X(PIXMAP_TABLE(bits)).raw();
    x_bits = IMAGE_X_BITS(image, color_p);

    if(IMAGE_X_BITS_VALID(image, color_p) == -1
       || IMAGE_X_BITS_VALID(image, color_p) != bits_ctab_seed_x
       || CTAB_SEED_X(PIXMAP_TABLE(x_bits)) != CTAB_SEED_X(gd_pixmap_ctab)
       || PIXMAP_PIXEL_SIZE_X(x_bits) != gd_bpp_x)
    {
        PIXMAP_CMP_SIZE_X(x_bits) = PIXMAP_PIXEL_SIZE_X(x_bits)
            = gd_bpp_x;
        ROMlib_copy_ctab(gd_pixmap_ctab, PIXMAP_TABLE(x_bits));

        HLockGuard guard1(bits), guard2(x_bits);
        convert_pixmap(STARH(bits), STARH(x_bits),
                       &PIXMAP_BOUNDS(bits), NULL);

        IMAGE_X_BITS_VALID(image, color_p) = bits_ctab_seed_x;
    }
}

/* assumes color */
void Executor::image_update_ctab(pixel_image_t *image, const RGBColor *new_colors,
                                 int max_color)
{
    PixMapHandle bits;
    CTabHandle bits_ctab;
    ColorSpec *bits_ctab_table;
    int bits_ctab_size;
    int ctab_changed_p;
    int i;

    bits = IMAGE_BITS(image, 1);
    bits_ctab = PIXMAP_TABLE(bits);
    bits_ctab_size = CTAB_SIZE(bits_ctab);
    bits_ctab_table = CTAB_TABLE(bits_ctab);

    ctab_changed_p = 0;
    for(i = std::min(bits_ctab_size, max_color); i >= 0; i--)
    {
        if(memcmp(&bits_ctab_table[i].rgb,
                  &new_colors[i], sizeof bits_ctab_table[i].rgb))
        {
            ctab_changed_p = 1;
            bits_ctab_table[i].rgb = new_colors[i];
        }
    }

    if(ctab_changed_p)
        CTAB_SEED_X(bits_ctab) = CL(GetCTSeed());
}
<commit_msg>pixelType field was not iniialized in image_validate_xbits<commit_after>/* Copyright 1994, 1995 by Abacus Research and
 * Development, Inc.  All rights reserved.
 */

#include "rsys/common.h"
#include "QuickDraw.h"
#include "MemoryMgr.h"

#include "rsys/cquick.h"
#include "rsys/mman.h"

#include "rsys/image.h"
#include <algorithm>

using namespace Executor;

#define MAX_ROWBYTES_FOR_WIDTH(w) ((((w)*32 + 31) / 32) * 4)

pixel_image_t *
Executor::image_init(pixel_image_desc_t *image_desc)
{
    pixel_image_t *retval;
    int i;

    TheZoneGuard guard(LM(SysZone));

    retval = (pixel_image_t *)NewPtr(sizeof *retval);

    for(i = 0; i < 2; i++)
    {
        PixMapHandle bits;
        PixMapHandle x_bits;
        int x_row_bytes;
        Rect bounds;
        int bpp;
        Ptr p;

        IMAGE_BITS(retval, i) = bits = NewPixMap();
        IMAGE_X_BITS(retval, i) = x_bits = NewPixMap();
        IMAGE_X_BITS_VALID(retval, i) = -1;

        PIXMAP_BASEADDR_X(bits) = RM((Ptr)image_desc->bits[i].raw_bits);
        PIXMAP_SET_ROWBYTES_X(bits, CW(image_desc->bits[i].row_bytes));
        bounds.top = CW(image_desc->bounds.top);
        bounds.left = CW(image_desc->bounds.left);
        bounds.bottom = CW(image_desc->bounds.bottom);
        bounds.right = CW(image_desc->bounds.right);
        retval->bounds = bounds;
        PIXMAP_BOUNDS(bits) = bounds;
        bpp = image_desc->bits[i].bpp;
        PIXMAP_CMP_SIZE_X(bits) = PIXMAP_PIXEL_SIZE_X(bits) = CW(bpp);
        if(i == 0)
        {
            /* the `zero' image is simply a 1bbp black and white image */
            gui_assert(bpp == 1);
            ROMlib_copy_ctab(ROMlib_bw_ctab,
                             PIXMAP_TABLE(bits));
        }
        else
        {
            CTabHandle bits_ctab;
            ColorSpec *bits_ctab_table;
            int j;

            bits_ctab = PIXMAP_TABLE(bits);
            SetHandleSize((Handle)bits_ctab,
                          CTAB_STORAGE_FOR_SIZE((1 << bpp) - 1));
            CTAB_SIZE_X(bits_ctab) = CW((1 << bpp) - 1);
            bits_ctab_table = CTAB_TABLE(bits_ctab);
            for(j = 0; j <= (1 << bpp) - 1; j++)
            {
                bits_ctab_table[j].value = CW(j);
                bits_ctab_table[j].rgb = {};
            }
            CTAB_FLAGS_X(bits_ctab) = CWC(0);
            CTAB_SEED_X(bits_ctab) = CL(GetCTSeed());
        }

        {
            int width;
            int height;

            width = RECT_WIDTH(&bounds);
            height = RECT_HEIGHT(&bounds);

            x_row_bytes = MAX_ROWBYTES_FOR_WIDTH(width);
            p = NewPtr(x_row_bytes * height);
            memset(p, 0, x_row_bytes * height);
            PIXMAP_BASEADDR_X(x_bits) = RM(p);
            PIXMAP_SET_ROWBYTES_X(x_bits, CW(x_row_bytes));
        }
    }

    return retval;
}

/* all image_... functions assume MR(qdGlobals().thePort) as target */
void Executor::image_copy(pixel_image_t *image, int color_p /* visual */,
                          Rect *dst_rect, int mode)
{
    WRAPPER_PIXMAP_FOR_COPY(wrapper);
    PixMapHandle x_bits;
    Rect x_bits_bounds;

    image_validate_x_bits(image, color_p);

    x_bits = IMAGE_X_BITS(image, color_p);
    WRAPPER_SET_PIXMAP_X(wrapper, RM(x_bits));
    x_bits_bounds = PIXMAP_BOUNDS(x_bits);

#if 0
  RGBForeColor (&ROMlib_black_rgb_color);
  RGBBackColor (&ROMlib_white_rgb_color);
#endif

    CopyBits(wrapper, PORT_BITS_FOR_COPY(MR(qdGlobals().thePort)),
             &x_bits_bounds, dst_rect, mode, NULL);
}

void Executor::image_validate_x_bits(pixel_image_t *image, int color_p /* visual */)
{
    GDHandle gdev;
    PixMapHandle bits, x_bits;
    PixMapHandle gd_pixmap;
    CTabHandle gd_pixmap_ctab;
    GUEST<INTEGER> gd_bpp_x;
    int bits_ctab_seed_x;

    gdev = MR(LM(TheGDevice));
    gd_pixmap = GD_PMAP(gdev);
    gd_pixmap_ctab = PIXMAP_TABLE(gd_pixmap);
    gd_bpp_x = PIXMAP_PIXEL_SIZE_X(gd_pixmap);

    bits = IMAGE_BITS(image, color_p);
    bits_ctab_seed_x = CTAB_SEED_X(PIXMAP_TABLE(bits)).raw();
    x_bits = IMAGE_X_BITS(image, color_p);

    if(IMAGE_X_BITS_VALID(image, color_p) == -1
       || IMAGE_X_BITS_VALID(image, color_p) != bits_ctab_seed_x
       || CTAB_SEED_X(PIXMAP_TABLE(x_bits)) != CTAB_SEED_X(gd_pixmap_ctab)
       || PIXMAP_PIXEL_SIZE_X(x_bits) != gd_bpp_x)
    {
        PIXMAP_CMP_SIZE_X(x_bits) = PIXMAP_PIXEL_SIZE_X(x_bits)
            = gd_bpp_x;
        STARH(x_bits)->pixelType = STARH(gd_pixmap)->pixelType;
        ROMlib_copy_ctab(gd_pixmap_ctab, PIXMAP_TABLE(x_bits));

        HLockGuard guard1(bits), guard2(x_bits);
        convert_pixmap(STARH(bits), STARH(x_bits),
                       &PIXMAP_BOUNDS(bits), NULL);

        IMAGE_X_BITS_VALID(image, color_p) = bits_ctab_seed_x;
    }
}

/* assumes color */
void Executor::image_update_ctab(pixel_image_t *image, const RGBColor *new_colors,
                                 int max_color)
{
    PixMapHandle bits;
    CTabHandle bits_ctab;
    ColorSpec *bits_ctab_table;
    int bits_ctab_size;
    int ctab_changed_p;
    int i;

    bits = IMAGE_BITS(image, 1);
    bits_ctab = PIXMAP_TABLE(bits);
    bits_ctab_size = CTAB_SIZE(bits_ctab);
    bits_ctab_table = CTAB_TABLE(bits_ctab);

    ctab_changed_p = 0;
    for(i = std::min(bits_ctab_size, max_color); i >= 0; i--)
    {
        if(memcmp(&bits_ctab_table[i].rgb,
                  &new_colors[i], sizeof bits_ctab_table[i].rgb))
        {
            ctab_changed_p = 1;
            bits_ctab_table[i].rgb = new_colors[i];
        }
    }

    if(ctab_changed_p)
        CTAB_SEED_X(bits_ctab) = CL(GetCTSeed());
}
<|endoftext|>