<commit_before>//////////////////////////////////////////////////////////////////////////
//
//  Copyright (c) 2007, Image Engine Design Inc. All rights reserved.
//
//  Redistribution and use in source and binary forms, with or without
//  modification, are permitted provided that the following conditions are
//  met:
//
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//
//     * Neither the name of Image Engine Design nor the names of any
//       other contributors to this software may be used to endorse or
//       promote products derived from this software without specific prior
//       written permission.
//
//  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
//  IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
//  THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
//  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
//  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
//  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
//  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
//  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
//  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
//  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
//  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//////////////////////////////////////////////////////////////////////////

// This include needs to be the very first to prevent problems with warnings
// regarding redefinition of _POSIX_C_SOURCE
#include <boost/python.hpp>

// System includes
#include <string>
#include <stdexcept>

#include <OpenEXR/ImathQuat.h>

#include "IECore/bindings/ImathQuatBinding.h"
#include "IECore/bindings/IECoreBinding.h"

using namespace boost::python;
using namespace Imath;

namespace IECore
{

template<typename T>
void bindQuat(const char *bindName);

void bindImathQuat()
{
	bindQuat<float>("Quatf");
	bindQuat<double>("Quatd");
}

template<typename T>
struct QuatIndexer
{
	static T get(const Quat<T> &x, int i)
	{
		// Do we want to handle backward indexing?
		if ( i >= 0 && i < 4 )
		{
			return x[i];
		}
		else
		{
			throw std::out_of_range("");
		}

	}

	static void set(Quat<T>  &x, int i, const T &v)
	{
		if ( i >= 0 && i < 4 )
		{
			x[i] = v;
		}
		else
		{
			throw std::out_of_range("");
		}
	}

};

#define DEFINEQUATSTRSPECIALISATION( QUAT )				\
														\
template<>												\
std::string repr<QUAT>( QUAT &x )						\
{														\
	std::stringstream s;								\
	s << #QUAT << "( ";									\
	for( unsigned i=0; i<4; i++ )						\
	{													\
		s << x[i];										\
		if( i!=3 )										\
		{												\
			s << ", ";									\
		}												\
	}													\
	s << " )";											\
	return s.str();										\
}														\
														\
template<>												\
std::string str<QUAT>( QUAT &x )						\
{														\
	std::stringstream s;								\
	for( unsigned i=0; i<4; i++ )						\
	{													\
		s << x[i];										\
		if( i!=3 )										\
		{												\
			s << " ";									\
		}												\
	}													\
	return s.str();										\
}														\

DEFINEQUATSTRSPECIALISATION( Quatf );
DEFINEQUATSTRSPECIALISATION( Quatd );

template<typename T>
void bindQuat(const char *bindName)
{
	class_< Quat<T> >(bindName)
		.def_readwrite("r", &Quat<T>::r)
		.def_readwrite("v", &Quat<T>::v)

		// [] operator support
		.def("__getitem__", &QuatIndexer<T>::get)
		.def("__setitem__", &QuatIndexer<T>::set)

		.def(init<>())
		.def(init<Quat<T> >())
		.def(init<T, T, T, T>())
		.def(init<T, Vec3<T> >())

		.def("identity", &Quat<T>::identity).staticmethod("identity")

		.def(self ^ self)

		.def(self *= self)
		.def(self *= T())
		.def(self /= self)
		.def(self /= T())
		.def(self += self)
		.def(self -= self)

		.def(self == self)
		.def(self != self)

		.def("invert", &Quat<T>::invert, return_self<>())
		.def("inverse", &Quat<T>::inverse)
		.def("normalize", &Quat<T>::normalize, return_self<>())
		.def("normalized", &Quat<T>::normalized)
		.def("length", &Quat<T>::length)

		.def("setAxisAngle", &Quat<T>::setAxisAngle, return_self<>())
		.def("setRotation", &Quat<T>::setRotation, return_self<>())

		.def("angle", &Quat<T>::angle)
		.def("axis", &Quat<T>::axis)

		.def("toMatrix33", &Quat<T>::toMatrix33)
		.def("toMatrix44", &Quat<T>::toMatrix44)

		.def("log", &Quat<T>::log)
		.def("exp", &Quat<T>::exp)

		.def("__str__", IECore::str<Quat<T> >)
		.def("__repr__", IECore::repr<Quat<T> >)
	;

	def("slerp", slerp<T>);
	def("squad", squad<T>);
	def("spline", spline<T>);
}

}
<commit_msg>Added more quaternion operators.<commit_after>//////////////////////////////////////////////////////////////////////////
//
//  Copyright (c) 2007, Image Engine Design Inc. All rights reserved.
//
//  Redistribution and use in source and binary forms, with or without
//  modification, are permitted provided that the following conditions are
//  met:
//
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//
//     * Neither the name of Image Engine Design nor the names of any
//       other contributors to this software may be used to endorse or
//       promote products derived from this software without specific prior
//       written permission.
//
//  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
//  IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
//  THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
//  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
//  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
//  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
//  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
//  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
//  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
//  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
//  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//////////////////////////////////////////////////////////////////////////

// This include needs to be the very first to prevent problems with warnings
// regarding redefinition of _POSIX_C_SOURCE
#include <boost/python.hpp>

// System includes
#include <string>
#include <stdexcept>

#include <OpenEXR/ImathQuat.h>

#include "IECore/bindings/ImathQuatBinding.h"
#include "IECore/bindings/IECoreBinding.h"

using namespace boost::python;
using namespace Imath;

namespace IECore
{

template<typename T>
void bindQuat(const char *bindName);

void bindImathQuat()
{
	bindQuat<float>("Quatf");
	bindQuat<double>("Quatd");
}

template<typename T>
struct QuatIndexer
{
	static T get(const Quat<T> &x, int i)
	{
		// Do we want to handle backward indexing?
		if ( i >= 0 && i < 4 )
		{
			return x[i];
		}
		else
		{
			throw std::out_of_range("");
		}

	}

	static void set(Quat<T>  &x, int i, const T &v)
	{
		if ( i >= 0 && i < 4 )
		{
			x[i] = v;
		}
		else
		{
			throw std::out_of_range("");
		}
	}

};

#define DEFINEQUATSTRSPECIALISATION( QUAT )				\
														\
template<>												\
std::string repr<QUAT>( QUAT &x )						\
{														\
	std::stringstream s;								\
	s << #QUAT << "( ";									\
	for( unsigned i=0; i<4; i++ )						\
	{													\
		s << x[i];										\
		if( i!=3 )										\
		{												\
			s << ", ";									\
		}												\
	}													\
	s << " )";											\
	return s.str();										\
}														\
														\
template<>												\
std::string str<QUAT>( QUAT &x )						\
{														\
	std::stringstream s;								\
	for( unsigned i=0; i<4; i++ )						\
	{													\
		s << x[i];										\
		if( i!=3 )										\
		{												\
			s << " ";									\
		}												\
	}													\
	return s.str();										\
}														\

DEFINEQUATSTRSPECIALISATION( Quatf );
DEFINEQUATSTRSPECIALISATION( Quatd );

template<typename T>
void bindQuat(const char *bindName)
{
	class_< Quat<T> >(bindName)
		.def_readwrite("r", &Quat<T>::r)
		.def_readwrite("v", &Quat<T>::v)

		// [] operator support
		.def("__getitem__", &QuatIndexer<T>::get)
		.def("__setitem__", &QuatIndexer<T>::set)

		.def(init<>())
		.def(init<Quat<T> >())
		.def(init<T, T, T, T>())
		.def(init<T, Vec3<T> >())

		.def("identity", &Quat<T>::identity).staticmethod("identity")

		.def(self ^ self)

		.def(self *= self)
		.def(self *= T())
		.def(self /= self)
		.def(self /= T())
		.def(self += self)
		.def(self -= self)

		.def(self == self)
		.def(self != self)

		.def( self * self )

		.def( ~self )

		.def("invert", &Quat<T>::invert, return_self<>())
		.def("inverse", &Quat<T>::inverse)
		.def("normalize", &Quat<T>::normalize, return_self<>())
		.def("normalized", &Quat<T>::normalized)
		.def("length", &Quat<T>::length)

		.def("setAxisAngle", &Quat<T>::setAxisAngle, return_self<>())
		.def("setRotation", &Quat<T>::setRotation, return_self<>())

		.def("angle", &Quat<T>::angle)
		.def("axis", &Quat<T>::axis)

		.def("toMatrix33", &Quat<T>::toMatrix33)
		.def("toMatrix44", &Quat<T>::toMatrix44)

		.def("log", &Quat<T>::log)
		.def("exp", &Quat<T>::exp)

		.def("__str__", IECore::str<Quat<T> >)
		.def("__repr__", IECore::repr<Quat<T> >)
	;

	def("slerp", slerp<T>);
	def("squad", squad<T>);
	def("spline", spline<T>);
}

}
<|endoftext|>


<commit_before>#include "ROOT/TDataFrame.hxx"
#include "Compression.h"
#include "TFile.h"
#include "TInterpreter.h"
#include "TRandom.h"

#include "gtest/gtest.h"

using namespace ROOT::Experimental;

namespace TEST_CATEGORY {

int DefineFunction()
{
   return 1;
}

struct DefineStruct {
   int operator()() { return 1; }
};

void FillTree(const char *filename, const char *treeName, int nevents = 0)
{
   TFile f(filename, "RECREATE");
   TTree t(treeName, treeName);
   t.SetAutoFlush(1); // yes, one event per cluster: to make MT more meaningful
   double b1;
   int b2;
   t.Branch("b1", &b1);
   t.Branch("b2", &b2);
   for (int i = 0; i < nevents; ++i) {
      b1 = i;
      b2 = i * i;
      t.Fill();
   }
   t.Write();
   f.Close();
}
}

TEST(TEST_CATEGORY, CreateEmpty)
{
   TDataFrame tdf(10);
   auto c = tdf.Count();
   EXPECT_EQ(10U, *c);
}

TEST(TEST_CATEGORY, CreateZeroEntries)
{
   TDataFrame tdf(0);
   auto c = tdf.Count();
   EXPECT_EQ(0U, *c);
}

TEST(TEST_CATEGORY, CreateZeroEntriesWithBranches)
{
   auto filename = "dataframe_simple_0.root";
   auto treename = "t";
#ifndef testTDF_simple_0_CREATED
#define testTDF_simple_0_CREATED
   TEST_CATEGORY::FillTree(filename, treename);
#endif
   TDataFrame tdf(treename, filename);
   auto c = tdf.Count();
   auto m = tdf.Mean("b1");
   EXPECT_EQ(0U, *c);
   EXPECT_EQ(0., *m);
}

TEST(TEST_CATEGORY, BuildWithTDirectory)
{
   auto filename = "dataframe_simple_1.root";
   auto treename = "t";
#ifndef testTDF_simple_1_CREATED
#define testTDF_simple_1_CREATED
   TEST_CATEGORY::FillTree(filename, treename, 50);
#endif
   TFile f(filename);
   TDataFrame tdf(treename, &f);
   auto c = tdf.Count();
   EXPECT_EQ(50U, *c);
}

// Jitting of column types
TEST(TEST_CATEGORY, TypeGuessing)
{
   auto filename = "dataframe_simple_2.root";
   auto treename = "t";
#ifndef testTDF_simple_2_CREATED
#define testTDF_simple_2_CREATED
   TEST_CATEGORY::FillTree(filename, treename, 50);
#endif
   TDataFrame tdf(treename, filename, {"b1"});
   auto hcompiled = tdf.Histo1D<double>();
   auto hjitted = tdf.Histo1D();
   EXPECT_EQ(50, hcompiled->GetEntries());
   EXPECT_EQ(50, hjitted->GetEntries());
   EXPECT_DOUBLE_EQ(hcompiled->GetMean(), hjitted->GetMean());
}

// Define

TEST(TEST_CATEGORY, Define_lambda)
{
   TDataFrame tdf(10);
   auto d = tdf.Define("i", []() { return 1; });
   auto m = d.Mean("i");
   EXPECT_DOUBLE_EQ(1., *m);
}

TEST(TEST_CATEGORY, Define_function)
{
   TDataFrame tdf(10);
   auto d = tdf.Define("i", TEST_CATEGORY::DefineFunction);
   auto m = d.Mean("i");
   EXPECT_DOUBLE_EQ(1., *m);
}

TEST(TEST_CATEGORY, Define_functor)
{
   TDataFrame tdf(10);
   TEST_CATEGORY::DefineStruct def;
   auto d = tdf.Define("i", def);
   auto m = d.Mean("i");
   EXPECT_DOUBLE_EQ(1., *m);
}

TEST(TEST_CATEGORY, Define_jitted)
{
   TDataFrame tdf(10);
   auto d = tdf.Define("i", "1");
   auto m = d.Mean("i");
   EXPECT_DOUBLE_EQ(1., *m);
}

TEST(TEST_CATEGORY, Define_jitted_complex)
{
// The test can be run in sequential and MT mode.
#ifndef RNDM_GEN_CREATED
#define RNDM_GEN_CREATED
   gInterpreter->ProcessLine("TRandom r;");
#endif
   gInterpreter->ProcessLine("r.SetSeed(1);");
   TDataFrame tdf(50);
   auto d = tdf.Define("i", "r.Uniform(0.,8.)");
   auto m = d.Max("i");
   EXPECT_EQ(7.867497533559811628, *m);
}

// Define + Filters
TEST(TEST_CATEGORY, Define_Filter)
{
   TRandom r(1);
   TDataFrame tdf(50);
   auto d = tdf.Define("r", [&r]() { return r.Uniform(0., 8.); });
   auto df = d.Filter([](double x) { return x > 5; }, {"r"});
   auto m = df.Max("r");
   EXPECT_EQ(7.867497533559811628, *m);
}

TEST(TEST_CATEGORY, Define_Filter_jitted)
{
   TRandom r(1);
   TDataFrame tdf(50);
   auto d = tdf.Define("r", [&r]() { return r.Uniform(0., 8.); });
   auto df = d.Filter("r>5");
   auto m = df.Max("r");
   EXPECT_EQ(7.867497533559811628, *m);
}

TEST(TEST_CATEGORY, Define_Filter_named)
{
   TRandom r(1);
   TDataFrame tdf(50);
   auto d = tdf.Define("r", [&r]() { return r.Uniform(0., 8.); });
   auto df = d.Filter([](double x) { return x > 5; }, {"r"}, "myFilter");
   auto m = df.Max("r");
   EXPECT_EQ(7.867497533559811628, *m);
}

TEST(TEST_CATEGORY, Define_Filter_named_jitted)
{
   TRandom r(1);
   TDataFrame tdf(50);
   auto d = tdf.Define("r", [&r]() { return r.Uniform(0., 8.); });
   auto df = d.Filter("r>5", "myFilter");
   auto m = df.Max("r");
   EXPECT_EQ(7.867497533559811628, *m);
}

// jitted Define + Filters
TEST(TEST_CATEGORY, Define_jitted_Filter)
{
   gInterpreter->ProcessLine("r.SetSeed(1);");
   TDataFrame tdf(50);
   auto d = tdf.Define("r", "r.Uniform(0.,8.)");
   auto df = d.Filter([](double x) { return x > 5; }, {"r"});
   auto m = df.Max("r");
   EXPECT_EQ(7.867497533559811628, *m);
}

TEST(TEST_CATEGORY, Define_jitted_Filter_jitted)
{
   gInterpreter->ProcessLine("r.SetSeed(1);");
   TDataFrame tdf(50);
   auto d = tdf.Define("r", "r.Uniform(0.,8.)");
   auto df = d.Filter("r>5");
   auto m = df.Max("r");
   EXPECT_EQ(7.867497533559811628, *m);
}

TEST(TEST_CATEGORY, Define_jitted_Filter_named)
{
   gInterpreter->ProcessLine("r.SetSeed(1);");
   TDataFrame tdf(50);
   auto d = tdf.Define("r", "r.Uniform(0.,8.)");
   auto df = d.Filter([](double x) { return x > 5; }, {"r"}, "myFilter");
   auto m = df.Max("r");
   EXPECT_EQ(7.867497533559811628, *m);
}

TEST(TEST_CATEGORY, Define_jitted_Filter_named_jitted)
{
   gInterpreter->ProcessLine("r.SetSeed(1);");
   TDataFrame tdf(50);
   auto d = tdf.Define("r", "r.Uniform(0.,8.)");
   auto df = d.Filter("r>5", "myFilter");
   auto m = df.Max("r");
   EXPECT_EQ(7.867497533559811628, *m);
}

TEST(TEST_CATEGORY, DefineSlot)
{
   std::array<int, NSLOTS> values;
   for (auto i = 0u; i < NSLOTS; ++i)
      values[i] = i;
   TDataFrame df(NSLOTS);
   auto ddf = df.DefineSlot("s", [values](unsigned int slot) { return values[slot]; });
   auto m = ddf.Max("s");
   EXPECT_EQ(*m, NSLOTS-1); // no matter the order of processing, the higher slot number is always taken at least once
}

TEST(TEST_CATEGORY, Snapshot_update)
{
   using SnapshotOptions = ROOT::Experimental::TDF::SnapshotOptions;

   SnapshotOptions opts;

   opts.fMode = "UPDATE";

   TDataFrame tdf1(1000);
   auto s1 = tdf1.Define("one", []() { return 1.0; })
               .Snapshot<double>("mytree1", "snapshot_test_update.root", {"one"});

   EXPECT_EQ(1000U, *s1.Count());

   EXPECT_EQ(1.0, *s1.Min("one"));
   EXPECT_EQ(1.0, *s1.Max("one"));
   EXPECT_EQ(1.0, *s1.Mean("one"));

   TDataFrame tdf2(1000);
   auto s2 = tdf2.Define("two", []() { return 2.0; })
               .Snapshot<double>("mytree2", "snapshot_test_update.root", {"two"}, opts);

   EXPECT_EQ(1000U, *s2.Count());

   EXPECT_EQ(2.0, *s2.Min("two"));
   EXPECT_EQ(2.0, *s2.Max("two"));
   EXPECT_EQ(2.0, *s2.Mean("two"));

   TFile *f = TFile::Open("snapshot_test_update.root", "READ");
   auto mytree1 = (TTree*) f->Get("mytree1");
   auto mytree2 = (TTree*) f->Get("mytree2");

   EXPECT_NE(nullptr, mytree1);
   EXPECT_NE(nullptr, mytree2);

   f->Close();
   delete f;
}

TEST(TEST_CATEGORY, Snapshot_action_with_options)
{
   using SnapshotOptions = ROOT::Experimental::TDF::SnapshotOptions;

   SnapshotOptions opts;
   opts.fAutoFlush = 10;
   opts.fMode = "RECREATE";

   for (auto algorithm : { ROOT::kZLIB, ROOT::kLZMA, ROOT::kLZ4 }) {
      TDataFrame tdf(1000);

      opts.fCompressionLevel = 6;
      opts.fCompressionAlgorithm = algorithm;

      auto s = tdf.Define("one", []() { return 1.0; })
                  .Snapshot<double>("mytree", "snapshot_test_opts.root", {"one"}, opts);

      EXPECT_EQ(1000U, *s.Count());
      EXPECT_EQ(1.0, *s.Min("one"));
      EXPECT_EQ(1.0, *s.Max("one"));
      EXPECT_EQ(1.0, *s.Mean("one"));

      TFile *f = TFile::Open("snapshot_test_opts.root", "READ");

      EXPECT_EQ(algorithm, f->GetCompressionAlgorithm());
      EXPECT_EQ(6, f->GetCompressionLevel());

      f->Close();
      delete f;
   }
}

// This tests the interface but we need to run it both w/ and w/o implicit mt
#ifdef R__USE_IMT
TEST(TEST_CATEGORY, GetNSlots)
{
   EXPECT_EQ(NSLOTS, ROOT::Internal::TDF::GetNSlots());
}
#endif
<commit_msg>[TDF] More tests of DefineSlot<commit_after>#include "ROOT/TDataFrame.hxx"
#include "Compression.h"
#include "TFile.h"
#include "TInterpreter.h"
#include "TRandom.h"

#include "gtest/gtest.h"

#include <chrono>
#include <thread>
#include <set>

using namespace ROOT::Experimental;

namespace TEST_CATEGORY {

int DefineFunction()
{
   return 1;
}

struct DefineStruct {
   int operator()() { return 1; }
};

void FillTree(const char *filename, const char *treeName, int nevents = 0)
{
   TFile f(filename, "RECREATE");
   TTree t(treeName, treeName);
   t.SetAutoFlush(1); // yes, one event per cluster: to make MT more meaningful
   double b1;
   int b2;
   t.Branch("b1", &b1);
   t.Branch("b2", &b2);
   for (int i = 0; i < nevents; ++i) {
      b1 = i;
      b2 = i * i;
      t.Fill();
   }
   t.Write();
   f.Close();
}
}

TEST(TEST_CATEGORY, CreateEmpty)
{
   TDataFrame tdf(10);
   auto c = tdf.Count();
   EXPECT_EQ(10U, *c);
}

TEST(TEST_CATEGORY, CreateZeroEntries)
{
   TDataFrame tdf(0);
   auto c = tdf.Count();
   EXPECT_EQ(0U, *c);
}

TEST(TEST_CATEGORY, CreateZeroEntriesWithBranches)
{
   auto filename = "dataframe_simple_0.root";
   auto treename = "t";
#ifndef testTDF_simple_0_CREATED
#define testTDF_simple_0_CREATED
   TEST_CATEGORY::FillTree(filename, treename);
#endif
   TDataFrame tdf(treename, filename);
   auto c = tdf.Count();
   auto m = tdf.Mean("b1");
   EXPECT_EQ(0U, *c);
   EXPECT_EQ(0., *m);
}

TEST(TEST_CATEGORY, BuildWithTDirectory)
{
   auto filename = "dataframe_simple_1.root";
   auto treename = "t";
#ifndef testTDF_simple_1_CREATED
#define testTDF_simple_1_CREATED
   TEST_CATEGORY::FillTree(filename, treename, 50);
#endif
   TFile f(filename);
   TDataFrame tdf(treename, &f);
   auto c = tdf.Count();
   EXPECT_EQ(50U, *c);
}

// Jitting of column types
TEST(TEST_CATEGORY, TypeGuessing)
{
   auto filename = "dataframe_simple_2.root";
   auto treename = "t";
#ifndef testTDF_simple_2_CREATED
#define testTDF_simple_2_CREATED
   TEST_CATEGORY::FillTree(filename, treename, 50);
#endif
   TDataFrame tdf(treename, filename, {"b1"});
   auto hcompiled = tdf.Histo1D<double>();
   auto hjitted = tdf.Histo1D();
   EXPECT_EQ(50, hcompiled->GetEntries());
   EXPECT_EQ(50, hjitted->GetEntries());
   EXPECT_DOUBLE_EQ(hcompiled->GetMean(), hjitted->GetMean());
}

// Define

TEST(TEST_CATEGORY, Define_lambda)
{
   TDataFrame tdf(10);
   auto d = tdf.Define("i", []() { return 1; });
   auto m = d.Mean("i");
   EXPECT_DOUBLE_EQ(1., *m);
}

TEST(TEST_CATEGORY, Define_function)
{
   TDataFrame tdf(10);
   auto d = tdf.Define("i", TEST_CATEGORY::DefineFunction);
   auto m = d.Mean("i");
   EXPECT_DOUBLE_EQ(1., *m);
}

TEST(TEST_CATEGORY, Define_functor)
{
   TDataFrame tdf(10);
   TEST_CATEGORY::DefineStruct def;
   auto d = tdf.Define("i", def);
   auto m = d.Mean("i");
   EXPECT_DOUBLE_EQ(1., *m);
}

TEST(TEST_CATEGORY, Define_jitted)
{
   TDataFrame tdf(10);
   auto d = tdf.Define("i", "1");
   auto m = d.Mean("i");
   EXPECT_DOUBLE_EQ(1., *m);
}

TEST(TEST_CATEGORY, Define_jitted_complex)
{
// The test can be run in sequential and MT mode.
#ifndef RNDM_GEN_CREATED
#define RNDM_GEN_CREATED
   gInterpreter->ProcessLine("TRandom r;");
#endif
   gInterpreter->ProcessLine("r.SetSeed(1);");
   TDataFrame tdf(50);
   auto d = tdf.Define("i", "r.Uniform(0.,8.)");
   auto m = d.Max("i");
   EXPECT_EQ(7.867497533559811628, *m);
}

// Define + Filters
TEST(TEST_CATEGORY, Define_Filter)
{
   TRandom r(1);
   TDataFrame tdf(50);
   auto d = tdf.Define("r", [&r]() { return r.Uniform(0., 8.); });
   auto df = d.Filter([](double x) { return x > 5; }, {"r"});
   auto m = df.Max("r");
   EXPECT_EQ(7.867497533559811628, *m);
}

TEST(TEST_CATEGORY, Define_Filter_jitted)
{
   TRandom r(1);
   TDataFrame tdf(50);
   auto d = tdf.Define("r", [&r]() { return r.Uniform(0., 8.); });
   auto df = d.Filter("r>5");
   auto m = df.Max("r");
   EXPECT_EQ(7.867497533559811628, *m);
}

TEST(TEST_CATEGORY, Define_Filter_named)
{
   TRandom r(1);
   TDataFrame tdf(50);
   auto d = tdf.Define("r", [&r]() { return r.Uniform(0., 8.); });
   auto df = d.Filter([](double x) { return x > 5; }, {"r"}, "myFilter");
   auto m = df.Max("r");
   EXPECT_EQ(7.867497533559811628, *m);
}

TEST(TEST_CATEGORY, Define_Filter_named_jitted)
{
   TRandom r(1);
   TDataFrame tdf(50);
   auto d = tdf.Define("r", [&r]() { return r.Uniform(0., 8.); });
   auto df = d.Filter("r>5", "myFilter");
   auto m = df.Max("r");
   EXPECT_EQ(7.867497533559811628, *m);
}

// jitted Define + Filters
TEST(TEST_CATEGORY, Define_jitted_Filter)
{
   gInterpreter->ProcessLine("r.SetSeed(1);");
   TDataFrame tdf(50);
   auto d = tdf.Define("r", "r.Uniform(0.,8.)");
   auto df = d.Filter([](double x) { return x > 5; }, {"r"});
   auto m = df.Max("r");
   EXPECT_EQ(7.867497533559811628, *m);
}

TEST(TEST_CATEGORY, Define_jitted_Filter_jitted)
{
   gInterpreter->ProcessLine("r.SetSeed(1);");
   TDataFrame tdf(50);
   auto d = tdf.Define("r", "r.Uniform(0.,8.)");
   auto df = d.Filter("r>5");
   auto m = df.Max("r");
   EXPECT_EQ(7.867497533559811628, *m);
}

TEST(TEST_CATEGORY, Define_jitted_Filter_named)
{
   gInterpreter->ProcessLine("r.SetSeed(1);");
   TDataFrame tdf(50);
   auto d = tdf.Define("r", "r.Uniform(0.,8.)");
   auto df = d.Filter([](double x) { return x > 5; }, {"r"}, "myFilter");
   auto m = df.Max("r");
   EXPECT_EQ(7.867497533559811628, *m);
}

TEST(TEST_CATEGORY, Define_jitted_Filter_named_jitted)
{
   gInterpreter->ProcessLine("r.SetSeed(1);");
   TDataFrame tdf(50);
   auto d = tdf.Define("r", "r.Uniform(0.,8.)");
   auto df = d.Filter("r>5", "myFilter");
   auto m = df.Max("r");
   EXPECT_EQ(7.867497533559811628, *m);
}

TEST(TEST_CATEGORY, DefineSlotConsistency)
{
   TDataFrame df(8);
   auto m = df.DefineSlot("x", [](unsigned int ) { return 1.; }).Max("x");
   EXPECT_EQ(1., *m);
}

TEST(TEST_CATEGORY, DefineSlot)
{
   std::array<int, NSLOTS> values;
   for (auto i = 0u; i < NSLOTS; ++i)
      values[i] = i;
   TDataFrame df(NSLOTS);
   auto ddf = df.DefineSlot("s", [values](unsigned int slot) { return values[slot]; });
   auto m = ddf.Max("s");
   EXPECT_EQ(*m, NSLOTS-1); // no matter the order of processing, the higher slot number is always taken at least once
}

TEST(TEST_CATEGORY, DefineSlotCheckMT)
{
   auto nSlots = NSLOTS;

   std::hash<std::thread::id> hasher;
   using H_t = decltype(hasher(std::this_thread::get_id()));

   std::vector<H_t> ids(nSlots, 0);
   TDataFrame d(nSlots);
   auto m = d.DefineSlot("x", [&](unsigned int slot) {
      std::this_thread::sleep_for(std::chrono::milliseconds(100));
      ids[slot] = hasher(std::this_thread::get_id());
      return 1.; }).Max("x");

   EXPECT_EQ(1, *m); // just in case

   std::set<H_t> s(ids.begin(), ids.end());
   EXPECT_EQ(nSlots, s.size());
   EXPECT_TRUE(s.end() == s.find(0));
}

TEST(TEST_CATEGORY, Snapshot_update)
{
   using SnapshotOptions = ROOT::Experimental::TDF::SnapshotOptions;

   SnapshotOptions opts;

   opts.fMode = "UPDATE";

   TDataFrame tdf1(1000);
   auto s1 = tdf1.Define("one", []() { return 1.0; })
               .Snapshot<double>("mytree1", "snapshot_test_update.root", {"one"});

   EXPECT_EQ(1000U, *s1.Count());

   EXPECT_EQ(1.0, *s1.Min("one"));
   EXPECT_EQ(1.0, *s1.Max("one"));
   EXPECT_EQ(1.0, *s1.Mean("one"));

   TDataFrame tdf2(1000);
   auto s2 = tdf2.Define("two", []() { return 2.0; })
               .Snapshot<double>("mytree2", "snapshot_test_update.root", {"two"}, opts);

   EXPECT_EQ(1000U, *s2.Count());

   EXPECT_EQ(2.0, *s2.Min("two"));
   EXPECT_EQ(2.0, *s2.Max("two"));
   EXPECT_EQ(2.0, *s2.Mean("two"));

   TFile *f = TFile::Open("snapshot_test_update.root", "READ");
   auto mytree1 = (TTree*) f->Get("mytree1");
   auto mytree2 = (TTree*) f->Get("mytree2");

   EXPECT_NE(nullptr, mytree1);
   EXPECT_NE(nullptr, mytree2);

   f->Close();
   delete f;
}

TEST(TEST_CATEGORY, Snapshot_action_with_options)
{
   using SnapshotOptions = ROOT::Experimental::TDF::SnapshotOptions;

   SnapshotOptions opts;
   opts.fAutoFlush = 10;
   opts.fMode = "RECREATE";

   for (auto algorithm : { ROOT::kZLIB, ROOT::kLZMA, ROOT::kLZ4 }) {
      TDataFrame tdf(1000);

      opts.fCompressionLevel = 6;
      opts.fCompressionAlgorithm = algorithm;

      auto s = tdf.Define("one", []() { return 1.0; })
                  .Snapshot<double>("mytree", "snapshot_test_opts.root", {"one"}, opts);

      EXPECT_EQ(1000U, *s.Count());
      EXPECT_EQ(1.0, *s.Min("one"));
      EXPECT_EQ(1.0, *s.Max("one"));
      EXPECT_EQ(1.0, *s.Mean("one"));

      TFile *f = TFile::Open("snapshot_test_opts.root", "READ");

      EXPECT_EQ(algorithm, f->GetCompressionAlgorithm());
      EXPECT_EQ(6, f->GetCompressionLevel());

      f->Close();
      delete f;
   }
}

// This tests the interface but we need to run it both w/ and w/o implicit mt
#ifdef R__USE_IMT
TEST(TEST_CATEGORY, GetNSlots)
{
   EXPECT_EQ(NSLOTS, ROOT::Internal::TDF::GetNSlots());
}
#endif
<|endoftext|>


<commit_before>///////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2002, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// *       Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// *       Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// *       Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
///////////////////////////////////////////////////////////////////////////

#include <ImfXdr.h>
#include <ImfIO.h>
#include <typeinfo>
#include <string.h>
#include <assert.h>

#if defined (__GNUC__) && __GNUC__ == 2
#include <strstream.h>
#else
#include <sstream>
#endif

using namespace std;
using namespace Imf;

namespace {

struct CharIO
{
    static void
    writeChars (ostream &os, const char c[], int n)
    {
	os.write (c, n);
    }

    static bool
    readChars (istream &is, char c[], int n)
    {
	is.read (c, n);
	return true;
    }
};

void
writeData (ostream &os)
{
    Xdr::write<CharIO>    (os, (bool) true);
    Xdr::write<CharIO>    (os, (bool) false);
    Xdr::write<CharIO>    (os, (char) 'r');
    Xdr::write<CharIO>    (os, (char) 'e');
    Xdr::write<CharIO>    (os, (signed char) 'u');
    Xdr::write<CharIO>    (os, (signed char) 'c');
    Xdr::write<CharIO>    (os, (unsigned char) 'k');
    Xdr::write<CharIO>    (os, (unsigned char) 'y');
    Xdr::write<CharIO>    (os, (signed short)  8765);
    Xdr::write<CharIO>    (os, (signed short) -9876);
    Xdr::write<CharIO>    (os, (unsigned short)  6543);
    Xdr::write<CharIO>    (os, (unsigned short) 17432);
    Xdr::write<CharIO>    (os, (signed int)  2023456789);
    Xdr::write<CharIO>    (os, (signed int) -2012345678);
    Xdr::write<CharIO>    (os, (unsigned int) 1234567890u);
    Xdr::write<CharIO>    (os, (unsigned int) 2345678901u);
    Xdr::write<CharIO>    (os, (signed long)  2034567890);
    Xdr::write<CharIO>    (os, (signed long) -2045678901);
    Xdr::write<CharIO>    (os, (unsigned long) 1345678901u);
    Xdr::write<CharIO>    (os, (unsigned long) 2456789012u);
    Xdr::write<CharIO>    (os, (Int64) 0x1122334455667788ll);
    Xdr::write<CharIO>    (os, (Int64) 0xf1f2f3f4f5f6f7f8ll);
    Xdr::write<CharIO>    (os, (float) 0.0f);
    Xdr::write<CharIO>    (os, (float) 3.141592653589793f);
    Xdr::write<CharIO>    (os, (float) 6.141592653589793f);
    Xdr::write<CharIO>    (os, (double) 0);
    Xdr::write<CharIO>    (os, (double) 1.41421356237309504880);
    Xdr::write<CharIO>    (os, (double) 2.41421356237309504880);
    Xdr::write<CharIO>    (os, (half) 0);
    Xdr::write<CharIO>    (os, (half) 3.4142);
    Xdr::write<CharIO>    (os, (half) 4.4142);
    Xdr::write<CharIO>    (os, "abcdefgh", 4);	// fixed-size char array
    Xdr::write<CharIO>    (os, "rstuvwxy", 5);
    Xdr::write<CharIO>    (os, "qwerty");	// zero-terminated string
    Xdr::write<CharIO>    (os, "asdfghjkl");
    Xdr::write<CharIO>    (os, "");
    Xdr::pad<CharIO>      (os, 17);
    Xdr::write<CharIO>    (os, (int) 1);
    Xdr::pad<CharIO>      (os, 0);
    Xdr::write<CharIO>    (os, (int) 2);
    Xdr::pad<CharIO>      (os, 17);
    Xdr::write<CharIO>    (os, (int) 3);

    assert (!os == false);
}

template <class T>
void
check (istream &is, T c)
{
    T v;

    Xdr::read<CharIO> (is, v);
    cout << typeid(v).name() << ": expected " << c << ", got " << v << endl;
    assert (c == v);
}

template <>
void
check (istream &is, const char * c)
{
    char v[1024];

    Xdr::read<CharIO> (is, sizeof (v), v);

    cout << "zero-terminated string: "
	    "expected \"" << c << "\", "
	    "got \"" << v << "\"" << endl;

    assert (!strcmp (c, v));
}

void
check (istream &is, const char c[/*n*/], int n)
{
    char v[1024];

    assert (n <= (int) sizeof (v));

    Xdr::read<CharIO> (is, v, n);

    cout << "char[" << n << "]: expected \"";

    for (int i = 0; i < n; i++)
	cout << c[i];

    cout << "\", got \"";

    for (int i = 0; i < n; i++)
	cout << v[i];

    cout << "\"" << endl;

    for (int i = 0; i < n; i++)
	assert (c[i] == v[i]);
}

void
readData (istream &is)
{
    check (is, (bool) true);
    check (is, (bool) false);
    check (is, (char) 'r');
    check (is, (char) 'e');
    check (is, (signed char) 'u');
    check (is, (signed char) 'c');
    check (is, (unsigned char) 'k');
    check (is, (unsigned char) 'y');
    check (is, (signed short)  8765);
    check (is, (signed short) -9876);
    check (is, (unsigned short)  6543);
    check (is, (unsigned short) 17432);
    check (is, (signed int)  2023456789);
    check (is, (signed int) -2012345678);
    check (is, (unsigned int) 1234567890u);
    check (is, (unsigned int) 2345678901u);
    check (is, (signed long)  2034567890);
    check (is, (signed long) -2045678901);
    check (is, (unsigned long) 1345678901u);
    check (is, (unsigned long) 2456789012u);
    check (is, (Int64) 0x1122334455667788ll);
    check (is, (Int64) 0xf1f2f3f4f5f6f7f8ll);
    check (is, (float) 0.0f);
    check (is, (float) 3.141592653589793f);
    check (is, (float) 6.141592653589793f);
    check (is, (double) 0.0);
    check (is, (double) 1.41421356237309504880);
    check (is, (double) 2.41421356237309504880);
    check (is, (half) 0);
    check (is, (half) 3.4142);
    check (is, (half) 4.4142);
    check (is, (const char *) "abcdefgh", 4);
    check (is, (const char *) "rstuvwxy", 5);
    check (is, (const char *) "qwerty");
    check (is, (const char *) "asdfghjkl");
    check (is, (const char *) "");
    Xdr::skip<CharIO>  (is, 17);
    check (is, (int) 1);
    Xdr::skip<CharIO>  (is, 0);
    check (is, (int) 2);
    Xdr::skip<CharIO>  (is, 17);
    check (is, (int) 3);

    assert (!is == false);
}

} // namespace

void
testXdr ()
{
    cout << "Testing Xdr" << endl;

    try
    {
#if defined (__GNUC__) && __GNUC__ == 2
	strstream s;
#else
	stringstream s;
#endif

	writeData (s);
	s.seekg (0);
	readData (s);
    }
    catch (const std::exception &e)
    {
	cout << "unexpected exception: " << e.what() << endl;
	assert (false);
    }
    catch (...)
    {
	cout << "unexpected exception" << endl;
	assert (false);
    }

    cout << "ok\n" << endl;
}
<commit_msg>added BROKEN_ISTREAM_HACK check to routines that bypass StdIO<commit_after>///////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2002, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// *       Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// *       Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// *       Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
///////////////////////////////////////////////////////////////////////////

#include <ImfXdr.h>
#include <ImfIO.h>
#include <typeinfo>
#include <string.h>
#include <assert.h>

#if defined (__GNUC__) && __GNUC__ == 2
#include <strstream.h>
#else
#include <sstream>
#endif

using namespace std;
using namespace Imf;

namespace {

struct CharIO
{
    static void
    writeChars (ostream &os, const char c[], int n)
    {
	os.write (c, n);
    }

    static bool
    readChars (istream &is, char c[], int n)
    {
	is.read (c, n);
	return true;
    }
};

void
writeData (ostream &os)
{
    Xdr::write<CharIO>    (os, (bool) true);
    Xdr::write<CharIO>    (os, (bool) false);
    Xdr::write<CharIO>    (os, (char) 'r');
    Xdr::write<CharIO>    (os, (char) 'e');
    Xdr::write<CharIO>    (os, (signed char) 'u');
    Xdr::write<CharIO>    (os, (signed char) 'c');
    Xdr::write<CharIO>    (os, (unsigned char) 'k');
    Xdr::write<CharIO>    (os, (unsigned char) 'y');
    Xdr::write<CharIO>    (os, (signed short)  8765);
    Xdr::write<CharIO>    (os, (signed short) -9876);
    Xdr::write<CharIO>    (os, (unsigned short)  6543);
    Xdr::write<CharIO>    (os, (unsigned short) 17432);
    Xdr::write<CharIO>    (os, (signed int)  2023456789);
    Xdr::write<CharIO>    (os, (signed int) -2012345678);
    Xdr::write<CharIO>    (os, (unsigned int) 1234567890u);
    Xdr::write<CharIO>    (os, (unsigned int) 2345678901u);
    Xdr::write<CharIO>    (os, (signed long)  2034567890);
    Xdr::write<CharIO>    (os, (signed long) -2045678901);
    Xdr::write<CharIO>    (os, (unsigned long) 1345678901u);
    Xdr::write<CharIO>    (os, (unsigned long) 2456789012u);
    Xdr::write<CharIO>    (os, (Int64) 0x1122334455667788ll);
    Xdr::write<CharIO>    (os, (Int64) 0xf1f2f3f4f5f6f7f8ll);
    Xdr::write<CharIO>    (os, (float) 0.0f);
    Xdr::write<CharIO>    (os, (float) 3.141592653589793f);
    Xdr::write<CharIO>    (os, (float) 6.141592653589793f);
    Xdr::write<CharIO>    (os, (double) 0);
    Xdr::write<CharIO>    (os, (double) 1.41421356237309504880);
    Xdr::write<CharIO>    (os, (double) 2.41421356237309504880);
    Xdr::write<CharIO>    (os, (half) 0);
    Xdr::write<CharIO>    (os, (half) 3.4142);
    Xdr::write<CharIO>    (os, (half) 4.4142);
    Xdr::write<CharIO>    (os, "abcdefgh", 4);	// fixed-size char array
    Xdr::write<CharIO>    (os, "rstuvwxy", 5);
    Xdr::write<CharIO>    (os, "qwerty");	// zero-terminated string
    Xdr::write<CharIO>    (os, "asdfghjkl");
    Xdr::write<CharIO>    (os, "");
    Xdr::pad<CharIO>      (os, 17);
    Xdr::write<CharIO>    (os, (int) 1);
    Xdr::pad<CharIO>      (os, 0);
    Xdr::write<CharIO>    (os, (int) 2);
    Xdr::pad<CharIO>      (os, 17);
    Xdr::write<CharIO>    (os, (int) 3);

    assert (!os == false);
}

template <class T>
void
check (istream &is, T c)
{
    T v;

    Xdr::read<CharIO> (is, v);
    cout << typeid(v).name() << ": expected " << c << ", got " << v << endl;
    assert (c == v);
}

template <>
void
check (istream &is, const char * c)
{
    char v[1024];

    Xdr::read<CharIO> (is, sizeof (v), v);

    cout << "zero-terminated string: "
	    "expected \"" << c << "\", "
	    "got \"" << v << "\"" << endl;

    assert (!strcmp (c, v));
}

void
check (istream &is, const char c[/*n*/], int n)
{
    char v[1024];

    assert (n <= (int) sizeof (v));

    Xdr::read<CharIO> (is, v, n);

    cout << "char[" << n << "]: expected \"";

    for (int i = 0; i < n; i++)
	cout << c[i];

    cout << "\", got \"";

    for (int i = 0; i < n; i++)
	cout << v[i];

    cout << "\"" << endl;

    for (int i = 0; i < n; i++)
	assert (c[i] == v[i]);
}

void
readData (istream &is)
{
    check (is, (bool) true);
    check (is, (bool) false);
    check (is, (char) 'r');
    check (is, (char) 'e');
    check (is, (signed char) 'u');
    check (is, (signed char) 'c');
    check (is, (unsigned char) 'k');
    check (is, (unsigned char) 'y');
    check (is, (signed short)  8765);
    check (is, (signed short) -9876);
    check (is, (unsigned short)  6543);
    check (is, (unsigned short) 17432);
    check (is, (signed int)  2023456789);
    check (is, (signed int) -2012345678);
    check (is, (unsigned int) 1234567890u);
    check (is, (unsigned int) 2345678901u);
    check (is, (signed long)  2034567890);
    check (is, (signed long) -2045678901);
    check (is, (unsigned long) 1345678901u);
    check (is, (unsigned long) 2456789012u);
    check (is, (Int64) 0x1122334455667788ll);
    check (is, (Int64) 0xf1f2f3f4f5f6f7f8ll);
    check (is, (float) 0.0f);
    check (is, (float) 3.141592653589793f);
    check (is, (float) 6.141592653589793f);
    check (is, (double) 0.0);
    check (is, (double) 1.41421356237309504880);
    check (is, (double) 2.41421356237309504880);
    check (is, (half) 0);
    check (is, (half) 3.4142);
    check (is, (half) 4.4142);
    check (is, (const char *) "abcdefgh", 4);
    check (is, (const char *) "rstuvwxy", 5);
    check (is, (const char *) "qwerty");
    check (is, (const char *) "asdfghjkl");
    check (is, (const char *) "");
    Xdr::skip<CharIO>  (is, 17);
    check (is, (int) 1);
    Xdr::skip<CharIO>  (is, 0);
    check (is, (int) 2);
    Xdr::skip<CharIO>  (is, 17);
    check (is, (int) 3);

	// HACK - this is a workaround for a bug in Apple's
	// implementation of istream::read.  It's present in
	// gcc 3.1, but fixed in gcc 3.3 and later.

#if !(BROKEN_ISTREAM_HACK)
    assert (!is == false);
#endif
}

} // namespace

void
testXdr ()
{
    cout << "Testing Xdr" << endl;

    try
    {
#if defined (__GNUC__) && __GNUC__ == 2
	strstream s;
#else
	stringstream s;
#endif

	writeData (s);
	s.seekg (0);
	readData (s);
    }
    catch (const std::exception &e)
    {
	cout << "unexpected exception: " << e.what() << endl;
	assert (false);
    }
    catch (...)
    {
	cout << "unexpected exception" << endl;
	assert (false);
    }

    cout << "ok\n" << endl;
}
<|endoftext|>


<commit_before><commit_msg>add missing DeleteTab in test<commit_after><|endoftext|>


<commit_before>#pragma once

#include <libkern/OSAtomic.h>

namespace blackhole {
inline namespace v1 {
namespace detail {

class spinlock_t {
    OSSpinLock mutex;

public:
    constexpr spinlock_t() noexcept:
        mutex(0)
    {}

    auto lock() noexcept -> void {
        OSSpinLockLock(&mutex);
    }

    auto unlock() noexcept -> void {
        OSSpinLockUnlock(&mutex);
    }

    auto trylock() noexcept -> bool {
        return OSSpinLockTry(&mutex);
    }
};

}  // namespace detail
}  // namespace v1
}  // namespace blackhole
<commit_msg>feat: replace deprecated OSX stuff with modern one<commit_after>#pragma once

#include <os/lock.h>

namespace blackhole {
inline namespace v1 {
namespace detail {

class spinlock_t {
    os_unfair_lock mutex;

public:
    constexpr spinlock_t() noexcept:
        mutex({0})
    {}

    auto lock() noexcept -> void {
        os_unfair_lock_lock(&mutex);
    }

    auto unlock() noexcept -> void {
        os_unfair_lock_unlock(&mutex);
    }

    auto trylock() noexcept -> bool {
        return os_unfair_lock_trylock(&mutex);
    }
};

}  // namespace detail
}  // namespace v1
}  // namespace blackhole
<|endoftext|>


<commit_before>#include "engine/selene/selene.h"
#include "engine/Game.hpp"

using namespace std;
using namespace sf;

class TestState : public GameState
{
public:
	TestState() : _main_open(false)
	{ }

	virtual void init() override
	{ }

	virtual void load_resources() override
	{ }

	virtual void unload_resources() override
	{ }

	virtual void update(Seconds) override
	{
		ImGui::Begin("Main", &_main_open, ImGuiWindowFlags_NoResize);
		ImGui::Text("Hello, world!");
		if (ImGui::Button("Exit"))
			game().quit(0);
		ImGui::End();
	}

	virtual void render() override
	{ }

protected:
	bool _main_open;
};

class TestGame : public Game
{
public:
	TestGame() : _stack(this)
	{ }

	virtual void init(int argc, char** argv) override
	{
		Game::init(argc, argv);
		_stack.push<TestState, PushType::PushWithoutPopping>();
	}

	virtual void frame_start() override
	{
		Game::frame_start();
	}

	virtual void process_event(sf::Event& e) override
	{
		Game::process_event(e);
	}

	virtual void update(Seconds delta_time) override
	{
		Game::update(delta_time);
		_stack.update(delta_time);
	}

	virtual void frame_end() override
	{
		_stack.render();
		Game::frame_end();
	}

private:
	GameStateStack _stack;
};

int main(int argc, char** argv)
{ return run<TestGame>(argc, argv); }
<commit_msg>Added a simple Lua test<commit_after>#include "engine/selene/selene.h"
#include "engine/Game.hpp"

using namespace std;
using namespace sf;

class TestState : public GameState
{
public:
	TestState() : _main_open(false)
	{ }

	virtual void init() override;

	virtual void load_resources() override;

	virtual void unload_resources() override;

	virtual void update(Seconds) override;

	virtual void render() override;

protected:
	bool _main_open;
};

class TestGame : public Game
{
public:
	TestGame() : _lua(true), _stack(this)
	{ }

	virtual void init(int argc, char** argv) override
	{
		Game::init(argc, argv);
		_stack.push<TestState, PushType::PushWithoutPopping>();
	}

	virtual void frame_start() override
	{
		Game::frame_start();
	}

	virtual void process_event(sf::Event& e) override
	{
		Game::process_event(e);
	}

	virtual void update(Seconds delta_time) override
	{
		Game::update(delta_time);
		_stack.update(delta_time);
	}

	virtual void frame_end() override
	{
		_stack.render();
		Game::frame_end();
	}

	sel::State& lua()
	{ return _lua; }

private:
	sel::State _lua;
	GameStateStack _stack;
};

int main(int argc, char** argv)
{ return run<TestGame>(argc, argv); }

void TestState::init()
{
	game<TestGame>().lua()("print('Hello Lua!')");
}

void TestState::load_resources()
{ }

void TestState::unload_resources()
{ }

void TestState::update(Seconds)
{
	ImGui::Begin("Main", &_main_open, ImGuiWindowFlags_NoResize);
	ImGui::Text("Hello, world!");
	if (ImGui::Button("Exit"))
		game<TestGame>().quit(0);
	ImGui::End();
}

void TestState::render()
{ }
<|endoftext|>


<commit_before>
// .\Release\x64\benchmarks.exe --benchmark_repetitions=10 --benchmark_min_time=2 --benchmark_filter=Elliptic  // NOLINT(whitespace/line_length)

#include <random>
#include <vector>

#include "base/tags.hpp"
#include "benchmark/benchmark.h"
#include "numerics/elliptic_integrals.hpp"
#include "quantities/numbers.hpp"
#include "quantities/si.hpp"

namespace principia {

using base::uninitialized;
using quantities::Angle;
using quantities::si::Radian;

namespace numerics {

void BM_EllipticFEΠ(benchmark::State& state) {
  constexpr int size = 20;

  std::mt19937_64 random(42);
  std::uniform_real_distribution<> distribution_φ(0.0, π / 2);
  std::uniform_real_distribution<> distribution_n(0.0, 1.0);
  std::uniform_real_distribution<> distribution_mc(0.0, 1.0);
  std::vector<Angle> φs;
  std::vector<double> ns;
  std::vector<double> mcs;
  for (int i = 0; i < size; ++i) {
    φs.push_back(distribution_φ(random) * Radian);
    ns.push_back(distribution_n(random));
    mcs.push_back(distribution_mc(random));
  }

  while (state.KeepRunningBatch(size * size * size)) {
    Angle e{uninitialized};
    Angle f{uninitialized};
    Angle ᴨ{uninitialized};
    for (Angle const φ : φs) {
      for (double const n : ns) {
        for (double const mc : mcs) {
          EllipticFEΠ(φ, n, mc, f, e, ᴨ);
        }
      }
    }
    benchmark::DoNotOptimize(e);
    benchmark::DoNotOptimize(f);
    benchmark::DoNotOptimize(ᴨ);
  }
}

void BM_FukushimaEllipticBDJ(benchmark::State& state) {
  constexpr int size = 20;

  std::mt19937_64 random(42);
  std::uniform_real_distribution<> distribution_φ(0.0, π / 2);
  std::uniform_real_distribution<> distribution_n(0.0, 1.0);
  std::uniform_real_distribution<> distribution_mc(0.0, 1.0);
  std::vector<Angle> φs;
  std::vector<double> ns;
  std::vector<double> mcs;
  for (int i = 0; i < size; ++i) {
    φs.push_back(distribution_φ(random) * Radian);
    ns.push_back(distribution_n(random));
    mcs.push_back(distribution_mc(random));
  }

  while (state.KeepRunningBatch(size * size * size)) {
    Angle b{uninitialized};
    Angle d{uninitialized};
    Angle j{uninitialized};
    for (Angle const φ : φs) {
      for (double const n : ns) {
        for (double const mc : mcs) {
          FukushimaEllipticBDJ(φ, n, mc, b, d, j);
        }
      }
    }
    benchmark::DoNotOptimize(b);
    benchmark::DoNotOptimize(d);
    benchmark::DoNotOptimize(j);
  }
}

BENCHMARK(BM_EllipticFEΠ);
BENCHMARK(BM_FukushimaEllipticBDJ);

}  // namespace numerics
}  // namespace principia
<commit_msg>benchmark<commit_after>
// .\Release\x64\benchmarks.exe --benchmark_repetitions=10 --benchmark_min_time=2 --benchmark_filter=Elliptic  // NOLINT(whitespace/line_length)

#include <random>
#include <vector>

#include "base/tags.hpp"
#include "benchmark/benchmark.h"
#include "numerics/elliptic_integrals.hpp"
#include "quantities/numbers.hpp"
#include "quantities/si.hpp"

namespace principia {

using base::uninitialized;
using quantities::Angle;
using quantities::si::Radian;

namespace numerics {

void BM_EllipticF(benchmark::State& state) {
  constexpr int size = 20;

  std::mt19937_64 random(42);
  std::uniform_real_distribution<> distribution_φ(0.0, π / 2);
  std::uniform_real_distribution<> distribution_n(0.0, 1.0);
  std::uniform_real_distribution<> distribution_mc(0.0, 1.0);
  std::vector<Angle> φs;
  std::vector<double> ns;
  std::vector<double> mcs;
  for (int i = 0; i < size; ++i) {
    φs.push_back(distribution_φ(random) * Radian);
    ns.push_back(distribution_n(random));
    mcs.push_back(distribution_mc(random));
  }

  while (state.KeepRunningBatch(size * size * size)) {
    Angle f;
    for (Angle const φ : φs) {
      for (double const n : ns) {
        for (double const mc : mcs) {
          f += EllipticF(φ, mc);
        }
      }
    }
    benchmark::DoNotOptimize(f);
  }
}

void BM_EllipticFEΠ(benchmark::State& state) {
  constexpr int size = 20;

  std::mt19937_64 random(42);
  std::uniform_real_distribution<> distribution_φ(0.0, π / 2);
  std::uniform_real_distribution<> distribution_n(0.0, 1.0);
  std::uniform_real_distribution<> distribution_mc(0.0, 1.0);
  std::vector<Angle> φs;
  std::vector<double> ns;
  std::vector<double> mcs;
  for (int i = 0; i < size; ++i) {
    φs.push_back(distribution_φ(random) * Radian);
    ns.push_back(distribution_n(random));
    mcs.push_back(distribution_mc(random));
  }

  while (state.KeepRunningBatch(size * size * size)) {
    Angle e{uninitialized};
    Angle f{uninitialized};
    Angle ᴨ{uninitialized};
    for (Angle const φ : φs) {
      for (double const n : ns) {
        for (double const mc : mcs) {
          EllipticFEΠ(φ, n, mc, f, e, ᴨ);
        }
      }
    }
    benchmark::DoNotOptimize(e);
    benchmark::DoNotOptimize(f);
    benchmark::DoNotOptimize(ᴨ);
  }
}

void BM_FukushimaEllipticBDJ(benchmark::State& state) {
  constexpr int size = 20;

  std::mt19937_64 random(42);
  std::uniform_real_distribution<> distribution_φ(0.0, π / 2);
  std::uniform_real_distribution<> distribution_n(0.0, 1.0);
  std::uniform_real_distribution<> distribution_mc(0.0, 1.0);
  std::vector<Angle> φs;
  std::vector<double> ns;
  std::vector<double> mcs;
  for (int i = 0; i < size; ++i) {
    φs.push_back(distribution_φ(random) * Radian);
    ns.push_back(distribution_n(random));
    mcs.push_back(distribution_mc(random));
  }

  while (state.KeepRunningBatch(size * size * size)) {
    Angle b{uninitialized};
    Angle d{uninitialized};
    Angle j{uninitialized};
    for (Angle const φ : φs) {
      for (double const n : ns) {
        for (double const mc : mcs) {
          FukushimaEllipticBDJ(φ, n, mc, b, d, j);
        }
      }
    }
    benchmark::DoNotOptimize(b);
    benchmark::DoNotOptimize(d);
    benchmark::DoNotOptimize(j);
  }
}

BENCHMARK(BM_EllipticF);
BENCHMARK(BM_EllipticFEΠ);
BENCHMARK(BM_FukushimaEllipticBDJ);

}  // namespace numerics
}  // namespace principia
<|endoftext|>


<commit_before>// Copyright (C) 2010-2013 Joshua Boyce.
// See the file COPYING for copying permission.

#pragma once

#include <cstddef>
#include <iosfwd>
#include <memory>
#include <ostream>
#include <utility>

#include <windows.h>
#include <winnt.h>

#include <hadesmem/config.hpp>
#include <hadesmem/detail/assert.hpp>
#include <hadesmem/error.hpp>
#include <hadesmem/process.hpp>
#include <hadesmem/read.hpp>

// TODO: Extra sanity checking in all components. E.g. Check
// NumberOfRvaAndSizes in NtHeaders before attempting to retrieve a data dir.

// TODO: Helper functions such as FindExport, FindImport, HasDataDir,
// GetArchitecture, IsDotNet, GetPDB, etc.

// TODO: Move PeLib code into PeLib namespace.

// TODO: Rewrite PeLib to allow writes from scratch (building new PE file
// sections, data, etc. or even an entire mew PE file). This includes full
// support for writing back to existing PE files also, including automatically
// performing adjustments where required to fit in new data or remove
// unnecessary space.

// TODO: Decouple PeFile from Process. It should use a generic interface
// instead.	Another potential alternative would be policy classes. Needs
// investigation.

// TODO: Decouple PeLib from the architecture being compiled for. Required
// for cross-architecture support in hadesmem.

// TODO: Support more of the PE file format.
// Overlay data.
// Resource directory.
// Exception directory.
// Relocation directory.
// Security directory.
// Debug directory.
// Load config directory.
// Delay import directory.
// Bound import directory.
// IAT(as opposed to Import) directory.
// CLR runtime directory support.
// DOS stub.
// Rich header.
// Checksum.
// etc.

// TODO: Improve PeLib support for pathological cases like Corkami tests. We
// should not only ensure we don't crash, but we should also ensure we're
// actually getting the right data out!

// TODO: Where possible, document the SHA1 of example files which prompted the
// addition of corner cases.

namespace hadesmem
{

// TODO: Investigate whether there is a better way to implement this.
enum class PeFileType
{
  Image,
  Data
};

class PeFile
{
public:
  explicit PeFile(Process const& process,
                  PVOID address,
                  PeFileType type,
                  DWORD size)
    : base_(static_cast<PBYTE>(address)), type_(type), size_(size)
  {
    HADESMEM_DETAIL_ASSERT(base_ != 0);
    if (type == PeFileType::Data && !size)
    {
      HADESMEM_DETAIL_THROW_EXCEPTION(Error()
                                      << ErrorString("Invalid file size."));
    }

    // Process is not actually used but we take it anyway for
    // interface symetry and in case we want to change the
    // implementation to use it later without breaking the interface.
    (void)process;
  }

  PVOID GetBase() const HADESMEM_DETAIL_NOEXCEPT
  {
    return base_;
  }

  PeFileType GetType() const HADESMEM_DETAIL_NOEXCEPT
  {
    return type_;
  }

  DWORD GetSize() const HADESMEM_DETAIL_NOEXCEPT
  {
    return size_;
  }

private:
  PBYTE base_;
  PeFileType type_;
  DWORD size_;
};

inline bool operator==(PeFile const& lhs, PeFile const& rhs)
  HADESMEM_DETAIL_NOEXCEPT
{
  return lhs.GetBase() == rhs.GetBase();
}

inline bool operator!=(PeFile const& lhs, PeFile const& rhs)
  HADESMEM_DETAIL_NOEXCEPT
{
  return !(lhs == rhs);
}

inline bool operator<(PeFile const& lhs, PeFile const& rhs)
  HADESMEM_DETAIL_NOEXCEPT
{
  return lhs.GetBase() < rhs.GetBase();
}

inline bool operator<=(PeFile const& lhs, PeFile const& rhs)
  HADESMEM_DETAIL_NOEXCEPT
{
  return lhs.GetBase() <= rhs.GetBase();
}

inline bool operator>(PeFile const& lhs, PeFile const& rhs)
  HADESMEM_DETAIL_NOEXCEPT
{
  return lhs.GetBase() > rhs.GetBase();
}

inline bool operator>=(PeFile const& lhs, PeFile const& rhs)
  HADESMEM_DETAIL_NOEXCEPT
{
  return lhs.GetBase() >= rhs.GetBase();
}

inline std::ostream& operator<<(std::ostream& lhs, PeFile const& rhs)
{
  std::locale const old = lhs.imbue(std::locale::classic());
  lhs << static_cast<void*>(rhs.GetBase());
  lhs.imbue(old);
  return lhs;
}

inline std::wostream& operator<<(std::wostream& lhs, PeFile const& rhs)
{
  std::locale const old = lhs.imbue(std::locale::classic());
  lhs << static_cast<void*>(rhs.GetBase());
  lhs.imbue(old);
  return lhs;
}

inline PVOID RvaToVa(Process const& process, PeFile const& pe_file, DWORD rva)
{
  PeFileType const type = pe_file.GetType();
  PBYTE base = static_cast<PBYTE>(pe_file.GetBase());

  if (type == PeFileType::Data)
  {
    if (!rva)
    {
      return nullptr;
    }

    IMAGE_DOS_HEADER dos_header = Read<IMAGE_DOS_HEADER>(process, base);
    if (dos_header.e_magic != IMAGE_DOS_SIGNATURE)
    {
      HADESMEM_DETAIL_THROW_EXCEPTION(Error()
                                      << ErrorString("Invalid DOS header."));
    }

    BYTE* ptr_nt_headers = base + dos_header.e_lfanew;
    IMAGE_NT_HEADERS nt_headers =
      Read<IMAGE_NT_HEADERS>(process, ptr_nt_headers);
    if (nt_headers.Signature != IMAGE_NT_SIGNATURE)
    {
      HADESMEM_DETAIL_THROW_EXCEPTION(Error()
                                      << ErrorString("Invalid NT headers."));
    }

    // Windows will load specially crafted images with no sections.
    // TODO: Improve the logic here using the information in "Zero section PE
    // file" in ReversingLabs "Undocumented PECOFF" whitepaper.
    WORD num_sections = nt_headers.FileHeader.NumberOfSections;
    if (!num_sections)
    {
      // In cases where the PE file has no sections it can apparently also have
      // all sorts of messed up RVAs for data dirs etc... Make sure that none of
      // them lie outside the file, because otherwise simply returning a direct
      // offset from the base wouldn't work anyway...
      if (rva > pe_file.GetSize())
      {
        return nullptr;
      }
      else
      {
        return base + rva;
      }
    }

    // SizeOfHeaders can be arbitrarily large, including the size of the
    // entire file. RVAs inside the headers are treated as an offset from
    // zero, rather than finding the 'true' location in a section.
    if (rva < nt_headers.OptionalHeader.SizeOfHeaders)
    {
      return base + rva;
    }

    // Apparently on XP it's possible to load a PE with a SizeOfImage of only
    // 0x2e. Treat anything outside of that as invalid. For an example see
    // foldedhdr.exe from the Corkami PE corpus.
    // TODO: According to ReversingLabs "Undocumented PECOFF" whitepaper,
    // SizeOfImage should be rounded up using SectionAlignment. Investigate
    // this.
    if (rva > nt_headers.OptionalHeader.SizeOfImage)
    {
      return nullptr;
    }

    IMAGE_SECTION_HEADER* ptr_section_header =
      reinterpret_cast<PIMAGE_SECTION_HEADER>(
        ptr_nt_headers + offsetof(IMAGE_NT_HEADERS, OptionalHeader) +
        nt_headers.FileHeader.SizeOfOptionalHeader);
    IMAGE_SECTION_HEADER section_header =
      Read<IMAGE_SECTION_HEADER>(process, ptr_section_header);

    bool in_header = true;
    for (WORD i = 0; i < num_sections; ++i)
    {
      DWORD const virtual_beg = section_header.VirtualAddress;
      DWORD const virtual_size = section_header.Misc.VirtualSize;
      DWORD const raw_size = section_header.SizeOfRawData;
      // If VirtualSize is zero then SizeOfRawData is used.
      DWORD const virtual_end =
        virtual_beg + (virtual_size ? virtual_size : raw_size);
      if (virtual_beg <= rva && rva < virtual_end)
      {
        rva -= virtual_beg;

        // If the RVA is outside the raw data (which would put it in the
        // zero-fill of the virtual data) just return nullptr because it's
        // invalid. Technically files like this will work when loaded by the
        // PE loader due to the sections being mapped differention in memory
        // to on disk, but if you want to inspect the file in that manner you
        // should just use LoadLibrary with the appropriate flags for your
        // scenario and then use PeFileType::Image.
        if (rva > raw_size)
        {
          return nullptr;
        }

        // If PointerToRawData is less than 0x200 it is rounded
        // down to 0. Safe to mask it off unconditionally because
        // it must be a multiple of FileAlignment.
        rva +=
          section_header.PointerToRawData &
          ~((std::max)(0x200UL, nt_headers.OptionalHeader.FileAlignment) - 1);

        // If the RVA now lies outside the actual file just return nullptr
        // because it's invalid.
        if (rva >= pe_file.GetSize())
        {
          return nullptr;
        }

        return base + rva;
      }

      // This should be the 'normal' case. However sometimes the RVA is at a
      // lower address than any of the sections, so we want to detect this so we
      // can just treat the RVA as an offset from the module base (similar to
      // when the image is loaded).
      if (virtual_beg <= rva)
      {
        in_header = false;
      }

      section_header =
        Read<IMAGE_SECTION_HEADER>(process, ++ptr_section_header);
    }

    if (in_header && rva < pe_file.GetSize())
    {
      return base + rva;
    }

    return nullptr;
  }
  else if (type == PeFileType::Image)
  {
    return rva ? (base + rva) : nullptr;
  }
  else
  {
    HADESMEM_DETAIL_THROW_EXCEPTION(Error()
                                    << ErrorString("Unhandled file type."));
  }
}
}
<commit_msg>* [PeFile] Note to self.<commit_after>// Copyright (C) 2010-2013 Joshua Boyce.
// See the file COPYING for copying permission.

#pragma once

#include <cstddef>
#include <iosfwd>
#include <memory>
#include <ostream>
#include <utility>

#include <windows.h>
#include <winnt.h>

#include <hadesmem/config.hpp>
#include <hadesmem/detail/assert.hpp>
#include <hadesmem/error.hpp>
#include <hadesmem/process.hpp>
#include <hadesmem/read.hpp>

// TODO: Extra sanity checking in all components. E.g. Check
// NumberOfRvaAndSizes in NtHeaders before attempting to retrieve a data dir.

// TODO: Helper functions such as FindExport, FindImport, HasDataDir,
// GetArchitecture, IsDotNet, GetPDB, etc.

// TODO: Move PeLib code into PeLib namespace.

// TODO: Rewrite PeLib to allow writes from scratch (building new PE file
// sections, data, etc. or even an entire mew PE file). This includes full
// support for writing back to existing PE files also, including automatically
// performing adjustments where required to fit in new data or remove
// unnecessary space.

// TODO: Decouple PeFile from Process (and other memory APIs). It should use a
// generic interface instead.	Another potential alternative would be policy
// classes. Needs investigation.

// TODO: Decouple PeLib from the architecture being compiled for. Required
// for cross-architecture support in hadesmem.

// TODO: Support more of the PE file format.
// Overlay data.
// Resource directory.
// Exception directory.
// Relocation directory.
// Security directory.
// Debug directory.
// Load config directory.
// Delay import directory.
// Bound import directory.
// IAT(as opposed to Import) directory.
// CLR runtime directory support.
// DOS stub.
// Rich header.
// Checksum.
// etc.

// TODO: Improve PeLib support for pathological cases like Corkami tests. We
// should not only ensure we don't crash, but we should also ensure we're
// actually getting the right data out!

// TODO: Where possible, document the SHA1 of example files which prompted the
// addition of corner cases.

namespace hadesmem
{

// TODO: Investigate whether there is a better way to implement this.
enum class PeFileType
{
  Image,
  Data
};

class PeFile
{
public:
  explicit PeFile(Process const& process,
                  PVOID address,
                  PeFileType type,
                  DWORD size)
    : base_(static_cast<PBYTE>(address)), type_(type), size_(size)
  {
    HADESMEM_DETAIL_ASSERT(base_ != 0);
    if (type == PeFileType::Data && !size)
    {
      HADESMEM_DETAIL_THROW_EXCEPTION(Error()
                                      << ErrorString("Invalid file size."));
    }

    // Process is not actually used but we take it anyway for
    // interface symetry and in case we want to change the
    // implementation to use it later without breaking the interface.
    (void)process;
  }

  PVOID GetBase() const HADESMEM_DETAIL_NOEXCEPT
  {
    return base_;
  }

  PeFileType GetType() const HADESMEM_DETAIL_NOEXCEPT
  {
    return type_;
  }

  DWORD GetSize() const HADESMEM_DETAIL_NOEXCEPT
  {
    return size_;
  }

private:
  PBYTE base_;
  PeFileType type_;
  DWORD size_;
};

inline bool operator==(PeFile const& lhs, PeFile const& rhs)
  HADESMEM_DETAIL_NOEXCEPT
{
  return lhs.GetBase() == rhs.GetBase();
}

inline bool operator!=(PeFile const& lhs, PeFile const& rhs)
  HADESMEM_DETAIL_NOEXCEPT
{
  return !(lhs == rhs);
}

inline bool operator<(PeFile const& lhs, PeFile const& rhs)
  HADESMEM_DETAIL_NOEXCEPT
{
  return lhs.GetBase() < rhs.GetBase();
}

inline bool operator<=(PeFile const& lhs, PeFile const& rhs)
  HADESMEM_DETAIL_NOEXCEPT
{
  return lhs.GetBase() <= rhs.GetBase();
}

inline bool operator>(PeFile const& lhs, PeFile const& rhs)
  HADESMEM_DETAIL_NOEXCEPT
{
  return lhs.GetBase() > rhs.GetBase();
}

inline bool operator>=(PeFile const& lhs, PeFile const& rhs)
  HADESMEM_DETAIL_NOEXCEPT
{
  return lhs.GetBase() >= rhs.GetBase();
}

inline std::ostream& operator<<(std::ostream& lhs, PeFile const& rhs)
{
  std::locale const old = lhs.imbue(std::locale::classic());
  lhs << static_cast<void*>(rhs.GetBase());
  lhs.imbue(old);
  return lhs;
}

inline std::wostream& operator<<(std::wostream& lhs, PeFile const& rhs)
{
  std::locale const old = lhs.imbue(std::locale::classic());
  lhs << static_cast<void*>(rhs.GetBase());
  lhs.imbue(old);
  return lhs;
}

inline PVOID RvaToVa(Process const& process, PeFile const& pe_file, DWORD rva)
{
  PeFileType const type = pe_file.GetType();
  PBYTE base = static_cast<PBYTE>(pe_file.GetBase());

  if (type == PeFileType::Data)
  {
    if (!rva)
    {
      return nullptr;
    }

    IMAGE_DOS_HEADER dos_header = Read<IMAGE_DOS_HEADER>(process, base);
    if (dos_header.e_magic != IMAGE_DOS_SIGNATURE)
    {
      HADESMEM_DETAIL_THROW_EXCEPTION(Error()
                                      << ErrorString("Invalid DOS header."));
    }

    BYTE* ptr_nt_headers = base + dos_header.e_lfanew;
    IMAGE_NT_HEADERS nt_headers =
      Read<IMAGE_NT_HEADERS>(process, ptr_nt_headers);
    if (nt_headers.Signature != IMAGE_NT_SIGNATURE)
    {
      HADESMEM_DETAIL_THROW_EXCEPTION(Error()
                                      << ErrorString("Invalid NT headers."));
    }

    // Windows will load specially crafted images with no sections.
    // TODO: Improve the logic here using the information in "Zero section PE
    // file" in ReversingLabs "Undocumented PECOFF" whitepaper.
    WORD num_sections = nt_headers.FileHeader.NumberOfSections;
    if (!num_sections)
    {
      // In cases where the PE file has no sections it can apparently also have
      // all sorts of messed up RVAs for data dirs etc... Make sure that none of
      // them lie outside the file, because otherwise simply returning a direct
      // offset from the base wouldn't work anyway...
      if (rva > pe_file.GetSize())
      {
        return nullptr;
      }
      else
      {
        return base + rva;
      }
    }

    // SizeOfHeaders can be arbitrarily large, including the size of the
    // entire file. RVAs inside the headers are treated as an offset from
    // zero, rather than finding the 'true' location in a section.
    if (rva < nt_headers.OptionalHeader.SizeOfHeaders)
    {
      return base + rva;
    }

    // Apparently on XP it's possible to load a PE with a SizeOfImage of only
    // 0x2e. Treat anything outside of that as invalid. For an example see
    // foldedhdr.exe from the Corkami PE corpus.
    // TODO: According to ReversingLabs "Undocumented PECOFF" whitepaper,
    // SizeOfImage should be rounded up using SectionAlignment. Investigate
    // this.
    if (rva > nt_headers.OptionalHeader.SizeOfImage)
    {
      return nullptr;
    }

    IMAGE_SECTION_HEADER* ptr_section_header =
      reinterpret_cast<PIMAGE_SECTION_HEADER>(
        ptr_nt_headers + offsetof(IMAGE_NT_HEADERS, OptionalHeader) +
        nt_headers.FileHeader.SizeOfOptionalHeader);
    IMAGE_SECTION_HEADER section_header =
      Read<IMAGE_SECTION_HEADER>(process, ptr_section_header);

    bool in_header = true;
    for (WORD i = 0; i < num_sections; ++i)
    {
      DWORD const virtual_beg = section_header.VirtualAddress;
      DWORD const virtual_size = section_header.Misc.VirtualSize;
      DWORD const raw_size = section_header.SizeOfRawData;
      // If VirtualSize is zero then SizeOfRawData is used.
      DWORD const virtual_end =
        virtual_beg + (virtual_size ? virtual_size : raw_size);
      if (virtual_beg <= rva && rva < virtual_end)
      {
        rva -= virtual_beg;

        // If the RVA is outside the raw data (which would put it in the
        // zero-fill of the virtual data) just return nullptr because it's
        // invalid. Technically files like this will work when loaded by the
        // PE loader due to the sections being mapped differention in memory
        // to on disk, but if you want to inspect the file in that manner you
        // should just use LoadLibrary with the appropriate flags for your
        // scenario and then use PeFileType::Image.
        if (rva > raw_size)
        {
          return nullptr;
        }

        // If PointerToRawData is less than 0x200 it is rounded
        // down to 0. Safe to mask it off unconditionally because
        // it must be a multiple of FileAlignment.
        rva +=
          section_header.PointerToRawData &
          ~((std::max)(0x200UL, nt_headers.OptionalHeader.FileAlignment) - 1);

        // If the RVA now lies outside the actual file just return nullptr
        // because it's invalid.
        if (rva >= pe_file.GetSize())
        {
          return nullptr;
        }

        return base + rva;
      }

      // This should be the 'normal' case. However sometimes the RVA is at a
      // lower address than any of the sections, so we want to detect this so we
      // can just treat the RVA as an offset from the module base (similar to
      // when the image is loaded).
      if (virtual_beg <= rva)
      {
        in_header = false;
      }

      section_header =
        Read<IMAGE_SECTION_HEADER>(process, ++ptr_section_header);
    }

    if (in_header && rva < pe_file.GetSize())
    {
      return base + rva;
    }

    return nullptr;
  }
  else if (type == PeFileType::Image)
  {
    return rva ? (base + rva) : nullptr;
  }
  else
  {
    HADESMEM_DETAIL_THROW_EXCEPTION(Error()
                                    << ErrorString("Unhandled file type."));
  }
}
}
<|endoftext|>


<commit_before>///
/// @file   PushBackPrimes.hpp
/// @brief  This file contains classes needed to store primes in
///         std::vector objects. These classes derive from
///         PrimeSieveCallback and call PrimeSieve's callbackPrimes()
///         method, the primes are then pushed back into the vector
///         inside the callback method.
///
/// Copyright (C) 2013 Kim Walisch, <kim.walisch@gmail.com>
///
/// This file is distributed under the BSD License. See the COPYING
/// file in the top level directory.
///

#ifndef PUSHBACKPRIMES_HPP
#define PUSHBACKPRIMES_HPP

#include "PrimeSieve.hpp"
#include "PrimeSieveCallback.hpp"
#include "cancel_callback.hpp"

#include <stdint.h>
#include <algorithm>
#include <cmath>
#include <limits>
#include <vector>

namespace soe {

/// approximate_prime_count(x) > pi(x)
inline uint64_t approximate_prime_count(uint64_t start, uint64_t stop)
{
  if (start > stop)
    return 0;
  if (stop < 10)
    return 10;
  return static_cast<uint64_t>((stop - start) / (std::log(static_cast<double>(stop)) - 1.1));
}

template <typename T>
class PushBackPrimes : public PrimeSieveCallback<uint64_t>
{
public:
  PushBackPrimes(std::vector<T>& primes)
    : primes_(primes)
  { }
  void pushBackPrimes(uint64_t start, uint64_t stop)
  {
    if (start <= stop)
    {
      uint64_t prime_count = approximate_prime_count(start, stop);
      uint64_t limit = std::numeric_limits<std::size_t>::max();
      primes_.reserve(primes_.size() + static_cast<std::size_t>(std::min(prime_count, limit)));
      PrimeSieve ps;
      ps.callbackPrimes(start, stop, this);
    }
  }
  void callback(uint64_t prime)
  {
    primes_.push_back(static_cast<T>(prime));
  }
private:
  PushBackPrimes(const PushBackPrimes&);
  void operator=(const PushBackPrimes&);
  std::vector<T>& primes_;
};

template <typename T>
class PushBack_N_Primes : public PrimeSieveCallback<uint64_t>
{
public:
  PushBack_N_Primes(std::vector<T>& primes)
    : primes_(primes)
  { }
  void pushBack_N_Primes(uint64_t n, uint64_t start)
  {
    n_ = n;
    primes_.reserve(primes_.size() + n_);
    PrimeSieve ps;
    try
    {
      while (n_ > 0)
      {
        uint64_t logn = 50;
        // choose stop > nth prime
        uint64_t stop = start + n_ * logn + 10000;
        ps.callbackPrimes(start, stop, this);
        start = stop + 1;
      }
    }
    catch (cancel_callback&) { }
  }
  void callback(uint64_t prime)
  {
    primes_.push_back(static_cast<T>(prime));
    if (--n_ == 0)
      throw cancel_callback();
  }
  private:
    PushBack_N_Primes(const PushBack_N_Primes&);
    void operator=(const PushBack_N_Primes&);
    std::vector<T>& primes_;
    uint64_t n_;
};

} // namespace soe

#endif
<commit_msg>Silence sunCC warning<commit_after>///
/// @file   PushBackPrimes.hpp
/// @brief  This file contains classes needed to store primes in
///         std::vector objects. These classes derive from
///         PrimeSieveCallback and call PrimeSieve's callbackPrimes()
///         method, the primes are then pushed back into the vector
///         inside the callback method.
///
/// Copyright (C) 2013 Kim Walisch, <kim.walisch@gmail.com>
///
/// This file is distributed under the BSD License. See the COPYING
/// file in the top level directory.
///

#ifndef PUSHBACKPRIMES_HPP
#define PUSHBACKPRIMES_HPP

#include "PrimeSieve.hpp"
#include "PrimeSieveCallback.hpp"
#include "cancel_callback.hpp"
#include "primesieve_error.hpp"

#include <stdint.h>
#include <algorithm>
#include <cmath>
#include <limits>
#include <vector>

namespace soe {

/// approximate_prime_count(x) > pi(x)
inline uint64_t approximate_prime_count(uint64_t start, uint64_t stop)
{
  if (start > stop)
    return 0;
  if (stop < 10)
    return 10;
  return static_cast<uint64_t>((stop - start) / (std::log(static_cast<double>(stop)) - 1.1));
}

template <typename T>
class PushBackPrimes : public PrimeSieveCallback<uint64_t>
{
public:
  PushBackPrimes(std::vector<T>& primes)
    : primes_(primes)
  { }
  void pushBackPrimes(uint64_t start, uint64_t stop)
  {
    if (start <= stop)
    {
      uint64_t prime_count = approximate_prime_count(start, stop);
      if (prime_count > std::numeric_limits<std::size_t>::max())
        throw primesieve_error("cannot generate number of primes > SIZE_MAX (max(size_t))");
      primes_.reserve(primes_.size() + static_cast<std::size_t>(prime_count));
      PrimeSieve ps;
      ps.callbackPrimes(start, stop, this);
    }
  }
  void callback(uint64_t prime)
  {
    primes_.push_back(static_cast<T>(prime));
  }
private:
  PushBackPrimes(const PushBackPrimes&);
  void operator=(const PushBackPrimes&);
  std::vector<T>& primes_;
};

template <typename T>
class PushBack_N_Primes : public PrimeSieveCallback<uint64_t>
{
public:
  PushBack_N_Primes(std::vector<T>& primes)
    : primes_(primes)
  { }
  void pushBack_N_Primes(uint64_t n, uint64_t start)
  {
    n_ = n;
    if (n_ > std::numeric_limits<std::size_t>::max())
      throw primesieve_error("cannot generate number of primes > SIZE_MAX (max(size_t))");
    primes_.reserve(primes_.size() + static_cast<std::size_t>(n_));
    PrimeSieve ps;
    try
    {
      while (n_ > 0)
      {
        uint64_t logn = 50;
        // choose stop > nth prime
        uint64_t stop = start + n_ * logn + 10000;
        ps.callbackPrimes(start, stop, this);
        start = stop + 1;
      }
    }
    catch (cancel_callback&) { }
  }
  void callback(uint64_t prime)
  {
    primes_.push_back(static_cast<T>(prime));
    if (--n_ == 0)
      throw cancel_callback();
  }
  private:
    PushBack_N_Primes(const PushBack_N_Primes&);
    void operator=(const PushBack_N_Primes&);
    std::vector<T>& primes_;
    uint64_t n_;
};

} // namespace soe

#endif
<|endoftext|>


<commit_before>#pragma once

#include "indices_2d.hxx"
#include "../math/circular_modulus.hxx"

#include <boost/circular_buffer.hpp>
#include <cstdint>
#include <functional>

namespace usagi
{
  namespace container
  {
    template
    < typename T >
    class circular_tile
      : boost::circular_buffer< boost::circular_buffer< T > >
    {
    public:
      using type = circular_tile<T>;

      using cols_type = boost::circular_buffer< T >;
      using rows_type = boost::circular_buffer< cols_type >;

      using operate_cols_functor_signature = auto ( cols_type& ) -> void;
      using operate_cols_functor_type = std::function< operate_cols_functor_signature >;

      using apply_functor_signature = auto ( T& ) -> void;
      using apply_functor_type = std::function< apply_functor_signature >;

      using on_arris_resize_functor_signature = auto ( const type& ref, std::size_t new_size ) -> void;
      using on_arris_resize_functor_type = std::function< on_arris_resize_functor_signature >;

    protected:

      inline static auto make_cols( const std::size_t size, const T& default_value = T() )
      { return cols_type( size, default_value ); }

      auto make_cols( const T& default_value = T() )
      { return make_cols( rows_type::front().size(), default_value ); }

      template < typename DATA_TYPE = std::initializer_list<T> >
      auto make_cols( const DATA_TYPE& data )
      {
        cols_type cols( rows_type::front().size() );
        for ( const auto& datum : data )
          cols.push_back( datum );
        return cols;
      }

      template < typename VALUE_TYPE, typename MESSAGE_TYPE >
      inline static auto throw_if_zero( const VALUE_TYPE value, const MESSAGE_TYPE& message )
      {
        if ( value == 0 )
          throw std::logic_error( message );
      }

    public:

      on_arris_resize_functor_type on_cols_resize_before;
      on_arris_resize_functor_type on_cols_resize_after;

      on_arris_resize_functor_type on_rows_resize_before;
      on_arris_resize_functor_type on_rows_resize_after;

      circular_tile( const std::size_t cols_size, const std::size_t rows_size, const T& default_value = T() )
        : rows_type( rows_size, make_cols( cols_size, default_value ) )
        , on_cols_resize_before( get_nothing_functor_on_arris_resize() )
        , on_cols_resize_after ( get_nothing_functor_on_arris_resize() )
        , on_rows_resize_before( get_nothing_functor_on_arris_resize() )
        , on_rows_resize_after ( get_nothing_functor_on_arris_resize() )
      {
        throw_if_zero( cols_size, "cols_size == 0" );
        throw_if_zero( rows_size, "rows_size == 0" );
      }

      circular_tile( const std::size_t size, const T& default_value = T() )
        : circular_tile( size, size, default_value )
      { }

      static inline auto get_nothing_functor_on_arris_resize()
      { return []( const auto&, auto& ){ }; }

      auto cols_size() const { return this->front().size(); }
      auto rows_size() const { return rows_type::size(); }

      auto size() const { return cols_size() * rows_size(); }

      auto resize_rows( const std::size_t size, const T& default_value = T() )
      {
        on_rows_resize_before( *this, size );

        throw_if_zero( size, "the new rows size is 0; circular_tile cannot use 0 size rows." );
        rows_type::resize( size, make_cols( default_value ) );

        on_rows_resize_after( *this, size );
      }

      auto resize_cols( const std::size_t size, const T& default_value = T() )
      {
        on_cols_resize_before( *this, size );

        throw_if_zero( size, "the new cols size is 0; circular_tile cannot use 0 size cols." );
        for ( auto i = rows_type::begin(), e = rows_type::end(); i != e; ++i )
          i->resize( size, default_value );

        on_cols_resize_after( *this, size );
      }

      auto resize( const std::size_t cols_size, const std::size_t rows_size, const T& default_value = T() )
      {
        resize_rows( rows_size, default_value );
        resize_cols( cols_size, default_value );
      }

      auto resize ( const std::size_t size, const T& default_value = T() )
      { resize( size, size, default_value ); }

      auto begin() const -> decltype( rows_type::begin() ) { return rows_type::begin(); }
      auto end()   const -> decltype( rows_type::end() ){ return rows_type::end();   }

      auto get_center_index_x()
      { return cols_size() >> 1; }

      auto get_center_index_y()
      { return rows_size() >> 1; }

      auto get_center_indices()
      { return indices_2d{ get_center_index_x(), get_center_index_y() }; }

      template < typename INDEX_TYPE >
      decltype(auto) operator()( const INDEX_TYPE col, const INDEX_TYPE row )
      { return (*this)[ math::circular_modulus( row, rows_size() ) ][ math::circular_modulus( col, cols_size() ) ]; }

      template < typename INDICES_TYPE >
      decltype(auto) operator()( const INDICES_TYPE& indices )
      { return operator()( indices.x, indices.y ); }

      template < typename INDEX_TYPE >
      decltype(auto) from_center( const INDEX_TYPE delta_col, const INDEX_TYPE delta_row )
      { return operator()( get_center_index_x() + delta_col, get_center_index_y() + delta_row ); }

      template < typename INDICES_TYPE >
      decltype(auto) from_center( const INDICES_TYPE& delta_indices )
      { return operator()( get_center_index_x() + delta_indices.x, get_center_index_y() + delta_indices.y() ); }

      auto operate_cols( const operate_cols_functor_type& f )
      {
        for ( auto i = rows_type::begin(), e = rows_type::end(); i != e; ++i )
          f( *i );
      }

      auto apply( const apply_functor_type& f )
      {
        for ( auto ir = rows_type::begin(), er = rows_type::end(); ir != er; ++ir )
          for ( auto ic = ir->begin(), ec = ir->end(); ic != ec; ++ic )
            f( *ic );
      }

      auto shift_to_right( const T& default_value = T() )
      { operate_cols( [&]( auto& c ){ c.push_back( default_value ); } ); }

      auto shift_to_left( const T& default_value = T() )
      { operate_cols( [&]( auto& c ){ c.push_front( default_value ); } ); }

      auto shift_to_top( const T& default_value = T() )
      { rows_type::push_front( make_cols( default_value ) ); }

      auto shift_to_bottom( const T& default_value = T() )
      { rows_type::push_back( make_cols( default_value ) ); }

      auto throw_if_ne_rows_size( const std::size_t size )
      {
        if ( size != rows_size() )
          throw std::runtime_error( "size != rows_size()" );
      }

      auto throw_if_ne_cols_size( const std::size_t size )
      {
        if ( size != cols_size() )
          throw std::runtime_error( "size != cols_size()" );
      }

      template < typename DATA_TYPE = std::initializer_list<T> >
      auto shift_to_right( const DATA_TYPE& data )
      {
        throw_if_ne_rows_size( data.size() );

        auto i = data.begin();
        operate_cols( [&]( auto& c ){ c.push_back( *i++ ); } );
      }

      template < typename DATA_TYPE = std::initializer_list<T> >
      auto shift_to_left( const DATA_TYPE& data )
      {
        throw_if_ne_rows_size( data.size() );

        auto i = data.begin();
        operate_cols( [&]( auto& c ){ c.push_front( *i++ ); } );
      }

      template < typename DATA_TYPE = std::initializer_list<T> >
      auto shift_to_top( const DATA_TYPE& data )
      {
        throw_if_ne_cols_size( data.size() );

        rows_type::push_front( make_cols( data ) );
      }

      template < typename DATA_TYPE = std::initializer_list<T> >
      auto shift_to_bottom( const DATA_TYPE& data )
      {
        throw_if_ne_cols_size( data.size() );

        rows_type::push_back( make_cols( data ) );
      }
    };

    template < typename T >
    static decltype(auto) operator<<( std::ostream& o , const circular_tile<T>& tiles )
    {
      for ( const auto& cols : tiles )
      {
        for ( const auto& value : cols )
          o << value << " ";
        o << "\n";
      }

      return o;
    }
  }
}
<commit_msg>GCCがautoを解決できずに翻訳できない問題に対応<commit_after>#pragma once

#include "indices_2d.hxx"
#include "../math/circular_modulus.hxx"

#include <boost/circular_buffer.hpp>
#include <cstdint>
#include <functional>

namespace usagi
{
  namespace container
  {
    template
    < typename T >
    class circular_tile
      : boost::circular_buffer< boost::circular_buffer< T > >
    {
    public:
      using type = circular_tile<T>;

      using cols_type = boost::circular_buffer< T >;
      using rows_type = boost::circular_buffer< cols_type >;

      using operate_cols_functor_signature = auto ( cols_type& ) -> void;
      using operate_cols_functor_type = std::function< operate_cols_functor_signature >;

      using apply_functor_signature = auto ( T& ) -> void;
      using apply_functor_type = std::function< apply_functor_signature >;

      using on_arris_resize_functor_signature = auto ( const type& ref, std::size_t new_size ) -> void;
      using on_arris_resize_functor_type = std::function< on_arris_resize_functor_signature >;

    protected:

      inline static auto make_cols( const std::size_t size, const T& default_value = T() )
      { return cols_type( size, default_value ); }

      auto make_cols( const T& default_value = T() )
      { return make_cols( rows_type::front().size(), default_value ); }

      template < typename DATA_TYPE = std::initializer_list<T> >
      auto make_cols( const DATA_TYPE& data )
      {
        cols_type cols( rows_type::front().size() );
        for ( const auto& datum : data )
          cols.push_back( datum );
        return cols;
      }

      template < typename VALUE_TYPE, typename MESSAGE_TYPE >
      inline static auto throw_if_zero( const VALUE_TYPE value, const MESSAGE_TYPE& message )
      {
        if ( value == 0 )
          throw std::logic_error( message );
      }

    public:

      on_arris_resize_functor_type on_cols_resize_before;
      on_arris_resize_functor_type on_cols_resize_after;

      on_arris_resize_functor_type on_rows_resize_before;
      on_arris_resize_functor_type on_rows_resize_after;

      circular_tile( const std::size_t cols_size, const std::size_t rows_size, const T& default_value = T() )
        : rows_type( rows_size, make_cols( cols_size, default_value ) )
        , on_cols_resize_before( get_nothing_functor_on_arris_resize() )
        , on_cols_resize_after ( get_nothing_functor_on_arris_resize() )
        , on_rows_resize_before( get_nothing_functor_on_arris_resize() )
        , on_rows_resize_after ( get_nothing_functor_on_arris_resize() )
      {
        throw_if_zero( cols_size, "cols_size == 0" );
        throw_if_zero( rows_size, "rows_size == 0" );
      }

      circular_tile( const std::size_t size, const T& default_value = T() )
        : circular_tile( size, size, default_value )
      { }

      static inline auto get_nothing_functor_on_arris_resize()
      { return []( const type&, std::size_t ){ }; }

      auto cols_size() const { return this->front().size(); }
      auto rows_size() const { return rows_type::size(); }

      auto size() const { return cols_size() * rows_size(); }

      auto resize_rows( const std::size_t size, const T& default_value = T() )
      {
        on_rows_resize_before( *this, size );

        throw_if_zero( size, "the new rows size is 0; circular_tile cannot use 0 size rows." );
        rows_type::resize( size, make_cols( default_value ) );

        on_rows_resize_after( *this, size );
      }

      auto resize_cols( const std::size_t size, const T& default_value = T() )
      {
        on_cols_resize_before( *this, size );

        throw_if_zero( size, "the new cols size is 0; circular_tile cannot use 0 size cols." );
        for ( auto i = rows_type::begin(), e = rows_type::end(); i != e; ++i )
          i->resize( size, default_value );

        on_cols_resize_after( *this, size );
      }

      auto resize( const std::size_t cols_size, const std::size_t rows_size, const T& default_value = T() )
      {
        resize_rows( rows_size, default_value );
        resize_cols( cols_size, default_value );
      }

      auto resize ( const std::size_t size, const T& default_value = T() )
      { resize( size, size, default_value ); }

      auto begin() const -> decltype( rows_type::begin() ) { return rows_type::begin(); }
      auto end()   const -> decltype( rows_type::end() ){ return rows_type::end();   }

      auto get_center_index_x()
      { return cols_size() >> 1; }

      auto get_center_index_y()
      { return rows_size() >> 1; }

      auto get_center_indices()
      { return indices_2d{ get_center_index_x(), get_center_index_y() }; }

      template < typename INDEX_TYPE >
      decltype(auto) operator()( const INDEX_TYPE col, const INDEX_TYPE row )
      { return (*this)[ math::circular_modulus( row, rows_size() ) ][ math::circular_modulus( col, cols_size() ) ]; }

      template < typename INDICES_TYPE >
      decltype(auto) operator()( const INDICES_TYPE& indices )
      { return operator()( indices.x, indices.y ); }

      template < typename INDEX_TYPE >
      decltype(auto) from_center( const INDEX_TYPE delta_col, const INDEX_TYPE delta_row )
      { return operator()( get_center_index_x() + delta_col, get_center_index_y() + delta_row ); }

      template < typename INDICES_TYPE >
      decltype(auto) from_center( const INDICES_TYPE& delta_indices )
      { return operator()( get_center_index_x() + delta_indices.x, get_center_index_y() + delta_indices.y() ); }

      auto operate_cols( const operate_cols_functor_type& f )
      {
        for ( auto i = rows_type::begin(), e = rows_type::end(); i != e; ++i )
          f( *i );
      }

      auto apply( const apply_functor_type& f )
      {
        for ( auto ir = rows_type::begin(), er = rows_type::end(); ir != er; ++ir )
          for ( auto ic = ir->begin(), ec = ir->end(); ic != ec; ++ic )
            f( *ic );
      }

      auto shift_to_right( const T& default_value = T() )
      { operate_cols( [&]( auto& c ){ c.push_back( default_value ); } ); }

      auto shift_to_left( const T& default_value = T() )
      { operate_cols( [&]( auto& c ){ c.push_front( default_value ); } ); }

      auto shift_to_top( const T& default_value = T() )
      { rows_type::push_front( make_cols( default_value ) ); }

      auto shift_to_bottom( const T& default_value = T() )
      { rows_type::push_back( make_cols( default_value ) ); }

      auto throw_if_ne_rows_size( const std::size_t size )
      {
        if ( size != rows_size() )
          throw std::runtime_error( "size != rows_size()" );
      }

      auto throw_if_ne_cols_size( const std::size_t size )
      {
        if ( size != cols_size() )
          throw std::runtime_error( "size != cols_size()" );
      }

      template < typename DATA_TYPE = std::initializer_list<T> >
      auto shift_to_right( const DATA_TYPE& data )
      {
        throw_if_ne_rows_size( data.size() );

        auto i = data.begin();
        operate_cols( [&]( auto& c ){ c.push_back( *i++ ); } );
      }

      template < typename DATA_TYPE = std::initializer_list<T> >
      auto shift_to_left( const DATA_TYPE& data )
      {
        throw_if_ne_rows_size( data.size() );

        auto i = data.begin();
        operate_cols( [&]( auto& c ){ c.push_front( *i++ ); } );
      }

      template < typename DATA_TYPE = std::initializer_list<T> >
      auto shift_to_top( const DATA_TYPE& data )
      {
        throw_if_ne_cols_size( data.size() );

        rows_type::push_front( make_cols( data ) );
      }

      template < typename DATA_TYPE = std::initializer_list<T> >
      auto shift_to_bottom( const DATA_TYPE& data )
      {
        throw_if_ne_cols_size( data.size() );

        rows_type::push_back( make_cols( data ) );
      }
    };

    template < typename T >
    static decltype(auto) operator<<( std::ostream& o , const circular_tile<T>& tiles )
    {
      for ( const auto& cols : tiles )
      {
        for ( const auto& value : cols )
          o << value << " ";
        o << "\n";
      }

      return o;
    }
  }
}
<|endoftext|>


<commit_before>// This file is distributed under the MIT license.
// See the LICENSE file for details.

#pragma once

#ifndef VSNRAY_DETAIL_PATHTRACING_INL
#define VSNRAY_DETAIL_PATHTRACING_INL 1

#include <visionaray/get_surface.h>
#include <visionaray/result_record.h>
#include <visionaray/surface_interaction.h>
#include <visionaray/traverse.h>

namespace visionaray
{
namespace pathtracing
{

template <typename Params>
struct kernel
{

    Params params;

    template <typename Intersector, typename R, typename Generator>
    VSNRAY_FUNC result_record<typename R::scalar_type> operator()(
            Intersector& isect,
            R ray,
            Generator& gen
            ) const
    {
        using S = typename R::scalar_type;
        using I = simd::int_type_t<S>;
        using V = typename result_record<S>::vec_type;
        using C = spectrum<S>;

        simd::mask_type_t<S> active_rays = true;

        C dst(1.0);

        result_record<S> result;
        result.color = params.bg_color;

        for (unsigned bounce = 0; bounce < params.num_bounces; ++bounce)
        {
            auto hit_rec = closest_hit(ray, params.prims.begin, params.prims.end, isect);

            // Handle rays that just exited
            auto exited = active_rays & !hit_rec.hit;
            dst = mul( dst, C(from_rgba(params.ambient_color)), exited, dst );

            // Exit if no ray is active anymore
            active_rays &= hit_rec.hit;

            if (!any(active_rays))
            {
                break;
            }

            // Special handling for first bounce
            if (bounce == 0)
            {
                result.hit = hit_rec.hit;
                result.isect_pos = ray.ori + ray.dir * hit_rec.t;
            }

            // Process the current bounce

            V refl_dir;
            V view_dir = -ray.dir;

            hit_rec.isect_pos = ray.ori + ray.dir * hit_rec.t;

            auto surf = get_surface(hit_rec, params);

            S pdf(0.0);
            I inter = 0;

            auto src = surf.sample(view_dir, refl_dir, pdf, inter, gen);

            auto zero_pdf = pdf <= S(0.0);

            dst = mul( dst, src, active_rays && !zero_pdf, dst );
            dst = select( zero_pdf && active_rays, C(0.0), dst );

            active_rays &= inter != I(surface_interaction::Emission);
            active_rays &= !zero_pdf;

            if (!any(active_rays))
            {
                break;
            }

            ray.ori = hit_rec.isect_pos + refl_dir * S(params.epsilon);
            ray.dir = refl_dir;
        }

        // Terminate paths that are still active
        dst = select(active_rays, C(0.0), dst);

        result.color = select( result.hit, to_rgba(dst), result.color );

        return result;
    }

    template <typename R, typename Generator>
    VSNRAY_FUNC result_record<typename R::scalar_type> operator()(
            R ray,
            Generator& gen
            ) const
    {
        default_intersector ignore;
        return (*this)(ignore, ray, gen);
    }
};

} // pathtracing
} // visionaray

#endif // VSNRAY_DETAIL_PATHTRACING_INL
<commit_msg>Unnecessary cast<commit_after>// This file is distributed under the MIT license.
// See the LICENSE file for details.

#pragma once

#ifndef VSNRAY_DETAIL_PATHTRACING_INL
#define VSNRAY_DETAIL_PATHTRACING_INL 1

#include <visionaray/get_surface.h>
#include <visionaray/result_record.h>
#include <visionaray/surface_interaction.h>
#include <visionaray/traverse.h>

namespace visionaray
{
namespace pathtracing
{

template <typename Params>
struct kernel
{

    Params params;

    template <typename Intersector, typename R, typename Generator>
    VSNRAY_FUNC result_record<typename R::scalar_type> operator()(
            Intersector& isect,
            R ray,
            Generator& gen
            ) const
    {
        using S = typename R::scalar_type;
        using I = simd::int_type_t<S>;
        using V = typename result_record<S>::vec_type;
        using C = spectrum<S>;

        simd::mask_type_t<S> active_rays = true;

        C dst(1.0);

        result_record<S> result;
        result.color = params.bg_color;

        for (unsigned bounce = 0; bounce < params.num_bounces; ++bounce)
        {
            auto hit_rec = closest_hit(ray, params.prims.begin, params.prims.end, isect);

            // Handle rays that just exited
            auto exited = active_rays & !hit_rec.hit;
            dst = mul( dst, C(from_rgba(params.ambient_color)), exited, dst );

            // Exit if no ray is active anymore
            active_rays &= hit_rec.hit;

            if (!any(active_rays))
            {
                break;
            }

            // Special handling for first bounce
            if (bounce == 0)
            {
                result.hit = hit_rec.hit;
                result.isect_pos = ray.ori + ray.dir * hit_rec.t;
            }

            // Process the current bounce

            V refl_dir;
            V view_dir = -ray.dir;

            hit_rec.isect_pos = ray.ori + ray.dir * hit_rec.t;

            auto surf = get_surface(hit_rec, params);

            S pdf(0.0);
            I inter = 0;

            auto src = surf.sample(view_dir, refl_dir, pdf, inter, gen);

            auto zero_pdf = pdf <= S(0.0);

            dst = mul( dst, src, active_rays && !zero_pdf, dst );
            dst = select( zero_pdf && active_rays, C(0.0), dst );

            active_rays &= inter != surface_interaction::Emission;
            active_rays &= !zero_pdf;

            if (!any(active_rays))
            {
                break;
            }

            ray.ori = hit_rec.isect_pos + refl_dir * S(params.epsilon);
            ray.dir = refl_dir;
        }

        // Terminate paths that are still active
        dst = select(active_rays, C(0.0), dst);

        result.color = select( result.hit, to_rgba(dst), result.color );

        return result;
    }

    template <typename R, typename Generator>
    VSNRAY_FUNC result_record<typename R::scalar_type> operator()(
            R ray,
            Generator& gen
            ) const
    {
        default_intersector ignore;
        return (*this)(ignore, ray, gen);
    }
};

} // pathtracing
} // visionaray

#endif // VSNRAY_DETAIL_PATHTRACING_INL
<|endoftext|>