<commit_before>#include <reactive/buffer.hpp>
#include <reactive/process.hpp>
#include <reactive/variant.hpp>
#include <reactive/coroutine.hpp>
#include <reactive/generate.hpp>
#include <reactive/consume.hpp>
#include <reactive/tuple.hpp>
#include <reactive/ptr_observable.hpp>
#include <reactive/transform.hpp>
#include <reactive/bridge.hpp>
#include <reactive/take.hpp>
#include <reactive/enumerate.hpp>
#include <reactive/cache.hpp>
#include <reactive/connector.hpp>
#include <reactive/receiver.hpp>
#include <reactive/deref_optional.hpp>
#include <boost/container/string.hpp>
#include <boost/test/unit_test.hpp>
#include <boost/bind.hpp>

namespace rx
{
	template <class Element>
	struct empty : observable<Element>
	{
		virtual void async_get_one(observer<Element> &receiver) SILICIUM_OVERRIDE
		{
			return receiver.ended();
		}

		virtual void cancel() SILICIUM_OVERRIDE
		{
			throw std::logic_error("empty observable cannot be cancelled");
		}
	};
}

namespace Si
{
#if SILICIUM_RX_TUPLE_AVAILABLE
	BOOST_AUTO_TEST_CASE(reactive_take)
	{
		auto zeros = rx::generate([]{ return 0; });
		auto ones  = rx::generate([]{ return 1; });
		auto both = rx::make_tuple(zeros, ones);
		std::vector<std::tuple<int, int>> const expected(4, std::make_tuple(0, 1));
		std::vector<std::tuple<int, int>> const generated = rx::take(both, expected.size());
		BOOST_CHECK(expected == generated);
	}
#endif

#if SILICIUM_RX_TUPLE_AVAILABLE
	BOOST_AUTO_TEST_CASE(reactive_transform)
	{
		auto twos = rx::generate([]{ return 2; });
		auto ones  = rx::generate([]{ return 1; });
		auto both = rx::make_tuple(twos, ones);
		auto added = rx::transform(both, [](std::tuple<int, int> const &element)
		{
			return std::get<0>(element) + std::get<1>(element);
		});
		std::vector<int> const expected(4, 3);
		std::vector<int> const generated = rx::take(added, expected.size());
		BOOST_CHECK(expected == generated);
	}
#endif

#if SILICIUM_RX_TUPLE_AVAILABLE
	BOOST_AUTO_TEST_CASE(reactive_bridge)
	{
		auto bridge = std::make_shared<rx::bridge<int>>();
		rx::ptr_observable<int, std::shared_ptr<rx::observable<int>>> first(bridge);
		auto ones  = rx::generate([]{ return 1; });
		auto both = rx::make_tuple(first, ones);
		auto added = rx::transform(both, [](std::tuple<int, int> const &element)
		{
			return std::get<0>(element) + std::get<1>(element);
		});
		std::vector<int> generated;
		auto consumer = rx::consume<int>([&generated](int element)
		{
			generated.emplace_back(element);
		});
		BOOST_CHECK(generated.empty());

		added.async_get_one(consumer);
		BOOST_CHECK(generated.empty());

		bridge->got_element(2);
		std::vector<int> const expected(1, 3);
		BOOST_CHECK(expected == generated);
	}
#endif

	BOOST_AUTO_TEST_CASE(reactive_make_buffer)
	{
		auto bridge = std::make_shared<rx::bridge<int>>();
		rx::ptr_observable<int, std::shared_ptr<rx::observable<int>>> first{bridge};
		auto buf = rx::make_buffer(first, 2);

		std::vector<int> generated;
		auto consumer = rx::consume<int>([&generated](int element)
		{
			generated.emplace_back(element);
		});
		BOOST_CHECK(generated.empty());

		for (size_t i = 0; i < 2; ++i)
		{
			BOOST_REQUIRE(bridge->is_waiting());
			bridge->got_element(7);
		}
		BOOST_CHECK(!bridge->is_waiting());
		BOOST_CHECK(generated.empty());

		buf.async_get_one(consumer);
		std::vector<int> expected(1, 7);
		BOOST_CHECK(expected == generated);

		buf.async_get_one(consumer);
		expected.emplace_back(7);
		BOOST_CHECK(expected == generated);

		buf.async_get_one(consumer);
		BOOST_CHECK(expected == generated);
	}

	BOOST_AUTO_TEST_CASE(reactive_coroutine_generate)
	{
		auto co = rx::make_coroutine<int>([](rx::yield_context<int> &yield) -> void
		{
			yield(1);
			yield(2);
		});
		std::vector<int> generated;
		auto collector = rx::consume<int>([&generated](int element)
		{
			generated.emplace_back(element);
		});
		for (;;)
		{
			auto old_size = generated.size();
			co.async_get_one(collector);
			if (generated.size() == old_size)
			{
				break;
			}
			BOOST_REQUIRE(generated.size() == old_size + 1);
		}
		std::vector<int> const expected{1, 2};
		BOOST_CHECK(expected == generated);
	}

	BOOST_AUTO_TEST_CASE(reactive_coroutine_get_one)
	{
		rx::bridge<int> asyncs;
		bool exited_cleanly = false;
		auto co = rx::make_coroutine<int>([&asyncs, &exited_cleanly](rx::yield_context<int> &yield) -> void
		{
			auto a = yield.get_one(asyncs);
			BOOST_REQUIRE(a);
			yield(*a - 1);
			exited_cleanly = true;
		});
		std::vector<int> generated;
		auto collector = rx::consume<int>([&generated](int element)
		{
			generated.emplace_back(element);
		});
		co.async_get_one(collector);
		BOOST_REQUIRE(generated.empty());
		asyncs.got_element(4);

		//TODO: reading past the end should not be the required way to avoid a force unwind of the coroutine
		//      because the unwinding is done by throwing an exception.
		co.async_get_one(collector);
		BOOST_CHECK(exited_cleanly);

		std::vector<int> const expected{3};
		BOOST_CHECK(expected == generated);
	}

#if SILICIUM_RX_VARIANT_AVAILABLE
	BOOST_AUTO_TEST_CASE(reactive_make_variant)
	{
		rx::bridge<int> first;
		rx::bridge<boost::container::string> second;
		auto variants = make_variant(rx::ref(first), rx::ref(second));

		typedef Si::fast_variant<int, boost::container::string> variant;
		std::vector<variant> produced;
		auto consumer = rx::consume<variant>([&produced](variant element)
		{
			produced.emplace_back(std::move(element));
		});

		variants.async_get_one(consumer);
		BOOST_CHECK(produced.empty());
		first.got_element(4);

		variants.async_get_one(consumer);
		BOOST_CHECK_EQUAL(1,produced.size());
		second.got_element("Hi");

		std::vector<variant> const expected
		{
			4,
			boost::container::string("Hi")
		};

		BOOST_CHECK(expected == produced);
		BOOST_CHECK(!rx::get_immediate(variants));
	}
#endif

	template <class Element, class Action>
	struct blocking_then_state : rx::observer<Element>
	{
		boost::asio::io_service &dispatcher;
		boost::optional<boost::asio::io_service::work> blocker;
		Action action;
		rx::observable<Element> *from = nullptr;

		explicit blocking_then_state(boost::asio::io_service &dispatcher, Action action)
			: dispatcher(dispatcher)
			, blocker(boost::in_place(boost::ref(dispatcher)))
			, action(std::move(action))
		{
		}

		~blocking_then_state()
		{
			if (!from)
			{
				return;
			}
			from->cancel();
		}

		virtual void got_element(Element value) SILICIUM_OVERRIDE
		{
			dispatcher.post(boost::bind<void>(action, boost::make_optional(std::move(value))));
			blocker.reset();
		}

		virtual void ended() SILICIUM_OVERRIDE
		{
			dispatcher.post(boost::bind<void>(action, boost::optional<Element>()));
			blocker.reset();
		}
	};

	template <class Element, class Action>
	auto blocking_then(boost::asio::io_service &io, rx::observable<Element> &from, Action &&action) -> std::shared_ptr<blocking_then_state<Element, typename std::decay<Action>::type>>
	{
		auto state = std::make_shared<blocking_then_state<Element, typename std::decay<Action>::type>>(io, std::forward<Action>(action));
		from.async_get_one(*state);
		state->from = &from;
		return state;
	}

	BOOST_AUTO_TEST_CASE(reactive_process)
	{
		rx::empty<char> input;
		rx::process proc = rx::launch_process("/usr/bin/which", {"which"}, input);

		boost::asio::io_service io;
		auto blocking = blocking_then(io, proc.exit_code, [](boost::optional<int> ec)
		{
			BOOST_CHECK_EQUAL(0, ec);
		});
		io.run();
	}
}
<commit_msg>design a replacement for boost::signal<commit_after>#include <reactive/buffer.hpp>
#include <reactive/process.hpp>
#include <reactive/variant.hpp>
#include <reactive/coroutine.hpp>
#include <reactive/generate.hpp>
#include <reactive/consume.hpp>
#include <reactive/tuple.hpp>
#include <reactive/ptr_observable.hpp>
#include <reactive/transform.hpp>
#include <reactive/bridge.hpp>
#include <reactive/take.hpp>
#include <reactive/enumerate.hpp>
#include <reactive/cache.hpp>
#include <reactive/connector.hpp>
#include <reactive/receiver.hpp>
#include <reactive/deref_optional.hpp>
#include <boost/container/string.hpp>
#include <boost/test/unit_test.hpp>
#include <boost/bind.hpp>
#include <boost/container/flat_map.hpp>

namespace rx
{
	template <class Element>
	struct empty : observable<Element>
	{
		virtual void async_get_one(observer<Element> &receiver) SILICIUM_OVERRIDE
		{
			return receiver.ended();
		}

		virtual void cancel() SILICIUM_OVERRIDE
		{
			throw std::logic_error("empty observable cannot be cancelled");
		}
	};
}

namespace Si
{
#if SILICIUM_RX_TUPLE_AVAILABLE
	BOOST_AUTO_TEST_CASE(reactive_take)
	{
		auto zeros = rx::generate([]{ return 0; });
		auto ones  = rx::generate([]{ return 1; });
		auto both = rx::make_tuple(zeros, ones);
		std::vector<std::tuple<int, int>> const expected(4, std::make_tuple(0, 1));
		std::vector<std::tuple<int, int>> const generated = rx::take(both, expected.size());
		BOOST_CHECK(expected == generated);
	}
#endif

#if SILICIUM_RX_TUPLE_AVAILABLE
	BOOST_AUTO_TEST_CASE(reactive_transform)
	{
		auto twos = rx::generate([]{ return 2; });
		auto ones  = rx::generate([]{ return 1; });
		auto both = rx::make_tuple(twos, ones);
		auto added = rx::transform(both, [](std::tuple<int, int> const &element)
		{
			return std::get<0>(element) + std::get<1>(element);
		});
		std::vector<int> const expected(4, 3);
		std::vector<int> const generated = rx::take(added, expected.size());
		BOOST_CHECK(expected == generated);
	}
#endif

#if SILICIUM_RX_TUPLE_AVAILABLE
	BOOST_AUTO_TEST_CASE(reactive_bridge)
	{
		auto bridge = std::make_shared<rx::bridge<int>>();
		rx::ptr_observable<int, std::shared_ptr<rx::observable<int>>> first(bridge);
		auto ones  = rx::generate([]{ return 1; });
		auto both = rx::make_tuple(first, ones);
		auto added = rx::transform(both, [](std::tuple<int, int> const &element)
		{
			return std::get<0>(element) + std::get<1>(element);
		});
		std::vector<int> generated;
		auto consumer = rx::consume<int>([&generated](int element)
		{
			generated.emplace_back(element);
		});
		BOOST_CHECK(generated.empty());

		added.async_get_one(consumer);
		BOOST_CHECK(generated.empty());

		bridge->got_element(2);
		std::vector<int> const expected(1, 3);
		BOOST_CHECK(expected == generated);
	}
#endif

	BOOST_AUTO_TEST_CASE(reactive_make_buffer)
	{
		auto bridge = std::make_shared<rx::bridge<int>>();
		rx::ptr_observable<int, std::shared_ptr<rx::observable<int>>> first{bridge};
		auto buf = rx::make_buffer(first, 2);

		std::vector<int> generated;
		auto consumer = rx::consume<int>([&generated](int element)
		{
			generated.emplace_back(element);
		});
		BOOST_CHECK(generated.empty());

		for (size_t i = 0; i < 2; ++i)
		{
			BOOST_REQUIRE(bridge->is_waiting());
			bridge->got_element(7);
		}
		BOOST_CHECK(!bridge->is_waiting());
		BOOST_CHECK(generated.empty());

		buf.async_get_one(consumer);
		std::vector<int> expected(1, 7);
		BOOST_CHECK(expected == generated);

		buf.async_get_one(consumer);
		expected.emplace_back(7);
		BOOST_CHECK(expected == generated);

		buf.async_get_one(consumer);
		BOOST_CHECK(expected == generated);
	}

	BOOST_AUTO_TEST_CASE(reactive_coroutine_generate)
	{
		auto co = rx::make_coroutine<int>([](rx::yield_context<int> &yield) -> void
		{
			yield(1);
			yield(2);
		});
		std::vector<int> generated;
		auto collector = rx::consume<int>([&generated](int element)
		{
			generated.emplace_back(element);
		});
		for (;;)
		{
			auto old_size = generated.size();
			co.async_get_one(collector);
			if (generated.size() == old_size)
			{
				break;
			}
			BOOST_REQUIRE(generated.size() == old_size + 1);
		}
		std::vector<int> const expected{1, 2};
		BOOST_CHECK(expected == generated);
	}

	BOOST_AUTO_TEST_CASE(reactive_coroutine_get_one)
	{
		rx::bridge<int> asyncs;
		bool exited_cleanly = false;
		auto co = rx::make_coroutine<int>([&asyncs, &exited_cleanly](rx::yield_context<int> &yield) -> void
		{
			auto a = yield.get_one(asyncs);
			BOOST_REQUIRE(a);
			yield(*a - 1);
			exited_cleanly = true;
		});
		std::vector<int> generated;
		auto collector = rx::consume<int>([&generated](int element)
		{
			generated.emplace_back(element);
		});
		co.async_get_one(collector);
		BOOST_REQUIRE(generated.empty());
		asyncs.got_element(4);

		//TODO: reading past the end should not be the required way to avoid a force unwind of the coroutine
		//      because the unwinding is done by throwing an exception.
		co.async_get_one(collector);
		BOOST_CHECK(exited_cleanly);

		std::vector<int> const expected{3};
		BOOST_CHECK(expected == generated);
	}

#if SILICIUM_RX_VARIANT_AVAILABLE
	BOOST_AUTO_TEST_CASE(reactive_make_variant)
	{
		rx::bridge<int> first;
		rx::bridge<boost::container::string> second;
		auto variants = make_variant(rx::ref(first), rx::ref(second));

		typedef Si::fast_variant<int, boost::container::string> variant;
		std::vector<variant> produced;
		auto consumer = rx::consume<variant>([&produced](variant element)
		{
			produced.emplace_back(std::move(element));
		});

		variants.async_get_one(consumer);
		BOOST_CHECK(produced.empty());
		first.got_element(4);

		variants.async_get_one(consumer);
		BOOST_CHECK_EQUAL(1,produced.size());
		second.got_element("Hi");

		std::vector<variant> const expected
		{
			4,
			boost::container::string("Hi")
		};

		BOOST_CHECK(expected == produced);
		BOOST_CHECK(!rx::get_immediate(variants));
	}
#endif

	template <class Element, class Action>
	struct blocking_then_state : rx::observer<Element>
	{
		boost::asio::io_service &dispatcher;
		boost::optional<boost::asio::io_service::work> blocker;
		Action action;
		rx::observable<Element> *from = nullptr;

		explicit blocking_then_state(boost::asio::io_service &dispatcher, Action action)
			: dispatcher(dispatcher)
			, blocker(boost::in_place(boost::ref(dispatcher)))
			, action(std::move(action))
		{
		}

		~blocking_then_state()
		{
			if (!from)
			{
				return;
			}
			from->cancel();
		}

		virtual void got_element(Element value) SILICIUM_OVERRIDE
		{
			dispatcher.post(boost::bind<void>(action, boost::make_optional(std::move(value))));
			blocker.reset();
		}

		virtual void ended() SILICIUM_OVERRIDE
		{
			dispatcher.post(boost::bind<void>(action, boost::optional<Element>()));
			blocker.reset();
		}
	};

	template <class Element, class Action>
	auto blocking_then(boost::asio::io_service &io, rx::observable<Element> &from, Action &&action) -> std::shared_ptr<blocking_then_state<Element, typename std::decay<Action>::type>>
	{
		auto state = std::make_shared<blocking_then_state<Element, typename std::decay<Action>::type>>(io, std::forward<Action>(action));
		from.async_get_one(*state);
		state->from = &from;
		return state;
	}

	BOOST_AUTO_TEST_CASE(reactive_process)
	{
		rx::empty<char> input;
		rx::process proc = rx::launch_process("/usr/bin/which", {"which"}, input);

		boost::asio::io_service io;
		auto blocking = blocking_then(io, proc.exit_code, [](boost::optional<int> ec)
		{
			BOOST_CHECK_EQUAL(0, ec);
		});
		io.run();
	}
}

namespace rx
{
	template <class Element>
	using signal_observer_map = boost::container::flat_map<observer<Element> *, bool>;

	template <class Element>
	struct connection : observable<Element>
	{
		typedef Element element_type;

		connection()
		{
		}

		explicit connection(signal_observer_map<Element> &connections)
			: connections(&connections)
		{
		}

		connection(connection &&other)
			: connections(other.connections)
			, receiver_(other.receiver_)
		{
			other.connections = nullptr;
			other.receiver_ = nullptr;
		}

		connection &operator = (connection &&other)
		{
			boost::swap(connections, other.connections);
			boost::swap(receiver_, other.receiver_);
			return *this;
		}

		~connection()
		{
			if (!connections)
			{
				return;
			}
			connections->erase(receiver_);
		}

		virtual void async_get_one(observer<element_type> &receiver) SILICIUM_OVERRIDE
		{
			auto * const old_receiver = receiver_;
			connections->insert(std::make_pair(&receiver, true)).first->second = true;
			if (old_receiver && (old_receiver != &receiver))
			{
				auto i = connections->find(receiver_);
				assert(i->second);
				connections->erase(i);
			}
			receiver_ = &receiver;
		}

		virtual void cancel() SILICIUM_OVERRIDE
		{
			assert(receiver_);
			size_t erased = connections->erase(exchange(receiver_, nullptr));
			assert(erased == 1);
		}

	private:

		signal_observer_map<Element> *connections = nullptr;
		observer<Element> *receiver_ = nullptr;

		BOOST_DELETED_FUNCTION(connection(connection const &))
		BOOST_DELETED_FUNCTION(connection &operator = (connection const &))
	};

	template <class Element>
	struct signal
	{
		typedef connection<Element> connection_type;

		connection_type connect()
		{
			return connection_type(observers);
		}

		void emit_one(Element const &value)
		{
			for (auto &observer : observers)
			{
				if (observer.second)
				{
					observer.second = false;
					observer.first->got_element(value);
				}
			}
		}

	private:

		signal_observer_map<Element> observers;
	};
}

namespace
{
	BOOST_AUTO_TEST_CASE(reactive_signal)
	{
		rx::signal<int> s;
		auto con1 = s.connect();
		auto con2 = s.connect();
		std::vector<int> generated;
		auto consumer = rx::consume<int>([&generated](boost::optional<int> value)
		{
			BOOST_REQUIRE(value);
			generated.emplace_back(*value);
		});
		con1.async_get_one(consumer);
		s.emit_one(2);
		con2 = std::move(con1);
		con2.async_get_one(consumer);
		s.emit_one(3);
		s.emit_one(4);
		std::vector<int> const expected{2, 3};
		BOOST_CHECK(expected == generated);
	}
}
<|endoftext|>


<commit_before>#include <MdisPlugin.h>
#include <MdisNacSensorModel.h>
#include <IsdReader.h>

#include <csm/Isd.h>

#include <gtest/gtest.h>

/**
 * Sub-class MdisNacSensorModel to get test its protected linear algebra methods.
 *
 * We should be testing the protected methods of MdisNacSensorModel since imageToGround
 * depends on intersect, which depends on project, etc.
 */
class TestableMdisNacSensorModel : public MdisNacSensorModel {
  // Give linear algebra methods public accessing when using instances of this class.
  public:
    using MdisNacSensorModel::computeElevation;
    using MdisNacSensorModel::intersect;
    using MdisNacSensorModel::perpendicular;
    using MdisNacSensorModel::project;
    using MdisNacSensorModel::dot;
    using MdisNacSensorModel::magnitude;
    using MdisNacSensorModel::normalize;
};

// Set up a fixture (i.e. objects we can use throughout test)
class MdisNacSensorModelTest : public ::testing::Test {
  protected:
    // Per test-case setup and teardown (e.g. once for this MdisNacSensorModelTest)
    static void SetUpTestCase() {
      dataFile = "./data/EN1007907102M.json";
      isd = readISD(dataFile);
      // printISD(*isd);
    }

    static void TearDownTestCase() {
      delete isd;
      isd = NULL;
    }

    // Per test setup and teardown (e.g. each TEST_F)
    virtual void SetUp() {
      tolerance = 0.00001;
    }

    virtual void TearDown() {}

    static csm::Isd *isd;                // ISD converted from JSON to use for creating model.
    static std::string dataFile;         // JSON data file to be converted to ISD for testing.

    double tolerance;                    // Tolerance to be used for double comparison.
    MdisPlugin mdisPlugin;               // Plugin used to create a model from ISD.
    MdisNacSensorModel defaultMdisNac;   // A default constructed MdisNacSensorModel.
    TestableMdisNacSensorModel testMath; // Subclassed MdisNacSensorModel for protected methods.
};

csm::Isd *MdisNacSensorModelTest::isd = NULL;
std::string MdisNacSensorModelTest::dataFile;

/*
 * Test imageToGround - truth extracted as follows:
 * setisis isis3
 * qview /work/projects/IAA_camera/data/EN100790102M.cub
 * F (selects "Find Tool")
 * On top toolbar, select "Find Point"
 * Type in 512.5, 512.5 for Sample/Line (ISIS3 pixel center = 1,1)
 * Click "Record Point"
 * Check "XYZ" -> { 1132.18, -1597.75, 1455.66 }
 */
TEST_F(MdisNacSensorModelTest, imageToGround1) {
  // CSM Line/Sample center = 512, 512
  csm::ImageCoord point(512.0, 512.0);
  double height = 0.0;

  // Create a model from the ISD so we can test a valid image.
  // Make sure the isd was read correctly.
  if (!isd) {
    FAIL() << "Could not create isd from file: " << dataFile;
  }
  std::string modelName = MdisNacSensorModel::_SENSOR_MODEL_NAME;
  csm::Model *validModel = mdisPlugin.constructModelFromISD(*isd, modelName);
  // We could static_cast, but may be hard to debug if it doesn't correctly cast.
  MdisNacSensorModel *mdisModel = dynamic_cast<MdisNacSensorModel *>(validModel);

  // Fatal failure if the downcast doesn't work
  if (!mdisModel) {
    FAIL() << "Could not downcast Model* to MdisNacSensorModel*.";
  }

  csm::EcefCoord xyz = mdisModel->imageToGround(point, height);
  double truth[] = { 1132.18*1000, -1597.75*1000, 1455.66*1000 };
  EXPECT_EQ(truth[0], xyz.x);
  EXPECT_EQ(truth[1], xyz.y);
  EXPECT_EQ(truth[2], xyz.z);

  // Remove the memory we took ownership of.
  delete mdisModel;
}

// Tests the getModelState() method with a default constructed MdisNacSensorModel.
TEST_F(MdisNacSensorModelTest, getModelStateDefault) {
  EXPECT_EQ(defaultMdisNac.getModelState(), std::string());
}

// Test getElevation
TEST_F(MdisNacSensorModelTest, computeElevationOnSphere) {
  // (1/4)^2 + (1/2)^2 + z^2 = 1^2; z^2 = 11/16
  double elevation = testMath.computeElevation(0.25, 0.5, sqrt(11)/4.0);
  EXPECT_EQ(0.0, elevation);
}

// Test intersect
TEST_F(MdisNacSensorModelTest, intersectTrivial) {
  std::vector<double> position { 0.0, 0.0, 1.5 };
  std::vector<double> look { 0.0, 0.0, -0.5 };
  csm::EcefCoord intersectGround = testMath.intersect(position, look, 1.0);
  EXPECT_EQ(0.0, intersectGround.x);
  EXPECT_EQ(0.0, intersectGround.y);
  EXPECT_EQ(1.0, intersectGround.z);
}

TEST_F(MdisNacSensorModelTest, intersectLookingAway) {
  std::vector<double> position { 0.0, 0.0, 2.0 };
  std::vector<double> look { 0.0, 0.0, 0.5 };
  csm::EcefCoord ground = testMath.intersect(position, look, 1.0);
  EXPECT_EQ(0.0, ground.x);
  EXPECT_EQ(0.0, ground.y);
  EXPECT_EQ(0.0, ground.z);
}

// Test perpendicular
TEST_F(MdisNacSensorModelTest, perpendicularNonZeros) {
  std::vector<double> v1(3), v2(3);
  v1[0] = 0.0;
  v1[1] = 0.0;
  v1[2] = 1.5;
  v2[0] = 0.0;
  v2[1] = -0.25;
  v2[2] = -0.5;
  std::vector<double> result = testMath.perpendicular(v1, v2);
  EXPECT_NEAR(0.0, result[0], tolerance);
  EXPECT_NEAR(-0.6, result[1], tolerance);
  EXPECT_NEAR(0.3, result[2], tolerance);
}

// Test project
TEST_F(MdisNacSensorModelTest, projectNonZeros) {
  std::vector<double> v1(3), v2(3);
  v1[0] = 0.0;
  v1[1] = 0.0;
  v1[2] = 1.5;
  v2[0] = 0.0;
  v2[1] = -0.25;
  v2[2] = -0.5;
  std::vector<double> result = testMath.project(v1, v2);
  EXPECT_NEAR(0.0, result[0], tolerance);
  EXPECT_NEAR(0.6, result[1], tolerance);
  EXPECT_NEAR(1.2, result[2], tolerance);
}

// Test dot
// TODO: use value-parameterized tests
TEST_F(MdisNacSensorModelTest, dotZeroVectors) {
  std::vector<double> v1(3, 0.0), v2(3, 0.0);
  EXPECT_EQ(0.0, testMath.dot(v1, v2));
}

TEST_F(MdisNacSensorModelTest, dotOneZeroVector) {
  std::vector<double> v1(3, 0.0), v2(3);
  v2[0] = 1.0;
  v2[1] = 2.0;
  v2[2] = 3.0;
  EXPECT_EQ(0.0, testMath.dot(v1, v2));
}

TEST_F(MdisNacSensorModelTest, dotVectors) {
  std::vector<double> v1(3), v2(3);
  v1[0] = 1.0;
  v1[1] = 2.0;
  v1[2] = 3.0;
  v2[0] = -2.0;
  v2[1] = 2.0;
  v2[2] = 3.0;
  EXPECT_EQ(11.0, testMath.dot(v1, v2));
}

// Test magnitude
TEST_F(MdisNacSensorModelTest, magnitudeZero) {
  std::vector<double> v(3, 0.0);
  EXPECT_EQ(0.0, testMath.magnitude(v));
}

TEST_F(MdisNacSensorModelTest, magnitudePositive) {
  std::vector<double>v(3);
  v[0] = 3.0;
  v[1] = 4.0;
  v[2] = 5.0;
  EXPECT_EQ(sqrt(50.0), testMath.magnitude(v));
}

TEST_F(MdisNacSensorModelTest, magnitudeNegative) {
  std::vector<double>v(3);
  v[0] = -3.0;
  v[1] = -4.0;
  v[2] = -5.0;
  EXPECT_EQ(sqrt(50.0), testMath.magnitude(v));
}

// Test normalize
TEST_F(MdisNacSensorModelTest, normalizeVector) {
  std::vector<double>v(3);
  v[0] = 2.0;
  v[1] = 3.0;
  v[2] = 4.0;
  std::vector<double> result = testMath.normalize(v);
  EXPECT_EQ((v[0] / sqrt(29.0)), result[0]);
  EXPECT_EQ((v[1] / sqrt(29.0)), result[1]);
  EXPECT_EQ((v[2] / sqrt(29.0)), result[2]);
}
<commit_msg>Added preliminary groundToImage test. Refactor MdisNacSensorModelTest to avoid code duplication between imageToGround and groundToImage test.<commit_after>#include <MdisPlugin.h>
#include <MdisNacSensorModel.h>
#include <IsdReader.h>

#include <csm/Isd.h>

#include <gtest/gtest.h>

/**
 * Sub-class MdisNacSensorModel to get test its protected linear algebra methods.
 *
 * We should be testing the protected methods of MdisNacSensorModel since imageToGround
 * depends on intersect, which depends on project, etc.
 */
class TestableMdisNacSensorModel : public MdisNacSensorModel {
  // Give linear algebra methods public accessing when using instances of this class.
  public:
    using MdisNacSensorModel::computeElevation;
    using MdisNacSensorModel::intersect;
    using MdisNacSensorModel::perpendicular;
    using MdisNacSensorModel::project;
    using MdisNacSensorModel::dot;
    using MdisNacSensorModel::magnitude;
    using MdisNacSensorModel::normalize;
};

// Set up a fixture (i.e. objects we can use throughout test)
class MdisNacSensorModelTest : public ::testing::Test {
  protected:

    // Per test-case setup and teardown (e.g. once for this MdisNacSensorModelTest)
    static void SetUpTestCase() {
      dataFile = "./data/EN1007907102M.json";
      isd = readISD(dataFile);
      // printISD(*isd);

      // Make sure the isd was read correctly.
      if (isd == nullptr) {
        FAIL() << "Could not create isd from file: " << dataFile;
      }

      // Create a model from the ISD so we can test a valid image.
      std::string modelName = MdisNacSensorModel::_SENSOR_MODEL_NAME;
      csm::Model *validModel = mdisPlugin.constructModelFromISD(*isd, modelName);

      // We could static_cast, but may be hard to debug if it doesn't correctly cast.
      mdisModel = dynamic_cast<MdisNacSensorModel *>(validModel);
      std::cout << "Construction model: " << mdisModel << "\n";

      // Fatal failure if the downcast doesn't work
      if (mdisModel == nullptr) {
        FAIL() << "Could not downcast Model* to MdisNacSensorModel*.";
      }
    }

    static void TearDownTestCase() {
      delete isd;
      delete mdisModel;
    }

    static csm::Isd *isd;                 // ISD converted from JSON to use for creating model.
    static std::string dataFile;          // JSON data file to be converted to ISD for testing.
    static MdisPlugin mdisPlugin;         // Plugin used to create a model from ISD.
    static MdisNacSensorModel *mdisModel; // MDIS-NAC sensor model created with ISD.

    // Per test setup and teardown (e.g. each TEST_F)
    virtual void SetUp() {
      tolerance = 0.00001;
    }

    virtual void TearDown() {}

    double tolerance;                     // Tolerance to be used for double comparison.
    MdisNacSensorModel defaultMdisNac;    // A default constructed MdisNacSensorModel.
    TestableMdisNacSensorModel testMath;  // Subclassed MdisNacSensorModel for protected methods.
};

csm::Isd *MdisNacSensorModelTest::isd = nullptr;
std::string MdisNacSensorModelTest::dataFile;
MdisPlugin MdisNacSensorModelTest::mdisPlugin;
MdisNacSensorModel *MdisNacSensorModelTest::mdisModel = nullptr;

/*
 * Test imageToGround - truth extracted as follows:
 * setisis isis3
 * qview /work/projects/IAA_camera/data/EN100790102M.cub
 * F (selects "Find Tool")
 * On top toolbar, select "Find Point"
 * Type in 512.5, 512.5 for Sample/Line (ISIS3 pixel center = 1,1)
 * Click "Record Point"
 * Check "XYZ" -> { 1132.18, -1597.75, 1455.66 }
 */
TEST_F(MdisNacSensorModelTest, imageToGround1) {
  // CSM Line/Sample center = 512, 512
  csm::ImageCoord point(512.0, 512.0);
  double height = 0.0;
  csm::EcefCoord xyz = mdisModel->imageToGround(point, height);
  double truth[] = { 1132.18*1000, -1597.75*1000, 1455.66*1000 };
  EXPECT_EQ(truth[0], xyz.x);
  EXPECT_EQ(truth[1], xyz.y);
  EXPECT_EQ(truth[2], xyz.z);
}

// Test groundToImage
TEST_F(MdisNacSensorModelTest, groundToImage1) {
  double x = 1132.18*1000;
  double y = -1597.75*1000;
  double z = 1455.66*1000;
  csm::EcefCoord xyz(x, y, z);
  csm::ImageCoord pt = mdisModel->groundToImage(xyz);
  EXPECT_EQ(512.0, pt.line);
  EXPECT_EQ(512.0, pt.samp);
}

// Tests the getModelState() method with a default constructed MdisNacSensorModel.
TEST_F(MdisNacSensorModelTest, getModelStateDefault) {
  EXPECT_EQ(defaultMdisNac.getModelState(), std::string());
}

// Test getElevation
TEST_F(MdisNacSensorModelTest, computeElevationOnSphere) {
  // (1/4)^2 + (1/2)^2 + z^2 = 1^2; z^2 = 11/16
  double elevation = testMath.computeElevation(0.25, 0.5, sqrt(11)/4.0);
  EXPECT_EQ(0.0, elevation);
}

// Test intersect
TEST_F(MdisNacSensorModelTest, intersectTrivial) {
  std::vector<double> position { 0.0, 0.0, 1.5 };
  std::vector<double> look { 0.0, 0.0, -0.5 };
  csm::EcefCoord intersectGround = testMath.intersect(position, look, 1.0);
  EXPECT_EQ(0.0, intersectGround.x);
  EXPECT_EQ(0.0, intersectGround.y);
  EXPECT_EQ(1.0, intersectGround.z);
}

TEST_F(MdisNacSensorModelTest, intersectLookingAway) {
  std::vector<double> position { 0.0, 0.0, 2.0 };
  std::vector<double> look { 0.0, 0.0, 0.5 };
  csm::EcefCoord ground = testMath.intersect(position, look, 1.0);
  EXPECT_EQ(0.0, ground.x);
  EXPECT_EQ(0.0, ground.y);
  EXPECT_EQ(0.0, ground.z);
}

// Test perpendicular
TEST_F(MdisNacSensorModelTest, perpendicularNonZeros) {
  std::vector<double> v1(3), v2(3);
  v1[0] = 0.0;
  v1[1] = 0.0;
  v1[2] = 1.5;
  v2[0] = 0.0;
  v2[1] = -0.25;
  v2[2] = -0.5;
  std::vector<double> result = testMath.perpendicular(v1, v2);
  EXPECT_NEAR(0.0, result[0], tolerance);
  EXPECT_NEAR(-0.6, result[1], tolerance);
  EXPECT_NEAR(0.3, result[2], tolerance);
}

// Test project
TEST_F(MdisNacSensorModelTest, projectNonZeros) {
  std::vector<double> v1(3), v2(3);
  v1[0] = 0.0;
  v1[1] = 0.0;
  v1[2] = 1.5;
  v2[0] = 0.0;
  v2[1] = -0.25;
  v2[2] = -0.5;
  std::vector<double> result = testMath.project(v1, v2);
  EXPECT_NEAR(0.0, result[0], tolerance);
  EXPECT_NEAR(0.6, result[1], tolerance);
  EXPECT_NEAR(1.2, result[2], tolerance);
}

// Test dot
// TODO: use value-parameterized tests
TEST_F(MdisNacSensorModelTest, dotZeroVectors) {
  std::vector<double> v1(3, 0.0), v2(3, 0.0);
  EXPECT_EQ(0.0, testMath.dot(v1, v2));
}

TEST_F(MdisNacSensorModelTest, dotOneZeroVector) {
  std::vector<double> v1(3, 0.0), v2(3);
  v2[0] = 1.0;
  v2[1] = 2.0;
  v2[2] = 3.0;
  EXPECT_EQ(0.0, testMath.dot(v1, v2));
}

TEST_F(MdisNacSensorModelTest, dotVectors) {
  std::vector<double> v1(3), v2(3);
  v1[0] = 1.0;
  v1[1] = 2.0;
  v1[2] = 3.0;
  v2[0] = -2.0;
  v2[1] = 2.0;
  v2[2] = 3.0;
  EXPECT_EQ(11.0, testMath.dot(v1, v2));
}

// Test magnitude
TEST_F(MdisNacSensorModelTest, magnitudeZero) {
  std::vector<double> v(3, 0.0);
  EXPECT_EQ(0.0, testMath.magnitude(v));
}

TEST_F(MdisNacSensorModelTest, magnitudePositive) {
  std::vector<double>v(3);
  v[0] = 3.0;
  v[1] = 4.0;
  v[2] = 5.0;
  EXPECT_EQ(sqrt(50.0), testMath.magnitude(v));
}

TEST_F(MdisNacSensorModelTest, magnitudeNegative) {
  std::vector<double>v(3);
  v[0] = -3.0;
  v[1] = -4.0;
  v[2] = -5.0;
  EXPECT_EQ(sqrt(50.0), testMath.magnitude(v));
}

// Test normalize
TEST_F(MdisNacSensorModelTest, normalizeVector) {
  std::vector<double>v(3);
  v[0] = 2.0;
  v[1] = 3.0;
  v[2] = 4.0;
  std::vector<double> result = testMath.normalize(v);
  EXPECT_EQ((v[0] / sqrt(29.0)), result[0]);
  EXPECT_EQ((v[1] / sqrt(29.0)), result[1]);
  EXPECT_EQ((v[2] / sqrt(29.0)), result[2]);
}
<|endoftext|>


<commit_before><commit_msg>INTEGRATION: CWS geordi2q14 (1.27.164); FILE MERGED 2004/01/30 11:16:42 hr 1.27.164.1: #111934#: merge CWS ooo111fix2<commit_after><|endoftext|>


<commit_before>/*
 * Copyright (c) 2007 The Hewlett-Packard Development Company
 * All rights reserved.
 *
 * Redistribution and use of this software in source and binary forms,
 * with or without modification, are permitted provided that the
 * following conditions are met:
 *
 * The software must be used only for Non-Commercial Use which means any
 * use which is NOT directed to receiving any direct monetary
 * compensation for, or commercial advantage from such use.  Illustrative
 * examples of non-commercial use are academic research, personal study,
 * teaching, education and corporate research & development.
 * Illustrative examples of commercial use are distributing products for
 * commercial advantage and providing services using the software for
 * commercial advantage.
 *
 * If you wish to use this software or functionality therein that may be
 * covered by patents for commercial use, please contact:
 *     Director of Intellectual Property Licensing
 *     Office of Strategy and Technology
 *     Hewlett-Packard Company
 *     1501 Page Mill Road
 *     Palo Alto, California  94304
 *
 * 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
 * the COPYRIGHT HOLDER(s), HEWLETT-PACKARD COMPANY, nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.  No right of
 * sublicense is granted herewith.  Derivatives of the software and
 * output created using the software may be prepared, but only for
 * Non-Commercial Uses.  Derivatives of the software may be shared with
 * others provided: (i) the others agree to abide by the list of
 * conditions herein which includes the Non-Commercial Use restrictions;
 * and (ii) such Derivatives of the software include the above copyright
 * notice to acknowledge the contribution from this software where
 * applicable, this list of conditions and the disclaimer below.
 *
 * 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.
 *
 * Authors: Gabe Black
 */

#include "arch/x86/insts/microregop.hh"
#include "arch/x86/miscregs.hh"
#include "base/condcodes.hh"
#include <string>

namespace X86ISA
{
    uint64_t RegOpBase::genFlags(uint64_t oldFlags, uint64_t flagMask,
            uint64_t _dest, uint64_t _src1, uint64_t _src2,
            bool subtract) const
    {
        DPRINTF(Sparc, "flagMask = %#x\n", flagMask);
        uint64_t flags = oldFlags & ~flagMask;
        if(flagMask & (ECFBit | CFBit))
        {
            if(findCarry(dataSize*8, _dest, _src1, _src2))
                flags |= (flagMask & (ECFBit | CFBit));
            if(subtract)
                flags ^= (flagMask & (ECFBit | CFBit));
        }
        if(flagMask & PFBit && findParity(dataSize*8, _dest))
            flags |= PFBit;
        if(flagMask & AFBit)
        {
            if(findCarry(4, _dest, _src1, _src2))
                flags |= AFBit;
            if(subtract)
                flags ^= AFBit;
        }
        if(flagMask & (EZFBit | ZFBit) && findZero(dataSize*8, _dest))
            flags |= (flagMask & (EZFBit | ZFBit));
        if(flagMask & SFBit && findNegative(dataSize*8, _dest))
            flags |= SFBit;
        if(flagMask & OFBit && findOverflow(dataSize*8, _dest, _src1, _src2))
            flags |= OFBit;
        return flags;
    }

    std::string RegOp::generateDisassembly(Addr pc,
            const SymbolTable *symtab) const
    {
        std::stringstream response;

        printMnemonic(response, instMnem, mnemonic);
        printDestReg(response, 0, dataSize);
        response << ", ";
        printSrcReg(response, 0, dataSize);
        response << ", ";
        printSrcReg(response, 1, dataSize);
        return response.str();
    }

    std::string RegOpImm::generateDisassembly(Addr pc,
            const SymbolTable *symtab) const
    {
        std::stringstream response;

        printMnemonic(response, instMnem, mnemonic);
        printDestReg(response, 0, dataSize);
        response << ", ";
        printSrcReg(response, 0, dataSize);
        ccprintf(response, ", %#x", imm8);
        return response.str();
    }
}
<commit_msg>X86: Get rid of stray Sparc DPRINTF<commit_after>/*
 * Copyright (c) 2007 The Hewlett-Packard Development Company
 * All rights reserved.
 *
 * Redistribution and use of this software in source and binary forms,
 * with or without modification, are permitted provided that the
 * following conditions are met:
 *
 * The software must be used only for Non-Commercial Use which means any
 * use which is NOT directed to receiving any direct monetary
 * compensation for, or commercial advantage from such use.  Illustrative
 * examples of non-commercial use are academic research, personal study,
 * teaching, education and corporate research & development.
 * Illustrative examples of commercial use are distributing products for
 * commercial advantage and providing services using the software for
 * commercial advantage.
 *
 * If you wish to use this software or functionality therein that may be
 * covered by patents for commercial use, please contact:
 *     Director of Intellectual Property Licensing
 *     Office of Strategy and Technology
 *     Hewlett-Packard Company
 *     1501 Page Mill Road
 *     Palo Alto, California  94304
 *
 * 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
 * the COPYRIGHT HOLDER(s), HEWLETT-PACKARD COMPANY, nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.  No right of
 * sublicense is granted herewith.  Derivatives of the software and
 * output created using the software may be prepared, but only for
 * Non-Commercial Uses.  Derivatives of the software may be shared with
 * others provided: (i) the others agree to abide by the list of
 * conditions herein which includes the Non-Commercial Use restrictions;
 * and (ii) such Derivatives of the software include the above copyright
 * notice to acknowledge the contribution from this software where
 * applicable, this list of conditions and the disclaimer below.
 *
 * 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.
 *
 * Authors: Gabe Black
 */

#include "arch/x86/insts/microregop.hh"
#include "arch/x86/miscregs.hh"
#include "base/condcodes.hh"
#include <string>

namespace X86ISA
{
    uint64_t RegOpBase::genFlags(uint64_t oldFlags, uint64_t flagMask,
            uint64_t _dest, uint64_t _src1, uint64_t _src2,
            bool subtract) const
    {
        DPRINTF(X86, "flagMask = %#x\n", flagMask);
        uint64_t flags = oldFlags & ~flagMask;
        if(flagMask & (ECFBit | CFBit))
        {
            if(findCarry(dataSize*8, _dest, _src1, _src2))
                flags |= (flagMask & (ECFBit | CFBit));
            if(subtract)
                flags ^= (flagMask & (ECFBit | CFBit));
        }
        if(flagMask & PFBit && findParity(dataSize*8, _dest))
            flags |= PFBit;
        if(flagMask & AFBit)
        {
            if(findCarry(4, _dest, _src1, _src2))
                flags |= AFBit;
            if(subtract)
                flags ^= AFBit;
        }
        if(flagMask & (EZFBit | ZFBit) && findZero(dataSize*8, _dest))
            flags |= (flagMask & (EZFBit | ZFBit));
        if(flagMask & SFBit && findNegative(dataSize*8, _dest))
            flags |= SFBit;
        if(flagMask & OFBit && findOverflow(dataSize*8, _dest, _src1, _src2))
            flags |= OFBit;
        return flags;
    }

    std::string RegOp::generateDisassembly(Addr pc,
            const SymbolTable *symtab) const
    {
        std::stringstream response;

        printMnemonic(response, instMnem, mnemonic);
        printDestReg(response, 0, dataSize);
        response << ", ";
        printSrcReg(response, 0, dataSize);
        response << ", ";
        printSrcReg(response, 1, dataSize);
        return response.str();
    }

    std::string RegOpImm::generateDisassembly(Addr pc,
            const SymbolTable *symtab) const
    {
        std::stringstream response;

        printMnemonic(response, instMnem, mnemonic);
        printDestReg(response, 0, dataSize);
        response << ", ";
        printSrcReg(response, 0, dataSize);
        ccprintf(response, ", %#x", imm8);
        return response.str();
    }
}
<|endoftext|>


<commit_before>#include <iostream>
#include <unistd.h>
#include <sys/stat.h>
#include <stdio.h>
#include <vector>
#include <sstream>
#include <dirent.h>
#include <errno.h>
#include <sys/types.h>
using namespace std;

bool isDirectory(char* directoryName) {

	struct stat directoryInCurrent;

	if (-1 == (stat(directoryName, &directoryInCurrent))) {

		perror("stat failed");
		return false;
	}

	if (directoryInCurrent.st_mode & S_IFDIR) {
		return true;
	}
	else {
		return false;
	}
}

int ls(char* directoryName) {

		char const *dirName = ".";
		DIR *dirp;
		if (!(dirp = opendir(dirName))) {
			cerr << "Error(" << errno << ") opening " << dirName << endl;
		}

		dirent *direntp;
		while ((direntp = readdir(dirp))) {
			if (direntp->d_name[0] != '.') {

				//cout << direntp->d_name << endl; // use stat here to find attributes of a file
				printf(direntp->d_name, 8);
				cout << " ";
			}
		}
		cout << endl;
		closedir(dirp);
		return 0;
}

int lsWithFlags(char* directoryName, vector<string> flags) {

	bool isA = false;
	bool isL = false;
	bool isR = false;
	for (unsigned i = 0; i < flags.size(); ++i) {
		for (unsigned k = 0; k < flags.at(i).size(); ++k) {
			if (flags.at(i).at(k) == 'a')
				isA = true;
			else if (flags.at(i).at(k) == 'l')
				isL = true;
			else if (flags.at(i).at(k) == 'R')
				isR = true;
		}

	}
	char const *dirName = directoryName;
	DIR *dirp;
	if (!(dirp = opendir(dirName))) {
		cerr << "Error(" << errno << ") opening " << dirName << endl;
		return errno;
	}

	dirent *direntp;
	if (isA) {
		while ((direntp = readdir(dirp))) {

			//cout << direntp->d_name << endl; // use stat here to find attributes of a file
			printf(direntp->d_name, 8);
			cout << " ";

		}
	}
	cout << endl;
	closedir(dirp);
	return 0;
}

int main(int argc, char* argv[]) {

	if (argc == 1) {

		if (errno == ls(".")) {

			return errno;
		}
	}

	else {

		vector<string> directories;
		vector<string> flags;
		vector<int> directoryIndex;
		bool directoryInArgv = false;
		for (int i = 1; i < argc; ++i) {

			if (isDirectory(argv[i])) {
				directoryInArgv = true;
				break;
			}
			else {

				if (argv[i][0] == '-') {

					flags.push_back(argv[i]);
				}
			}
		}
		if (!directoryInArgv) {

			if (errno == lsWithFlags(".", flags)) {

				return errno;
			}
		}
		else {

			cout << 131 << endl;
			for (int i = 0; i < argc; ++i) {

				if (isDirectory(argv[i])) {
					directories.push_back(argv[i]);
					directoryIndex.push_back(i);
				}
			}

			cout << "directories size: " << directories.size() << endl;
			for (unsigned int i = 0; i < directories.size(); ++i) {
				flags.clear();
				for (unsigned int k = static_cast<unsigned>(directoryIndex.at(i));
					 (i + 1) < directoryIndex.size() &&
					 k != (unsigned)directoryIndex.at(i + 1);
					  ++k) {
					if (argv[k][0] == '-') {

						flags.push_back(argv[k]);
					}
				}

				cout << "flags: ";
				for (unsigned j = 0; j < flags.size(); ++j) {

					cout << flags.at(j) << " ";
				}
				cout << endl;

				char* directoryName = new char[directories.at(i).size() + 1];
				strcpy(directoryName, directories.at(i).c_str());

				if (errno == lsWithFlags(directoryName, flags)) {

					return errno;
				}
			}
		}
	}

}

<commit_msg>changed conditions for boolean variables in lswithflags function<commit_after>#include <iostream>
#include <unistd.h>
#include <sys/stat.h>
#include <stdio.h>
#include <vector>
#include <sstream>
#include <dirent.h>
#include <errno.h>
#include <sys/types.h>
using namespace std;

bool isDirectory(char* directoryName) {

	struct stat directoryInCurrent;

	if (-1 == (stat(directoryName, &directoryInCurrent))) {

		perror("stat failed");
		return false;
	}

	if (directoryInCurrent.st_mode & S_IFDIR) {
		return true;
	}
	else {
		return false;
	}
}

int ls(char* directoryName) {

		char const *dirName = ".";
		DIR *dirp;
		if (!(dirp = opendir(dirName))) {
			cerr << "Error(" << errno << ") opening " << dirName << endl;
		}

		dirent *direntp;
		while ((direntp = readdir(dirp))) {
			if (direntp->d_name[0] != '.') {

				//cout << direntp->d_name << endl; // use stat here to find attributes of a file
				printf(direntp->d_name, 8);
				cout << " ";
			}
		}
		cout << endl;
		closedir(dirp);
		return 0;
}

int lsWithFlags(char* directoryName, vector<string> flags) {

	bool isA = false;
	bool isL = false;
	bool isR = false;
	for (unsigned i = 0; i < flags.size(); ++i) {
		for (unsigned k = 0; k < flags.at(i).size(); ++k) {
			if (flags.at(i).at(k) == 'a')
				isA = true;
			else if (flags.at(i).at(k) == 'l')
				isL = true;
			else if (flags.at(i).at(k) == 'R')
				isR = true;
		}

	}
	char const *dirName = directoryName;
	DIR *dirp;
	if (!(dirp = opendir(dirName))) {
		cerr << "Error(" << errno << ") opening " << dirName << endl;
		return errno;
	}

	dirent *direntp;
	if (isA) {
		while ((direntp = readdir(dirp))) {

			//cout << direntp->d_name << endl; // use stat here to find attributes of a file
			printf(direntp->d_name, 8);
			cout << " ";

		}
	}
	cout << endl;
	closedir(dirp);
	return 0;
}

int main(int argc, char* argv[]) {

	if (argc == 1) {

		if (errno == ls(".")) {

			return errno;
		}
	}

	else {

		vector<string> directories;
		vector<string> flags;
		vector<int> directoryIndex;
		bool directoryInArgv = false;
		for (int i = 1; i < argc; ++i) {

			if (isDirectory(argv[i])) {
				directoryInArgv = true;
				break;
			}
			else {

				if (argv[i][0] == '-') {

					flags.push_back(argv[i]);
				}
			}
		}
		if (!directoryInArgv) {

			if (errno == lsWithFlags(".", flags)) {

				return errno;
			}
		}
		else {

			cout << 131 << endl;
			for (int i = 1; i < argc; ++i) {

				if (isDirectory(argv[i])) {
					directories.push_back(argv[i]);
					directoryIndex.push_back(i);
				}
			}

			cout << "directories size: " << directories.size() << endl;
			for (unsigned int i = 0; i < directories.size(); ++i) {
				flags.clear();
				for (unsigned int k = static_cast<unsigned>(directoryIndex.at(i));
					 (i + 1) < directoryIndex.size() &&
					 k != (unsigned)directoryIndex.at(i + 1);
					  ++k) {
					if (argv[k][0] == '-') {

						flags.push_back(argv[k]);
					}
				}

				cout << "flags: ";
				for (unsigned j = 0; j < flags.size(); ++j) {

					cout << flags.at(j) << " ";
				}
				cout << endl;

				char* directoryName = new char[directories.at(i).size() + 1];
				strcpy(directoryName, directories.at(i).c_str());

				if (errno == lsWithFlags(directoryName, flags)) {

					return errno;
				}
			}
		}
	}

}

<|endoftext|>


<commit_before>//
//#include <unistd.h>
#include <cstdio>
#include <cstdlib>
#include <string>
#include <ctime>
#include <algorithm>
#include <cmath>
#include "GPIOClass.h"

using namespace std;

void Pulse(GPIOClass* pin, double cycles);
void Wait(double seconds);
clock_t timer;
double time_to_complete;
double resolution = 100;

#define PI 4*atan(1)

int main (int argc, char *argv[]) {
	string type = argv[1];
	transform(type.begin(), type.end(), type.begin(), :: tolower);
	// lets assume that the way to run this is
	// pwm.exe [rising/falling/sine/constant]
	if (argc != 2) {
		cout << "Usage: pwm [rising/falling/sine/constant/blink]" << endl;
		return -1;
	}

	while (time_to_complete <= 0) {
		cout << "Input How Long To Run (in seconds)" << endl;
		cin >> time_to_complete;
	}

	GPIOClass* out1 = new GPIOClass("4");
	GPIOClass* in2 = new GPIOClass("17");

	out1->export_gpio();
	in2->export_gpio();

	out1->setdir_gpio("out");
	in2->setdir_gpio("in");

	cout << "Pins are setup." << endl;
	// avoiding flickering will be at 100hz
	// aka turn on and off 100 times a sec
	// a cycle of 0 is off
	// a cycle of 100 is on

	if (type == "rising") {
		clock_t finish = clock() + time_to_complete * CLOCKS_PER_SEC;
		double t = time_to_complete;
		while (clock() < finish) {
			// pulse for however long we need to to achieve brightness.
				t -= (1/t);
				//cout << sin((PI/2) * (1/t)) << endl;
				Pulse(out1, sin((PI/2) * (1/t)));
				Wait(sin((PI/2) * (1/t)));
		}
	}
	if (type == "falling") {

	}
	if (type == "sine") {

	}
	if (type == "constant") {
		out1->setval_gpio("1"); // turn the pin on
		Wait(time_to_complete); // sleep for number of cycles / 1/100 sec
		//cout << "Waiting during pulse" << endl;
		out1->setval_gpio("0"); // turn the pin off
	}
	if (type == "blink") { // aka. TESTR
		clock_t finish = clock() + time_to_complete * CLOCKS_PER_SEC;
		while (clock() < finish) {
			// pulse for however long we need to to achieve brightness.
			Pulse(out1, 1 * resolution);
			Wait(0.5);
		}
	}
	cout << "Done." << endl;
}

//1 cycle is 1/100th of a second
//100 cycles is 1 sec
void Pulse(GPIOClass* pin, double cycles) {
	bool running = true;
	while (running) {
		pin->setval_gpio("1"); // turn the pin on
		Wait(cycles / resolution); // sleep for number of cycles / 1/100 sec
		//cout << "Waiting during pulse" << endl;
		pin->setval_gpio("0"); // turn the pin off
		running = false; // this is unnessesary but could be useful if modified a bit.
	}
}

void Wait ( double seconds )
{
	clock_t endwait;
	endwait = clock () + seconds * CLOCKS_PER_SEC ;
	while (clock() < endwait) {}
}
<commit_msg>Update pwm.cpp<commit_after>//
//#include <unistd.h>
#include <cstdio>
#include <cstdlib>
#include <string>
#include <ctime>
#include <algorithm>
#include <cmath>
#include "GPIOClass.h"

using namespace std;

void Pulse(GPIOClass* pin, double cycles);
void Wait(double seconds);
clock_t timer;
double time_to_complete;
double resolution = 100;

#define PI 4*atan(1)

int main (int argc, char *argv[]) {
	string type = argv[1];
	transform(type.begin(), type.end(), type.begin(), :: tolower);
	// lets assume that the way to run this is
	// pwm.exe [rising/falling/sine/constant]
	if (argc != 2) {
		cout << "Usage: pwm [rising/falling/sine/constant/blink]" << endl;
		return -1;
	}

	while (time_to_complete <= 0) {
		cout << "Input How Long To Run (in seconds)" << endl;
		cin >> time_to_complete;
	}

	GPIOClass* out1 = new GPIOClass("4");
	GPIOClass* in2 = new GPIOClass("17");

	out1->export_gpio();
	in2->export_gpio();

	out1->setdir_gpio("out");
	in2->setdir_gpio("in");

	cout << "Pins are setup." << endl;
	// avoiding flickering will be at 100hz
	// aka turn on and off 100 times a sec
	// a cycle of 0 is off
	// a cycle of 100 is on

	if (type == "rising") {
		clock_t finish = clock() + time_to_complete * CLOCKS_PER_SEC;
		double t = time_to_complete;
		while (clock() < finish) {
			// pulse for however long we need to to achieve brightness.
				t -= 1;
				cout << t << endl;
				Pulse(out1, sin((PI/2) * (1/t)));
				Wait(sin((PI/2) * (1/t)));
		}
	}
	if (type == "falling") {

	}
	if (type == "sine") {

	}
	if (type == "constant") {
		out1->setval_gpio("1"); // turn the pin on
		Wait(time_to_complete); // sleep for number of cycles / 1/100 sec
		//cout << "Waiting during pulse" << endl;
		out1->setval_gpio("0"); // turn the pin off
	}
	if (type == "blink") { // aka. TESTR
		clock_t finish = clock() + time_to_complete * CLOCKS_PER_SEC;
		while (clock() < finish) {
			// pulse for however long we need to to achieve brightness.
			Pulse(out1, 1 * resolution);
			Wait(0.5);
		}
	}
	cout << "Done." << endl;
}

//1 cycle is 1/100th of a second
//100 cycles is 1 sec
void Pulse(GPIOClass* pin, double cycles) {
	bool running = true;
	while (running) {
		pin->setval_gpio("1"); // turn the pin on
		Wait(cycles / resolution); // sleep for number of cycles / 1/100 sec
		//cout << "Waiting during pulse" << endl;
		pin->setval_gpio("0"); // turn the pin off
		running = false; // this is unnessesary but could be useful if modified a bit.
	}
}

void Wait ( double seconds )
{
	clock_t endwait;
	endwait = clock () + seconds * CLOCKS_PER_SEC ;
	while (clock() < endwait) {}
}
<|endoftext|>


<commit_before>/*******************************************************************************
 *
 * MIT License
 *
 * Copyright (c) 2017 Advanced Micro Devices, Inc.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *
 *******************************************************************************/
#include "driver.hpp"
#include "test.hpp"
#include "verify.hpp"
#include "get_handle.hpp"
#include "tensor_holder.hpp"
#include <miopen/miopen.h>
#include <miopen/tensor.hpp>
#include <miopen/stringutils.hpp>
#include <miopen/lrn.hpp>
#include <random>
#include <algorithm>
#include <iterator>
#include <limits>
#include <iostream>

template <class T>
struct verify_lrn_foward
{
    miopen::LRNDescriptor lrn;
    tensor<T> input;

    tensor<T> cpu()
    {
        auto output = input;
        int n_batch, channels, height, width;
        std::tie(n_batch, channels, height, width) = miopen::tien<4>(input.desc.GetLengths());

        auto alpha  = lrn.GetAlpha();
        auto beta   = lrn.GetBeta();
        auto K      = lrn.GetK();
        auto lrn_n  = lrn.GetN();
        auto radius = (lrn.GetN() - 1) / 2;
        auto mode   = lrn.GetMode();

        CHECK((lrn_n & 1) == 1);
        if(mode == miopenLRNCrossChannel)
        {
            auto alphaoverarea = alpha / lrn_n;

            par_ford(n_batch, height, width)([&](int b, int h, int w) {
                double scale = 0;
                ford(channels)([&](int c) {
                    auto start = (c - radius) < 0 ? 0 : (c - radius);
                    auto end   = (c + radius) > channels ? channels : (c + radius);

                    for(auto k = start; k < end; k++)
                    {
                        scale += std::pow(input(b, k, h, w), 2);
                    }

                    scale *= alphaoverarea;
                    scale += K;
                    scale = std::pow(scale, -beta);

                    output(b, c, h, w) = input(b, c, h, w) * scale;
                });
            });
        }
        else
        {

            par_ford(n_batch, channels)([&](int b, int c) {
                double scale = 0;
                ford(height, width)([&](int h, int w) {
                    auto left          = (w - radius) < 0 ? 0 : (w - radius);
                    auto right         = (w + radius) > width ? width : (w + radius);
                    auto top           = (h - radius) < 0 ? 0 : (h - radius);
                    auto bottom        = (h + radius) > height ? height : (h + radius);
                    auto alphaoverarea = alpha / ((right - left) * (bottom - top));

                    for(auto i = left; i < right; i++)
                    {
                        for(auto j = top; j < bottom; j++)
                        {
                            scale += std::pow(input(b, c, h, w), 2);
                        }
                    }
                    scale *= alphaoverarea;
                    scale += K;
                    scale = std::pow(scale, -beta);
                    output(b, c, h, w) = input(b, c, h, w) * scale;
                });
            });
        }

        return output;
    }

    tensor<T> gpu()
    {
        auto&& handle = get_handle();
        auto out      = input;
        auto in_dev   = handle.Write(input.data);
        auto out_dev  = handle.Write(out.data);
        auto alpha    = lrn.GetAlpha();
        auto beta     = lrn.GetBeta();
        auto bDoBwd   = false;

        lrn.Forward(handle,
                    &alpha,
                    input.desc,
                    in_dev.get(),
                    &beta,
                    out.desc,
                    out_dev.get(),
                    bDoBwd,
                    nullptr);

        out.data = handle.Read<T>(out_dev, out.data.size());
        return out;
    }

    void fail(int)
    {
        std::cout << "verify_lrn_foward" << std::endl;
        std::cout << "Input Tensor"
                  << " " << input.desc.ToString() << std::endl;
    }
};

template <class T>
struct verify_lrn_bwd
{

    miopen::LRNDescriptor lrn;
    tensor<T> inputY;
    tensor<T> inputDY;
    tensor<T> inputX;
    tensor<T> outputDX;
    tensor<T> scale;

    tensor<T> cpu()
    {
        int n_batch, channels, height, width;
        std::tie(n_batch, channels, height, width) = miopen::tien<4>(inputY.desc.GetLengths());

        auto alpha  = lrn.GetAlpha();
        auto beta   = lrn.GetBeta();
        auto lrn_n  = lrn.GetN();
        auto mode   = lrn.GetMode();
        auto radius = (lrn_n - 1) / 2;

        if(mode == miopenLRNWithinChannel)
        {
            par_ford(n_batch, channels)([&](int b, int c) {
                ford(height, width)([&](int h, int w) {
                    double ydy             = 0;
                    auto left              = (w - radius) < 0 ? 0 : (w - radius);
                    auto right             = (left + lrn_n) > width ? width : (left + lrn_n);
                    auto top               = (h - radius) < 0 ? 0 : (h - radius);
                    auto bottom            = (top + lrn_n) > height ? height : (top + lrn_n);
                    auto adjust_area       = (right - left) * (bottom - top);
                    auto cache_ratio_value = 2 * alpha * beta / adjust_area;

                    for(auto i = left; i < right; i++)
                    {
                        for(auto j = top; j < bottom; j++)
                        {
                            ydy += (inputY(b, c, j, i) * inputDY(b, c, j, i) / scale(b, c, j, i));
                        }
                    }

                    outputDX(b, c, h, w) = pow(scale(b, c, h, w), -beta) * inputDY(b, c, h, w) -
                                           cache_ratio_value * inputX(b, c, h, w) * ydy;
                });
            });
        }
        else
        {
            auto cache_ratio_value = 2 * alpha * beta / lrn_n;

            par_ford(n_batch, height, width)([&](int b, int h, int w) {
                ford(channels)([&](int c) {
                    double ydy = 0;
                    auto start = (c - radius) < 0 ? 0 : (c - radius);
                    auto end   = (c + radius) > channels ? channels : (c + radius);

                    for(auto k = start; k < end; k++)
                    {
                        ydy += (inputY(b, k, h, w) * inputDY(b, k, h, w) / scale(b, k, h, w));
                    }

                    outputDX(b, c, h, w) = pow(scale(b, c, h, w), -beta) * inputDY(b, c, h, w) -
                                           cache_ratio_value * inputX(b, c, h, w) * ydy;
                });
            });
        }

        return outputDX;
    }

    tensor<T> gpu()
    {
        auto&& handle     = get_handle();
        auto inputY_dev   = handle.Write(inputY.data);
        auto inputDY_dev  = handle.Write(inputDY.data);
        auto inputX_dev   = handle.Write(inputX.data);
        auto outputDX_dev = handle.Create<T>(outputDX.data.size());
        auto scale_dev    = handle.Write(scale.data);

        auto alpha = lrn.GetAlpha(), beta = lrn.GetBeta();
        lrn.Backward(handle,
                     &alpha,
                     inputY.desc, // Y
                     inputY_dev.get(),
                     inputDY.desc, // DY
                     inputDY_dev.get(),
                     inputX.desc, // X
                     inputX_dev.get(),
                     &beta,
                     outputDX.desc, // DX
                     outputDX_dev.get(),
                     scale_dev.get());

        outputDX.data = handle.Read<T>(outputDX_dev, outputDX.data.size());
        return outputDX;
    }

    void fail(int)
    {
        std::cout << "verify_lrn_bwd" << std::endl;
        std::cout << "Input Tensor Y"
                  << " " << inputY.desc.ToString() << std::endl;
        std::cout << "Input Tensor DY"
                  << " " << inputDY.desc.ToString() << std::endl;
        std::cout << "Input Tensor X"
                  << " " << scale.desc.ToString() << std::endl;
    }
};

template <class T>
struct lrn_driver : test_driver
{
    tensor<T> input;

    unsigned int n = 0;
    T alpha        = 0;
    T beta         = 0;
    T k            = 0;
    std::string mode;

    std::unordered_map<std::string, miopenLRNMode_t> mode_lookup = {
        {"WITHIN_CHANNEL", miopenLRNWithinChannel}, {"ACROSS_CHANNEL", miopenLRNCrossChannel}};

    lrn_driver()
    {
        add(input, "input", get_input_tensor());
        add(n, "N", generate_data({1, 3, 5}));
        add(alpha, "alpha", generate_data({1.0}));
        add(beta, "beta", generate_data({0}));
        add(k, "K", generate_data({1}));
        add(mode, "mode", generate_data({"Within_Channel", "Across_Channel"}));
    }

    void run()
    {
        miopen::LRNDescriptor lrn{mode_lookup.at(miopen::ToUpper(mode)), n, {alpha, beta, k}};

        auto OutputDX   = input;
        auto fwd_output = verify(verify_lrn_foward<T>{lrn, input});
        auto out = fwd_output.first;

        std::size_t n_batch, channels, height, width;
        std::tie(n_batch, channels, height, width) = miopen::tien<4>(input.desc.GetLengths());
        auto scale  = tensor<T>{n_batch, channels, height, width}.generate(rand_gen{});
        auto inputX = tensor<T>{n_batch, channels, height, width}.generate(rand_gen{});
        par_ford(n_batch, channels, height, width)([&](int b, int c, int h, int w) { scale(b, c, h, w) += 1; });

        auto bwd_output = verify(verify_lrn_bwd<T>{lrn, input, out, inputX, OutputDX, scale});
    };
};

int main(int argc, const char *argv[]) { test_drive<lrn_driver<float>>(argc, argv); };
<commit_msg>clang-format fix<commit_after>/*******************************************************************************
 *
 * MIT License
 *
 * Copyright (c) 2017 Advanced Micro Devices, Inc.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *
 *******************************************************************************/
#include "driver.hpp"
#include "test.hpp"
#include "verify.hpp"
#include "get_handle.hpp"
#include "tensor_holder.hpp"
#include <miopen/miopen.h>
#include <miopen/tensor.hpp>
#include <miopen/stringutils.hpp>
#include <miopen/lrn.hpp>
#include <random>
#include <algorithm>
#include <iterator>
#include <limits>
#include <iostream>

template <class T>
struct verify_lrn_foward
{
    miopen::LRNDescriptor lrn;
    tensor<T> input;

    tensor<T> cpu()
    {
        auto output = input;
        int n_batch, channels, height, width;
        std::tie(n_batch, channels, height, width) = miopen::tien<4>(input.desc.GetLengths());

        auto alpha  = lrn.GetAlpha();
        auto beta   = lrn.GetBeta();
        auto K      = lrn.GetK();
        auto lrn_n  = lrn.GetN();
        auto radius = (lrn.GetN() - 1) / 2;
        auto mode   = lrn.GetMode();

        CHECK((lrn_n & 1) == 1);
        if(mode == miopenLRNCrossChannel)
        {
            auto alphaoverarea = alpha / lrn_n;

            par_ford(n_batch, height, width)([&](int b, int h, int w) {
                double scale = 0;
                ford(channels)([&](int c) {
                    auto start = (c - radius) < 0 ? 0 : (c - radius);
                    auto end   = (c + radius) > channels ? channels : (c + radius);

                    for(auto k = start; k < end; k++)
                    {
                        scale += std::pow(input(b, k, h, w), 2);
                    }

                    scale *= alphaoverarea;
                    scale += K;
                    scale = std::pow(scale, -beta);

                    output(b, c, h, w) = input(b, c, h, w) * scale;
                });
            });
        }
        else
        {

            par_ford(n_batch, channels)([&](int b, int c) {
                double scale = 0;
                ford(height, width)([&](int h, int w) {
                    auto left          = (w - radius) < 0 ? 0 : (w - radius);
                    auto right         = (w + radius) > width ? width : (w + radius);
                    auto top           = (h - radius) < 0 ? 0 : (h - radius);
                    auto bottom        = (h + radius) > height ? height : (h + radius);
                    auto alphaoverarea = alpha / ((right - left) * (bottom - top));

                    for(auto i = left; i < right; i++)
                    {
                        for(auto j = top; j < bottom; j++)
                        {
                            scale += std::pow(input(b, c, h, w), 2);
                        }
                    }
                    scale *= alphaoverarea;
                    scale += K;
                    scale = std::pow(scale, -beta);
                    output(b, c, h, w) = input(b, c, h, w) * scale;
                });
            });
        }

        return output;
    }

    tensor<T> gpu()
    {
        auto&& handle = get_handle();
        auto out      = input;
        auto in_dev   = handle.Write(input.data);
        auto out_dev  = handle.Write(out.data);
        auto alpha    = lrn.GetAlpha();
        auto beta     = lrn.GetBeta();
        auto bDoBwd   = false;

        lrn.Forward(handle,
                    &alpha,
                    input.desc,
                    in_dev.get(),
                    &beta,
                    out.desc,
                    out_dev.get(),
                    bDoBwd,
                    nullptr);

        out.data = handle.Read<T>(out_dev, out.data.size());
        return out;
    }

    void fail(int)
    {
        std::cout << "verify_lrn_foward" << std::endl;
        std::cout << "Input Tensor"
                  << " " << input.desc.ToString() << std::endl;
    }
};

template <class T>
struct verify_lrn_bwd
{

    miopen::LRNDescriptor lrn;
    tensor<T> inputY;
    tensor<T> inputDY;
    tensor<T> inputX;
    tensor<T> outputDX;
    tensor<T> scale;

    tensor<T> cpu()
    {
        int n_batch, channels, height, width;
        std::tie(n_batch, channels, height, width) = miopen::tien<4>(inputY.desc.GetLengths());

        auto alpha  = lrn.GetAlpha();
        auto beta   = lrn.GetBeta();
        auto lrn_n  = lrn.GetN();
        auto mode   = lrn.GetMode();
        auto radius = (lrn_n - 1) / 2;

        if(mode == miopenLRNWithinChannel)
        {
            par_ford(n_batch, channels)([&](int b, int c) {
                ford(height, width)([&](int h, int w) {
                    double ydy             = 0;
                    auto left              = (w - radius) < 0 ? 0 : (w - radius);
                    auto right             = (left + lrn_n) > width ? width : (left + lrn_n);
                    auto top               = (h - radius) < 0 ? 0 : (h - radius);
                    auto bottom            = (top + lrn_n) > height ? height : (top + lrn_n);
                    auto adjust_area       = (right - left) * (bottom - top);
                    auto cache_ratio_value = 2 * alpha * beta / adjust_area;

                    for(auto i = left; i < right; i++)
                    {
                        for(auto j = top; j < bottom; j++)
                        {
                            ydy += (inputY(b, c, j, i) * inputDY(b, c, j, i) / scale(b, c, j, i));
                        }
                    }

                    outputDX(b, c, h, w) = pow(scale(b, c, h, w), -beta) * inputDY(b, c, h, w) -
                                           cache_ratio_value * inputX(b, c, h, w) * ydy;
                });
            });
        }
        else
        {
            auto cache_ratio_value = 2 * alpha * beta / lrn_n;

            par_ford(n_batch, height, width)([&](int b, int h, int w) {
                ford(channels)([&](int c) {
                    double ydy = 0;
                    auto start = (c - radius) < 0 ? 0 : (c - radius);
                    auto end   = (c + radius) > channels ? channels : (c + radius);

                    for(auto k = start; k < end; k++)
                    {
                        ydy += (inputY(b, k, h, w) * inputDY(b, k, h, w) / scale(b, k, h, w));
                    }

                    outputDX(b, c, h, w) = pow(scale(b, c, h, w), -beta) * inputDY(b, c, h, w) -
                                           cache_ratio_value * inputX(b, c, h, w) * ydy;
                });
            });
        }

        return outputDX;
    }

    tensor<T> gpu()
    {
        auto&& handle     = get_handle();
        auto inputY_dev   = handle.Write(inputY.data);
        auto inputDY_dev  = handle.Write(inputDY.data);
        auto inputX_dev   = handle.Write(inputX.data);
        auto outputDX_dev = handle.Create<T>(outputDX.data.size());
        auto scale_dev    = handle.Write(scale.data);

        auto alpha = lrn.GetAlpha(), beta = lrn.GetBeta();
        lrn.Backward(handle,
                     &alpha,
                     inputY.desc, // Y
                     inputY_dev.get(),
                     inputDY.desc, // DY
                     inputDY_dev.get(),
                     inputX.desc, // X
                     inputX_dev.get(),
                     &beta,
                     outputDX.desc, // DX
                     outputDX_dev.get(),
                     scale_dev.get());

        outputDX.data = handle.Read<T>(outputDX_dev, outputDX.data.size());
        return outputDX;
    }

    void fail(int)
    {
        std::cout << "verify_lrn_bwd" << std::endl;
        std::cout << "Input Tensor Y"
                  << " " << inputY.desc.ToString() << std::endl;
        std::cout << "Input Tensor DY"
                  << " " << inputDY.desc.ToString() << std::endl;
        std::cout << "Input Tensor X"
                  << " " << scale.desc.ToString() << std::endl;
    }
};

template <class T>
struct lrn_driver : test_driver
{
    tensor<T> input;

    unsigned int n = 0;
    T alpha        = 0;
    T beta         = 0;
    T k            = 0;
    std::string mode;

    std::unordered_map<std::string, miopenLRNMode_t> mode_lookup = {
        {"WITHIN_CHANNEL", miopenLRNWithinChannel}, {"ACROSS_CHANNEL", miopenLRNCrossChannel}};

    lrn_driver()
    {
        add(input, "input", get_input_tensor());
        add(n, "N", generate_data({1, 3, 5}));
        add(alpha, "alpha", generate_data({1.0}));
        add(beta, "beta", generate_data({0}));
        add(k, "K", generate_data({1}));
        add(mode, "mode", generate_data({"Within_Channel", "Across_Channel"}));
    }

    void run()
    {
        miopen::LRNDescriptor lrn{mode_lookup.at(miopen::ToUpper(mode)), n, {alpha, beta, k}};

        auto OutputDX   = input;
        auto fwd_output = verify(verify_lrn_foward<T>{lrn, input});
        auto out        = fwd_output.first;

        std::size_t n_batch, channels, height, width;
        std::tie(n_batch, channels, height, width) = miopen::tien<4>(input.desc.GetLengths());
        auto scale  = tensor<T>{n_batch, channels, height, width}.generate(rand_gen{});
        auto inputX = tensor<T>{n_batch, channels, height, width}.generate(rand_gen{});
        par_ford(n_batch, channels, height, width)(
            [&](int b, int c, int h, int w) { scale(b, c, h, w) += 1; });

        auto bwd_output = verify(verify_lrn_bwd<T>{lrn, input, out, inputX, OutputDX, scale});
    };
};

int main(int argc, const char* argv[]) { test_drive<lrn_driver<float>>(argc, argv); };
<|endoftext|>


<commit_before>namespace factor
{

template<typename T>
struct identity {
	T operator()(T t)
	{
		return t;
	}
};

struct no_fixup {
	static const bool translated_code_block_map = false;

	object *fixup_data(object *obj)
	{
		return obj;
	}

	code_block *fixup_code(code_block *compiled)
	{
		return compiled;
	}

	object *translate_data(const object *obj)
	{
		return fixup_data((object *)obj);
	}

	code_block *translate_code(const code_block *compiled)
	{
		return fixup_code((code_block *)compiled);
	}

	cell size(object *obj)
	{
		return obj->size();
	}

	cell size(code_block *compiled)
	{
		return compiled->size();
	}
};

}
<commit_msg>VM: Refactor fixup.hpp to Factor style<commit_after>namespace factor {

template <typename T> struct identity {
  T operator()(T t) { return t; }
};

struct no_fixup {
  static const bool translated_code_block_map = false;

  object* fixup_data(object* obj) { return obj; }

  code_block* fixup_code(code_block* compiled) { return compiled; }

  object* translate_data(const object* obj) { return fixup_data((object*)obj); }

  code_block* translate_code(const code_block* compiled) {
    return fixup_code((code_block*)compiled);
  }

  cell size(object* obj) { return obj->size(); }

  cell size(code_block* compiled) { return compiled->size(); }
};

}
<|endoftext|>


<commit_before>#include "master.hpp"

namespace factor {

bool factor_arg(const vm_char* str, const vm_char* arg, cell* value) {
  int val;
  if (SSCANF(str, arg, &val) > 0) {
    *value = val;
    return true;
  }
  return false;
}

vm_parameters::vm_parameters() {
  embedded_image = false;
  image_path = NULL;

  datastack_size = 32 * sizeof(cell);
  retainstack_size = 32 * sizeof(cell);

#if defined(FACTOR_PPC)
  callstack_size = 256 * sizeof(cell);
#else
  callstack_size = 128 * sizeof(cell);
#endif

  code_size = 64;
  young_size = sizeof(cell) / 4;
  aging_size = sizeof(cell) / 2;
  tenured_size = 24 * sizeof(cell);

  max_pic_size = 3;

  fep = false;
  signals = true;

#ifdef WINDOWS
  console = GetConsoleWindow() != NULL;
#else
  console = true;
#endif

  callback_size = 256;
}

void vm_parameters::init_from_args(int argc, vm_char** argv) {
  executable_path = argv[0];

  int i = 0;

  for (i = 1; i < argc; i++) {
    vm_char* arg = argv[i];
    if (STRCMP(arg, STRING_LITERAL("--")) == 0)
      break;
    else if (factor_arg(arg, STRING_LITERAL("-datastack=%d"),
                        &datastack_size))
      ;
    else if (factor_arg(arg, STRING_LITERAL("-retainstack=%d"),
                        &retainstack_size))
      ;
    else if (factor_arg(arg, STRING_LITERAL("-callstack=%d"),
                        &callstack_size))
      ;
    else if (factor_arg(arg, STRING_LITERAL("-young=%d"), &young_size))
      ;
    else if (factor_arg(arg, STRING_LITERAL("-aging=%d"), &aging_size))
      ;
    else if (factor_arg(arg, STRING_LITERAL("-tenured=%d"), &tenured_size))
      ;
    else if (factor_arg(arg, STRING_LITERAL("-codeheap=%d"), &code_size))
      ;
    else if (factor_arg(arg, STRING_LITERAL("-pic=%d"), &max_pic_size))
      ;
    else if (factor_arg(arg, STRING_LITERAL("-callbacks=%d"), &callback_size))
      ;
    else if (STRNCMP(arg, STRING_LITERAL("-i="), 3) == 0)
      image_path = arg + 3;
    else if (STRCMP(arg, STRING_LITERAL("-fep")) == 0)
      fep = true;
    else if (STRCMP(arg, STRING_LITERAL("-nosignals")) == 0)
      signals = false;
    else if (STRCMP(arg, STRING_LITERAL("-console")) == 0)
      console = true;
  }
}

void factor_vm::load_data_heap(FILE* file, image_header* h, vm_parameters* p) {
  p->tenured_size = std::max((h->data_size * 3) / 2, p->tenured_size);

  init_data_heap(p->young_size, p->aging_size, p->tenured_size);

  fixnum bytes_read =
      raw_fread((void*)data->tenured->start, 1, h->data_size, file);

  if ((cell)bytes_read != h->data_size) {
    std::cout << "truncated image: " << bytes_read << " bytes read, ";
    std::cout << h->data_size << " bytes expected\n";
    fatal_error("load_data_heap failed", 0);
  }

  data->tenured->initial_free_list(h->data_size);
}

void factor_vm::load_code_heap(FILE* file, image_header* h, vm_parameters* p) {
  if (h->code_size > p->code_size)
    fatal_error("Code heap too small to fit image", h->code_size);

  code = new code_heap(p->code_size);

  if (h->code_size != 0) {
    size_t bytes_read =
        raw_fread((void*)code->allocator->start, 1, h->code_size, file);
    if (bytes_read != h->code_size) {
      std::cout << "truncated image: " << bytes_read << " bytes read, ";
      std::cout << h->code_size << " bytes expected\n";
      fatal_error("load_code_heap failed", 0);
    }
  }

  code->allocator->initial_free_list(h->code_size);
  code->initialize_all_blocks_set();
}

struct startup_fixup {
  static const bool translated_code_block_map = true;

  cell data_offset;
  cell code_offset;

  startup_fixup(cell data_offset, cell code_offset)
      : data_offset(data_offset), code_offset(code_offset) {}

  object* fixup_data(object* obj) {
    return (object*)((cell)obj + data_offset);
  }

  code_block* fixup_code(code_block* obj) {
    return (code_block*)((cell)obj + code_offset);
  }

  object* translate_data(const object* obj) { return fixup_data((object*)obj); }

  code_block* translate_code(const code_block* compiled) {
    return fixup_code((code_block*)compiled);
  }

  cell size(const object* obj) { return obj->size(*this); }

  cell size(code_block* compiled) { return compiled->size(*this); }
};

void factor_vm::fixup_heaps(cell data_offset, cell code_offset) {
  startup_fixup fixup(data_offset, code_offset);
  slot_visitor<startup_fixup> visitor(this, fixup);
  visitor.visit_all_roots();

  auto start_object_updater = [&](object *obj, cell size) {
    data->tenured->starts.record_object_start_offset(obj);
    visitor.visit_slots(obj);
    switch (obj->type()) {
      case ALIEN_TYPE: {
        alien* ptr = (alien*)obj;
        if (to_boolean(ptr->base))
          ptr->update_address();
        else
          ptr->expired = special_objects[OBJ_CANONICAL_TRUE];
        break;
      }
      case DLL_TYPE: {
        ffi_dlopen((dll*)obj);
        break;
      }
      default: {
        visitor.visit_object_code_block(obj);
        break;
      }
    }
  };
  data->tenured->iterate(start_object_updater, fixup);

  auto updater = [&](code_block* compiled, cell size) {
    visitor.visit_code_block_objects(compiled);
    cell rel_base = compiled->entry_point() - fixup.code_offset;
    visitor.visit_instruction_operands(compiled, rel_base);
  };
  code->allocator->iterate(updater, fixup);
}

bool factor_vm::read_embedded_image_footer(FILE* file,
                                           embedded_image_footer* footer) {
  safe_fseek(file, -(off_t)sizeof(embedded_image_footer), SEEK_END);
  safe_fread(footer, (off_t)sizeof(embedded_image_footer), 1, file);
  return footer->magic == image_magic;
}

char *threadsafe_strerror(int errnum) {
  char *buf = (char *) malloc(STRERROR_BUFFER_SIZE);
  if(!buf) {
    fatal_error("Out of memory in threadsafe_strerror, errno", errnum);
  }
  THREADSAFE_STRERROR(errnum, buf, STRERROR_BUFFER_SIZE);
  return buf;
}

FILE* factor_vm::open_image(vm_parameters* p) {
  if (!p->embedded_image)
    return OPEN_READ(p->image_path);

  FILE* file = OPEN_READ(p->executable_path);
  if (file == NULL) {
    std::cout << "Cannot open embedded image" << std::endl;
    char *msg = threadsafe_strerror(errno);
    std::cout << "strerror:1: " << msg << std::endl;
    free(msg);
    exit(1);
  }
  embedded_image_footer footer;
  if (!read_embedded_image_footer(file, &footer)) {
    std::cout << "No embedded image" << std::endl;
    exit(1);
  }
  safe_fseek(file, (off_t)footer.image_offset, SEEK_SET);
  return file;
}

/* Read an image file from disk, only done once during startup */
/* This function also initializes the data and code heaps */
void factor_vm::load_image(vm_parameters* p) {
  FILE* file = open_image(p);
  if (file == NULL) {
    std::cout << "Cannot open image file: " << p->image_path << std::endl;
    char *msg = threadsafe_strerror(errno);
    std::cout << "strerror:2: " << msg << std::endl;
    free(msg);
    exit(1);
  }
  image_header h;
  if (raw_fread(&h, sizeof(image_header), 1, file) != 1)
    fatal_error("Cannot read image header", 0);

  if (h.magic != image_magic)
    fatal_error("Bad image: magic number check failed", h.magic);

  if (h.version != image_version)
    fatal_error("Bad image: version number check failed", h.version);

  load_data_heap(file, &h, p);
  load_code_heap(file, &h, p);

  raw_fclose(file);

  /* Certain special objects in the image are known to the runtime */
  memcpy(special_objects, h.special_objects, sizeof(special_objects));

  cell data_offset = data->tenured->start - h.data_relocation_base;
  cell code_offset = code->allocator->start - h.code_relocation_base;
  fixup_heaps(data_offset, code_offset);

  /* Store image path name */
  special_objects[OBJ_IMAGE] = allot_alien(false_object, (cell)p->image_path);
}

/* Save the current image to disk. We don't throw any exceptions here
   because if the 'then-die' argument is t it is not safe to do
   so. Instead we signal failure by returning false. */
bool factor_vm::save_image(const vm_char* saving_filename,
                           const vm_char* filename) {
  image_header h;

  h.magic = image_magic;
  h.version = image_version;
  h.data_relocation_base = data->tenured->start;
  h.data_size = data->tenured->occupied_space();
  h.code_relocation_base = code->allocator->start;
  h.code_size = code->allocator->occupied_space();

  for (cell i = 0; i < special_object_count; i++)
    h.special_objects[i] =
        (save_special_p(i) ? special_objects[i] : false_object);

  FILE* file = OPEN_WRITE(saving_filename);
  if (file == NULL)
    return false;
  if (safe_fwrite(&h, sizeof(image_header), 1, file) != 1)
    return false;
  if (h.data_size > 0 &&
      safe_fwrite((void*)data->tenured->start, h.data_size, 1, file) != 1)
    return false;
  if (h.code_size > 0 &&
      safe_fwrite((void*)code->allocator->start, h.code_size, 1, file) != 1)
    return false;
  if (raw_fclose(file) == -1)
    return false;
  if (!move_file(saving_filename, filename))
    return false;
  return true;
}

/* Allocates memory */
void factor_vm::primitive_save_image() {
  /* We unbox this before doing anything else. This is the only point
     where we might throw an error, so we have to throw an error here since
     later steps destroy the current image. */
  bool then_die = to_boolean(ctx->pop());
  byte_array* path2 = untag_check<byte_array>(ctx->pop());
  byte_array* path1 = untag_check<byte_array>(ctx->pop());

  /* Copy the paths to non-gc memory to avoid them hanging around in
     the saved image. */
  vm_char* path1_saved = safe_strdup(path1->data<vm_char>());
  vm_char* path2_saved = safe_strdup(path2->data<vm_char>());

  if (then_die) {
    /* strip out special_objects data which is set on startup anyway */
    for (cell i = 0; i < special_object_count; i++)
      if (!save_special_p(i))
        special_objects[i] = false_object;

    /* dont trace objects only reachable from context stacks so we don't
       get volatile data saved in the image. */
    active_contexts.clear();
    code->uninitialized_blocks.clear();

    /* I think clearing the callback heap should be fine too. */
    callbacks->allocator->initial_free_list(0);
  }

  /* do a full GC to push everything remaining into tenured space */
  primitive_compact_gc();

  /* Save the image */
  bool ret = save_image(path1_saved, path2_saved);
  if (then_die) {
    exit(ret ? 0 : 1);
  }
  free(path1_saved);
  free(path2_saved);

  if (!ret) {
    general_error(ERROR_IO, tag_fixnum(errno), false_object);
  }
}

bool factor_vm::embedded_image_p() {
  const vm_char* vm_path = vm_executable_path();
  if (!vm_path)
    return false;
  FILE* file = OPEN_READ(vm_path);
  if (!file)
    return false;
  embedded_image_footer footer;
  bool embedded_p = read_embedded_image_footer(file, &footer);
  fclose(file);
  return embedded_p;
}

}
<commit_msg>VM: return value of vm_executable_path() should be free'd<commit_after>#include "master.hpp"

namespace factor {

bool factor_arg(const vm_char* str, const vm_char* arg, cell* value) {
  int val;
  if (SSCANF(str, arg, &val) > 0) {
    *value = val;
    return true;
  }
  return false;
}

vm_parameters::vm_parameters() {
  embedded_image = false;
  image_path = NULL;

  datastack_size = 32 * sizeof(cell);
  retainstack_size = 32 * sizeof(cell);

#if defined(FACTOR_PPC)
  callstack_size = 256 * sizeof(cell);
#else
  callstack_size = 128 * sizeof(cell);
#endif

  code_size = 64;
  young_size = sizeof(cell) / 4;
  aging_size = sizeof(cell) / 2;
  tenured_size = 24 * sizeof(cell);

  max_pic_size = 3;

  fep = false;
  signals = true;

#ifdef WINDOWS
  console = GetConsoleWindow() != NULL;
#else
  console = true;
#endif

  callback_size = 256;
}

void vm_parameters::init_from_args(int argc, vm_char** argv) {
  executable_path = argv[0];

  int i = 0;

  for (i = 1; i < argc; i++) {
    vm_char* arg = argv[i];
    if (STRCMP(arg, STRING_LITERAL("--")) == 0)
      break;
    else if (factor_arg(arg, STRING_LITERAL("-datastack=%d"),
                        &datastack_size))
      ;
    else if (factor_arg(arg, STRING_LITERAL("-retainstack=%d"),
                        &retainstack_size))
      ;
    else if (factor_arg(arg, STRING_LITERAL("-callstack=%d"),
                        &callstack_size))
      ;
    else if (factor_arg(arg, STRING_LITERAL("-young=%d"), &young_size))
      ;
    else if (factor_arg(arg, STRING_LITERAL("-aging=%d"), &aging_size))
      ;
    else if (factor_arg(arg, STRING_LITERAL("-tenured=%d"), &tenured_size))
      ;
    else if (factor_arg(arg, STRING_LITERAL("-codeheap=%d"), &code_size))
      ;
    else if (factor_arg(arg, STRING_LITERAL("-pic=%d"), &max_pic_size))
      ;
    else if (factor_arg(arg, STRING_LITERAL("-callbacks=%d"), &callback_size))
      ;
    else if (STRNCMP(arg, STRING_LITERAL("-i="), 3) == 0)
      image_path = arg + 3;
    else if (STRCMP(arg, STRING_LITERAL("-fep")) == 0)
      fep = true;
    else if (STRCMP(arg, STRING_LITERAL("-nosignals")) == 0)
      signals = false;
    else if (STRCMP(arg, STRING_LITERAL("-console")) == 0)
      console = true;
  }
}

void factor_vm::load_data_heap(FILE* file, image_header* h, vm_parameters* p) {
  p->tenured_size = std::max((h->data_size * 3) / 2, p->tenured_size);

  init_data_heap(p->young_size, p->aging_size, p->tenured_size);

  fixnum bytes_read =
      raw_fread((void*)data->tenured->start, 1, h->data_size, file);

  if ((cell)bytes_read != h->data_size) {
    std::cout << "truncated image: " << bytes_read << " bytes read, ";
    std::cout << h->data_size << " bytes expected\n";
    fatal_error("load_data_heap failed", 0);
  }

  data->tenured->initial_free_list(h->data_size);
}

void factor_vm::load_code_heap(FILE* file, image_header* h, vm_parameters* p) {
  if (h->code_size > p->code_size)
    fatal_error("Code heap too small to fit image", h->code_size);

  code = new code_heap(p->code_size);

  if (h->code_size != 0) {
    size_t bytes_read =
        raw_fread((void*)code->allocator->start, 1, h->code_size, file);
    if (bytes_read != h->code_size) {
      std::cout << "truncated image: " << bytes_read << " bytes read, ";
      std::cout << h->code_size << " bytes expected\n";
      fatal_error("load_code_heap failed", 0);
    }
  }

  code->allocator->initial_free_list(h->code_size);
  code->initialize_all_blocks_set();
}

struct startup_fixup {
  static const bool translated_code_block_map = true;

  cell data_offset;
  cell code_offset;

  startup_fixup(cell data_offset, cell code_offset)
      : data_offset(data_offset), code_offset(code_offset) {}

  object* fixup_data(object* obj) {
    return (object*)((cell)obj + data_offset);
  }

  code_block* fixup_code(code_block* obj) {
    return (code_block*)((cell)obj + code_offset);
  }

  object* translate_data(const object* obj) { return fixup_data((object*)obj); }

  code_block* translate_code(const code_block* compiled) {
    return fixup_code((code_block*)compiled);
  }

  cell size(const object* obj) { return obj->size(*this); }

  cell size(code_block* compiled) { return compiled->size(*this); }
};

void factor_vm::fixup_heaps(cell data_offset, cell code_offset) {
  startup_fixup fixup(data_offset, code_offset);
  slot_visitor<startup_fixup> visitor(this, fixup);
  visitor.visit_all_roots();

  auto start_object_updater = [&](object *obj, cell size) {
    data->tenured->starts.record_object_start_offset(obj);
    visitor.visit_slots(obj);
    switch (obj->type()) {
      case ALIEN_TYPE: {
        alien* ptr = (alien*)obj;
        if (to_boolean(ptr->base))
          ptr->update_address();
        else
          ptr->expired = special_objects[OBJ_CANONICAL_TRUE];
        break;
      }
      case DLL_TYPE: {
        ffi_dlopen((dll*)obj);
        break;
      }
      default: {
        visitor.visit_object_code_block(obj);
        break;
      }
    }
  };
  data->tenured->iterate(start_object_updater, fixup);

  auto updater = [&](code_block* compiled, cell size) {
    visitor.visit_code_block_objects(compiled);
    cell rel_base = compiled->entry_point() - fixup.code_offset;
    visitor.visit_instruction_operands(compiled, rel_base);
  };
  code->allocator->iterate(updater, fixup);
}

bool factor_vm::read_embedded_image_footer(FILE* file,
                                           embedded_image_footer* footer) {
  safe_fseek(file, -(off_t)sizeof(embedded_image_footer), SEEK_END);
  safe_fread(footer, (off_t)sizeof(embedded_image_footer), 1, file);
  return footer->magic == image_magic;
}

char *threadsafe_strerror(int errnum) {
  char *buf = (char *) malloc(STRERROR_BUFFER_SIZE);
  if(!buf) {
    fatal_error("Out of memory in threadsafe_strerror, errno", errnum);
  }
  THREADSAFE_STRERROR(errnum, buf, STRERROR_BUFFER_SIZE);
  return buf;
}

FILE* factor_vm::open_image(vm_parameters* p) {
  if (!p->embedded_image)
    return OPEN_READ(p->image_path);

  FILE* file = OPEN_READ(p->executable_path);
  if (file == NULL) {
    std::cout << "Cannot open embedded image" << std::endl;
    char *msg = threadsafe_strerror(errno);
    std::cout << "strerror:1: " << msg << std::endl;
    free(msg);
    exit(1);
  }
  embedded_image_footer footer;
  if (!read_embedded_image_footer(file, &footer)) {
    std::cout << "No embedded image" << std::endl;
    exit(1);
  }
  safe_fseek(file, (off_t)footer.image_offset, SEEK_SET);
  return file;
}

/* Read an image file from disk, only done once during startup */
/* This function also initializes the data and code heaps */
void factor_vm::load_image(vm_parameters* p) {
  FILE* file = open_image(p);
  if (file == NULL) {
    std::cout << "Cannot open image file: " << p->image_path << std::endl;
    char *msg = threadsafe_strerror(errno);
    std::cout << "strerror:2: " << msg << std::endl;
    free(msg);
    exit(1);
  }
  image_header h;
  if (raw_fread(&h, sizeof(image_header), 1, file) != 1)
    fatal_error("Cannot read image header", 0);

  if (h.magic != image_magic)
    fatal_error("Bad image: magic number check failed", h.magic);

  if (h.version != image_version)
    fatal_error("Bad image: version number check failed", h.version);

  load_data_heap(file, &h, p);
  load_code_heap(file, &h, p);

  raw_fclose(file);

  /* Certain special objects in the image are known to the runtime */
  memcpy(special_objects, h.special_objects, sizeof(special_objects));

  cell data_offset = data->tenured->start - h.data_relocation_base;
  cell code_offset = code->allocator->start - h.code_relocation_base;
  fixup_heaps(data_offset, code_offset);

  /* Store image path name */
  special_objects[OBJ_IMAGE] = allot_alien(false_object, (cell)p->image_path);
}

/* Save the current image to disk. We don't throw any exceptions here
   because if the 'then-die' argument is t it is not safe to do
   so. Instead we signal failure by returning false. */
bool factor_vm::save_image(const vm_char* saving_filename,
                           const vm_char* filename) {
  image_header h;

  h.magic = image_magic;
  h.version = image_version;
  h.data_relocation_base = data->tenured->start;
  h.data_size = data->tenured->occupied_space();
  h.code_relocation_base = code->allocator->start;
  h.code_size = code->allocator->occupied_space();

  for (cell i = 0; i < special_object_count; i++)
    h.special_objects[i] =
        (save_special_p(i) ? special_objects[i] : false_object);

  FILE* file = OPEN_WRITE(saving_filename);
  if (file == NULL)
    return false;
  if (safe_fwrite(&h, sizeof(image_header), 1, file) != 1)
    return false;
  if (h.data_size > 0 &&
      safe_fwrite((void*)data->tenured->start, h.data_size, 1, file) != 1)
    return false;
  if (h.code_size > 0 &&
      safe_fwrite((void*)code->allocator->start, h.code_size, 1, file) != 1)
    return false;
  if (raw_fclose(file) == -1)
    return false;
  if (!move_file(saving_filename, filename))
    return false;
  return true;
}

/* Allocates memory */
void factor_vm::primitive_save_image() {
  /* We unbox this before doing anything else. This is the only point
     where we might throw an error, so we have to throw an error here since
     later steps destroy the current image. */
  bool then_die = to_boolean(ctx->pop());
  byte_array* path2 = untag_check<byte_array>(ctx->pop());
  byte_array* path1 = untag_check<byte_array>(ctx->pop());

  /* Copy the paths to non-gc memory to avoid them hanging around in
     the saved image. */
  vm_char* path1_saved = safe_strdup(path1->data<vm_char>());
  vm_char* path2_saved = safe_strdup(path2->data<vm_char>());

  if (then_die) {
    /* strip out special_objects data which is set on startup anyway */
    for (cell i = 0; i < special_object_count; i++)
      if (!save_special_p(i))
        special_objects[i] = false_object;

    /* dont trace objects only reachable from context stacks so we don't
       get volatile data saved in the image. */
    active_contexts.clear();
    code->uninitialized_blocks.clear();

    /* I think clearing the callback heap should be fine too. */
    callbacks->allocator->initial_free_list(0);
  }

  /* do a full GC to push everything remaining into tenured space */
  primitive_compact_gc();

  /* Save the image */
  bool ret = save_image(path1_saved, path2_saved);
  if (then_die) {
    exit(ret ? 0 : 1);
  }
  free(path1_saved);
  free(path2_saved);

  if (!ret) {
    general_error(ERROR_IO, tag_fixnum(errno), false_object);
  }
}

bool factor_vm::embedded_image_p() {
  const vm_char* vm_path = vm_executable_path();
  FILE* file = OPEN_READ(vm_path);
  if (!file) {
    free((vm_char *)vm_path);
    return false;
  }
  embedded_image_footer footer;
  bool embedded_p = read_embedded_image_footer(file, &footer);
  fclose(file);
  free((vm_char *)vm_path);
  return embedded_p;
}

}
<|endoftext|>