<commit_before>#include <RESTClient/base/url.hpp>
#include <RESTClient/base/logger.hpp>

#include <boost/config/warning_disable.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/fusion/include/io.hpp>
#include <boost/fusion/include/std_pair.hpp>
#include <boost/optional/optional.hpp>
#include <boost/spirit/home/x3.hpp>

#include <string>
#include <cassert>

using namespace std;
using namespace RESTClient;

#define EQ(a, b)                                                               \
  if (a != b) {                                                                \
    LOG_ERROR("Expected a == b, but it doesn't. a: "                           \
              << a << " - b: " << b << " - Line: " << __LINE__ << " - File: "  \
              << __FILE__ << " - Function: " << __FUNCTION__ << std::endl);    \
  }

template <typename T>
void test(const std::string &label, const T &parser) {
  auto begin = label.cbegin();
  auto end = label.cend();
  std::string out;
  bool worked =
      x3::phrase_parse(begin, end, x3::lexeme[parser], x3::space, out);
  assert(worked);
  if (begin != end) {
    std::string compare_to;
    std::copy(label.cbegin(), begin, std::back_inserter(compare_to));
    std::stringstream msg;
    msg << "Failed to do a full parse: " << std::endl << "Label: " << label
        << std::endl << "copyd: " << compare_to << std::endl;
    throw runtime_error(msg.str());
  }
  EQ(out, label);
}

void testDomainLabel(const std::string& label) {
  LOG_INFO("Testing domainlabel with " << label);
  test(label, domainlabel);
  // Test a bad label
  std::string bad = label + ".com";
  LOG_INFO("Testing domainlabel with " << bad);
  std::string out;
  auto begin = bad.cbegin();
  auto end = bad.cend();
  bool worked =
      x3::phrase_parse(begin, end, x3::lexeme[domainlabel], x3::space, out);
  assert(worked);
  assert(begin != end);
}

void testTopLabel(const std::string& label) {
  LOG_INFO("Test top label: " << label);
  test(label, toplabel);
}

void testHostName(const std::string& label) {
  LOG_INFO("Test Hostname: " << label);
  test(label, hostname);
}

void testQueryWord(const std::string& label) {
  LOG_INFO("Test Query word: " << label);
  test(label, query_word);
}

void testQueryPair(const std::string& label) {
  LOG_INFO("Test Query pair: " << label);
  std::pair<std::string, std::string> query_pair_out;
  x3::phrase_parse(label.begin(), label.end(), query_pair, x3::space, query_pair_out);
  std::pair<std::string, std::string> out;
  auto begin = label.cbegin();
  auto end = label.cend();
  bool worked =
      x3::phrase_parse(begin, end, x3::lexeme[query_pair], x3::space, out);
  assert(worked);
  if (begin != end) {
    std::string compare_to;
    std::copy(label.cbegin(), begin, std::back_inserter(compare_to));
    std::stringstream msg;
    msg << "Failed to do a full parse: " << std::endl << "Label: " << label
        << std::endl << "copyd: " << compare_to << std::endl;
    throw runtime_error(msg.str());
  }
}

void testHostPort(const std::string &label, const std::string &firstPart,
                  boost::optional<unsigned short> portToTest = {}) {
  LOG_INFO("Test hostport: " << label);
  auto begin = label.cbegin();
  auto end = label.cend();
  std::pair<std::string, boost::optional<unsigned short>> out;
  bool worked =
      x3::phrase_parse(begin, end, x3::lexeme[hostport], x3::space, out);
  assert(worked);
  if (begin != end) {
    std::string compare_to;
    std::copy(label.cbegin(), begin, std::back_inserter(compare_to));
    std::stringstream msg;
    msg << "Failed to do a full parse: " << std::endl << "Label: " << label
        << std::endl << "copyd: " << compare_to << std::endl;
    throw runtime_error(msg.str());
  }
  EQ(out.first, firstPart);
  EQ(out.second, portToTest);
}

void testUser(const std::string label) {
  LOG_INFO("Test User: " << label);
  test(label, user_string);
}

void testUserPass(const std::string &label, const std::string &username,
                  const std::string &password = "") {
  LOG_INFO("Test username and password: " << label);
  auto begin = label.cbegin();
  auto end = label.cend();
  std::pair<std::string, std::string> out;
  bool worked =
      x3::phrase_parse(begin, end, x3::lexeme[userpass], x3::space, out);
  assert(worked);
  if (begin != end) {
    std::string compare_to;
    std::copy(label.cbegin(), begin, std::back_inserter(compare_to));
    std::stringstream msg;
    msg << "Failed to do a full parse: " << std::endl << "label: " << label
        << std::endl << "copyd: " << compare_to << std::endl;
    throw runtime_error(msg.str());
  }
  EQ(out.first, username);
  if (password.empty())
    assert(out.second.empty());
  else
    EQ(out.second, password);
}

/*
void testLogin(const std::string &url, const std::string &username,
               const std::string &password, const std::string &hostname,
               boost::optional<unsigned short> portToTest = {}) {
  LOG_INFO("Test username and password: " << url);
  auto begin = url.cbegin();
  auto end = url.cend();
  std::tuple<std::string, std::string, std::string,
             boost::optional<unsigned short>> out;
  bool worked =
      x3::phrase_parse(begin, end, x3::lexeme[login], x3::space, out);
  assert(worked);
  if (begin != end) {
    std::string compare_to;
    std::copy(url.cbegin(), begin, std::back_inserter(compare_to));
    std::stringstream msg;
    msg << "Failed to do a full parse: " << std::endl << "url: " << url
        << std::endl << "copyd: " << compare_to << std::endl;
    throw runtime_error(msg.str());
  }
  //EQ(std::get<0>(out), username);
  //EQ(std::get<1>(out), password);
  //EQ(std::get<2>(out).first, hostname);
  //EQ(std::get<2>(out).second, portToTest);
}
*/

int main(int , char**)
{
  testDomainLabel("somewhere");
  testDomainLabel("s");
  testDomainLabel("s-w");

  testTopLabel("com");

  testHostName("some.host.com");
  testHostName("somewhere");
  testHostName("other-host.com");

  testHostPort("other-host.com", "other-host.com");
  testHostPort("somewhere:8080", "somewhere", 8080);
  testHostPort("somewhere.com:8000", "somewhere.com", 8000);
  testHostPort("123.100.200.300:65000", "123.100.200.300", 65000);

  testUser("mister");
  testUser(";?&=mister");
  testUserPass("mister", "mister", {});
  testUserPass("Doctor:who", "Doctor", "who");

  //testLogin("mister@somewhere.co.uk", "mister", "", "somewhere.co.uk");

  testQueryWord("abc");
  testQueryPair("abc=123");

  std::string query("?a=1&b=2");
  QueryParameters params;
  x3::phrase_parse(query.begin(), query.end(), query_def, x3::space, params);
  EQ(params.size(), 2);
  EQ(params.at("a"), "1");
  EQ(params.at("b"), "2");

  URL test1("http://somewhere.com");
  LOG_INFO("Test 1: " << test1);
  EQ(test1.parts().protocol, "http");
  EQ(test1.parts().hostname, "somewhere.com");
  LOG_INFO("URL Test 1 - PASSED");

  URL test2("https://somewhere.com/some/path/");
  LOG_INFO("URL Test 2: " << test2);
  using namespace std;
  cout << "Protocol: " << test2.parts().protocol << endl
       << "Hostname: " << test2.parts().hostname << endl;
  EQ(test2.parts().protocol, "https");
  EQ(test2.parts().hostname, "somewhere.com");
  EQ(test2.parts().path, "/some/path/");
  LOG_INFO("Test 2 - PASSED");

  URL megaTest1("https://doctor:who@somewhere.com:9000/some/path?flying=true&time=travel");
  LOG_INFO("Mega Test 1: " << megaTest1);
  EQ(megaTest1.parts().protocol, "https");
  EQ(megaTest1.parts().username, "doctor");
  EQ(megaTest1.parts().password, "who");
  EQ(megaTest1.parts().hostname, "somewhere.com");
  EQ(megaTest1.parts().port(), 9000);
  EQ(megaTest1.parts().path, "/some/path");
  EQ(megaTest1.parts().queryParameters.size(), 2);
  EQ(megaTest1.parts().queryParameters.at("flying"), "true");
  EQ(megaTest1.parts().queryParameters.at("time"), "travel");

  LOG_INFO("Mega Test 1 - PASSED");
  return 0;
}
<commit_msg>Added a new URL test<commit_after>#include <RESTClient/base/url.hpp>
#include <RESTClient/base/logger.hpp>

#include <boost/config/warning_disable.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/fusion/include/io.hpp>
#include <boost/fusion/include/std_pair.hpp>
#include <boost/optional/optional.hpp>
#include <boost/spirit/home/x3.hpp>

#include <string>
#include <cassert>

using namespace std;
using namespace RESTClient;

#define EQ(a, b)                                                               \
  if (a != b) {                                                                \
    LOG_ERROR("Expected a == b, but it doesn't. a: "                           \
              << a << " - b: " << b << " - Line: " << __LINE__ << " - File: "  \
              << __FILE__ << " - Function: " << __FUNCTION__ << std::endl);    \
  }

template <typename T>
void test(const std::string &label, const T &parser) {
  auto begin = label.cbegin();
  auto end = label.cend();
  std::string out;
  bool worked =
      x3::phrase_parse(begin, end, x3::lexeme[parser], x3::space, out);
  assert(worked);
  if (begin != end) {
    std::string compare_to;
    std::copy(label.cbegin(), begin, std::back_inserter(compare_to));
    std::stringstream msg;
    msg << "Failed to do a full parse: " << std::endl << "Label: " << label
        << std::endl << "copyd: " << compare_to << std::endl;
    throw runtime_error(msg.str());
  }
  EQ(out, label);
}

void testDomainLabel(const std::string& label) {
  LOG_INFO("Testing domainlabel with " << label);
  test(label, domainlabel);
  // Test a bad label
  std::string bad = label + ".com";
  LOG_INFO("Testing domainlabel with " << bad);
  std::string out;
  auto begin = bad.cbegin();
  auto end = bad.cend();
  bool worked =
      x3::phrase_parse(begin, end, x3::lexeme[domainlabel], x3::space, out);
  assert(worked);
  assert(begin != end);
}

void testTopLabel(const std::string& label) {
  LOG_INFO("Test top label: " << label);
  test(label, toplabel);
}

void testHostName(const std::string& label) {
  LOG_INFO("Test Hostname: " << label);
  test(label, hostname);
}

void testQueryWord(const std::string& label) {
  LOG_INFO("Test Query word: " << label);
  test(label, query_word);
}

void testQueryPair(const std::string& label) {
  LOG_INFO("Test Query pair: " << label);
  std::pair<std::string, std::string> query_pair_out;
  x3::phrase_parse(label.begin(), label.end(), query_pair, x3::space, query_pair_out);
  std::pair<std::string, std::string> out;
  auto begin = label.cbegin();
  auto end = label.cend();
  bool worked =
      x3::phrase_parse(begin, end, x3::lexeme[query_pair], x3::space, out);
  assert(worked);
  if (begin != end) {
    std::string compare_to;
    std::copy(label.cbegin(), begin, std::back_inserter(compare_to));
    std::stringstream msg;
    msg << "Failed to do a full parse: " << std::endl << "Label: " << label
        << std::endl << "copyd: " << compare_to << std::endl;
    throw runtime_error(msg.str());
  }
}

void testHostPort(const std::string &label, const std::string &firstPart,
                  boost::optional<unsigned short> portToTest = {}) {
  LOG_INFO("Test hostport: " << label);
  auto begin = label.cbegin();
  auto end = label.cend();
  std::pair<std::string, boost::optional<unsigned short>> out;
  bool worked =
      x3::phrase_parse(begin, end, x3::lexeme[hostport], x3::space, out);
  assert(worked);
  if (begin != end) {
    std::string compare_to;
    std::copy(label.cbegin(), begin, std::back_inserter(compare_to));
    std::stringstream msg;
    msg << "Failed to do a full parse: " << std::endl << "Label: " << label
        << std::endl << "copyd: " << compare_to << std::endl;
    throw runtime_error(msg.str());
  }
  EQ(out.first, firstPart);
  EQ(out.second, portToTest);
}

void testUser(const std::string label) {
  LOG_INFO("Test User: " << label);
  test(label, user_string);
}

void testUserPass(const std::string &label, const std::string &username,
                  const std::string &password = "") {
  LOG_INFO("Test username and password: " << label);
  auto begin = label.cbegin();
  auto end = label.cend();
  std::pair<std::string, std::string> out;
  bool worked =
      x3::phrase_parse(begin, end, x3::lexeme[userpass], x3::space, out);
  assert(worked);
  if (begin != end) {
    std::string compare_to;
    std::copy(label.cbegin(), begin, std::back_inserter(compare_to));
    std::stringstream msg;
    msg << "Failed to do a full parse: " << std::endl << "label: " << label
        << std::endl << "copyd: " << compare_to << std::endl;
    throw runtime_error(msg.str());
  }
  EQ(out.first, username);
  if (password.empty())
    assert(out.second.empty());
  else
    EQ(out.second, password);
}

/*
void testLogin(const std::string &url, const std::string &username,
               const std::string &password, const std::string &hostname,
               boost::optional<unsigned short> portToTest = {}) {
  LOG_INFO("Test username and password: " << url);
  auto begin = url.cbegin();
  auto end = url.cend();
  std::tuple<std::string, std::string, std::string,
             boost::optional<unsigned short>> out;
  bool worked =
      x3::phrase_parse(begin, end, x3::lexeme[login], x3::space, out);
  assert(worked);
  if (begin != end) {
    std::string compare_to;
    std::copy(url.cbegin(), begin, std::back_inserter(compare_to));
    std::stringstream msg;
    msg << "Failed to do a full parse: " << std::endl << "url: " << url
        << std::endl << "copyd: " << compare_to << std::endl;
    throw runtime_error(msg.str());
  }
  //EQ(std::get<0>(out), username);
  //EQ(std::get<1>(out), password);
  //EQ(std::get<2>(out).first, hostname);
  //EQ(std::get<2>(out).second, portToTest);
}
*/

int main(int , char**)
{
  testDomainLabel("somewhere");
  testDomainLabel("s");
  testDomainLabel("s-w");

  testTopLabel("com");

  testHostName("some.host.com");
  testHostName("somewhere");
  testHostName("other-host.com");

  testHostPort("other-host.com", "other-host.com");
  testHostPort("somewhere:8080", "somewhere", 8080);
  testHostPort("somewhere.com:8000", "somewhere.com", 8000);
  testHostPort("123.100.200.300:65000", "123.100.200.300", 65000);

  testUser("mister");
  testUser(";?&=mister");
  testUserPass("mister", "mister", {});
  testUserPass("Doctor:who", "Doctor", "who");

  //testLogin("mister@somewhere.co.uk", "mister", "", "somewhere.co.uk");

  testQueryWord("abc");
  testQueryPair("abc=123");

  std::string query("?a=1&b=2");
  QueryParameters params;
  x3::phrase_parse(query.begin(), query.end(), query_def, x3::space, params);
  EQ(params.size(), 2);
  EQ(params.at("a"), "1");
  EQ(params.at("b"), "2");

  URL test1("http://somewhere.com");
  LOG_INFO("Test 1: " << test1);
  EQ(test1.parts().protocol, "http");
  EQ(test1.parts().hostname, "somewhere.com");
  LOG_INFO("URL Test 1 - PASSED");

  URL test2("https://somewhere.com/some/path/");
  LOG_INFO("URL Test 2: " << test2);
  using namespace std;
  cout << "Protocol: " << test2.parts().protocol << endl
       << "Hostname: " << test2.parts().hostname << endl;
  EQ(test2.parts().protocol, "https");
  EQ(test2.parts().hostname, "somewhere.com");
  EQ(test2.parts().path, "/some/path/");
  LOG_INFO("Test 2 - PASSED");

  URL megaTest1("https://doctor:who@somewhere.com:9000/some/path?flying=true&time=travel");
  LOG_INFO("Mega Test 1: " << megaTest1);
  EQ(megaTest1.parts().protocol, "https");
  EQ(megaTest1.parts().username, "doctor");
  EQ(megaTest1.parts().password, "who");
  EQ(megaTest1.parts().hostname, "somewhere.com");
  EQ(megaTest1.parts().port(), 9000);
  EQ(megaTest1.parts().path, "/some/path");
  EQ(megaTest1.parts().queryParameters.size(), 2);
  EQ(megaTest1.parts().queryParameters.at("flying"), "true");
  EQ(megaTest1.parts().queryParameters.at("time"), "travel");

  URL megaTest2("https://doctor@somewhere.com:9000/some/path?");
  LOG_INFO("Mega Test 2: " << megaTest2);
  EQ(megaTest2.parts().protocol, "https");
  EQ(megaTest2.parts().username, "doctor");
  EQ(megaTest2.parts().password, "");
  EQ(megaTest2.parts().hostname, "somewhere.com");
  EQ(megaTest2.parts().port(), 9000);
  EQ(megaTest2.parts().path, "/some/path");
  EQ(megaTest2.parts().queryParameters.size(), 0);

  LOG_INFO("Mega Test 2 - PASSED");
  return 0;
}
<|endoftext|>


<commit_before>#include "Play.hpp"

#include <functional>

#include "../../ResourceManager/AssetManager.hpp"

/* GUI headers */
#include "../../GUI/Containers/Column.hpp"
#include "../../GUI/Containers/Row.hpp"
#include "../../GUI/Widgets/Label.hpp"
#include "../../GUI/Widgets/Button.hpp"
#include "../../GUI/Widgets/Spacer.hpp"

namespace swift
{
	Play::Play(sf::RenderWindow& win, AssetManager& am)
		:	State(win, am),
		    state(SubState::Play),
			world({static_cast<int>(window.getSize().x), static_cast<int>(window.getSize().y)}, assets)
	{
		returnType = State::Type::Play;
	}

	Play::~Play()
	{
		player = nullptr;
	}

	void Play::setup()
	{
		window.setKeyRepeatEnabled(false);
		Script* playSetup = &assets.getScript("./data/scripts/play.lua");
		Script* pauseSetup = &assets.getScript("./data/scripts/pause.lua");

		if(playSetup == nullptr)
			std::cerr << "Play script isn't being loaded\n";
		if(pauseSetup == nullptr)
			std::cerr << "Pause script isn't being loaded\n";

		playSetup->setGUI(hud);
		playSetup->setStateReturn(returnType);
		playSetup->setKeyboard(keyboard);
		playSetup->setWorld(world);
		playSetup->start();

		pauseSetup->setGUI(pauseMenu);
		pauseSetup->setStateReturn(returnType);
		pauseSetup->setKeyboard(keyboard);
		pauseSetup->start();

		setupKeyBindings();

		// setup pause menu GUI
		cstr::Column& pauseColumn = pauseMenu.addContainer(new cstr::Column({static_cast<int>(window.getSize().x) / 2 - 50, static_cast<int>(window.getSize().y / 2) - 50, 100, 125}, false));
		pauseColumn.addWidget(new cstr::Button({100, 50}, assets.getTexture("./data/textures/button.png"), [&]()
		{
			state = SubState::Play;
		})).setString("Resume", assets.getFont("./data/fonts/segoeuisl.ttf"));

		pauseColumn.addWidget(new cstr::Spacer({100, 25}));

		pauseColumn.addWidget(new cstr::Button({100, 50}, assets.getTexture("./data/textures/button.png"), [&]()
		{
			returnType = State::Type::MainMenu;
		})).setString("Main Menu", assets.getFont("./data/fonts/segoeuisl.ttf"));

		// World test code
		world.load("");
		bool result = world.tilemap.loadFile("./data/maps/maze.map");

		if(!result)
			log << "Loading \'./data/maps/maze.map\' failed\n";

		result = world.tilemap.load(assets.getTexture(world.tilemap.getTextureFile()));

		if(!result)
			std::cout << "Setting up vertices for \'./data/maps/maze.map\' failed\n";

		player = &world.getEntities()[0];
	}

	void Play::handleEvent(sf::Event& event)
	{
		switch(state)
		{
			case SubState::Play:
				hud.update(event);
				break;
			case SubState::Pause:
				pauseMenu.update(event);
				break;
			default:
				break;
		}

		keyboard(event);
		mouse(event);
	}

	void Play::update(sf::Time dt)
	{
		Script* playLogic = &assets.getScript("./data/scripts/play.lua");
		Script* pauseLogic = &assets.getScript("./data/scripts/pause.lua");

		switch(state)
		{
			case SubState::Play:
				world.update(dt.asSeconds());
				playLogic->run();
				break;
			case SubState::Pause:
				pauseLogic->run();
				break;
		}
	}

	void Play::draw(float /*e*/)
	{
		switch(state)
		{
			case SubState::Play:
				world.draw(window);
				window.draw(hud);
				break;
			case SubState::Pause:
				window.draw(pauseMenu);
				break;
			default:
				break;
		}
	}

	bool Play::switchFrom()
	{
		return returnType != State::Type::Play;
	}

	State::Type Play::finish()
	{
		world.save("");
		return returnType;
	}

	void Play::setupKeyBindings()
	{
		keyboard.newBinding("PauseMenu", sf::Keyboard::Escape, [&]()
		{
			state = (state == SubState::Pause) ? SubState::Play : SubState::Pause;
		}, false);

		// move up press and release
		keyboard.newBinding("moveUpStart", sf::Keyboard::Up, [&]()
		{
			player->get<Movable>()->velocity += {0, -player->get<Movable>()->moveVelocity};
		}, true);

		keyboard.newBinding("moveUpStop", sf::Keyboard::Up, [&]()
		{
			player->get<Movable>()->velocity += {0, player->get<Movable>()->moveVelocity};
		}, false);

		// move down press and release
		keyboard.newBinding("moveDownStart", sf::Keyboard::Down, [&]()
		{
			player->get<Movable>()->velocity += {0, player->get<Movable>()->moveVelocity};
		}, true);

		keyboard.newBinding("moveDownStop", sf::Keyboard::Down, [&]()
		{
			player->get<Movable>()->velocity += {0, -player->get<Movable>()->moveVelocity};
		}, false);

		// move left press and release
		keyboard.newBinding("moveLeftStart", sf::Keyboard::Left, [&]()
		{
			player->get<Movable>()->velocity += {-player->get<Movable>()->moveVelocity, 0};
		}, true);

		keyboard.newBinding("moveLeftStop", sf::Keyboard::Left, [&]()
		{
			player->get<Movable>()->velocity += {player->get<Movable>()->moveVelocity, 0};
		}, false);

		// move right press and release
		keyboard.newBinding("moveRightStart", sf::Keyboard::Right, [&]()
		{
			player->get<Movable>()->velocity += {player->get<Movable>()->moveVelocity, 0};
		}, true);

		keyboard.newBinding("moveRightStop", sf::Keyboard::Right, [&]()
		{
			player->get<Movable>()->velocity += {-player->get<Movable>()->moveVelocity, 0};
		}, false);
	}
}
<commit_msg>Removed extra entity creation for testing.<commit_after>#include "Play.hpp"

#include <functional>

#include "../../ResourceManager/AssetManager.hpp"

/* GUI headers */
#include "../../GUI/Containers/Column.hpp"
#include "../../GUI/Containers/Row.hpp"
#include "../../GUI/Widgets/Label.hpp"
#include "../../GUI/Widgets/Button.hpp"
#include "../../GUI/Widgets/Spacer.hpp"

namespace swift
{
	Play::Play(sf::RenderWindow& win, AssetManager& am)
		:	State(win, am),
		    state(SubState::Play),
			world({static_cast<int>(window.getSize().x), static_cast<int>(window.getSize().y)}, assets),
			player(nullptr)
	{
		returnType = State::Type::Play;
	}

	Play::~Play()
	{
		//player = nullptr;
	}

	void Play::setup()
	{
		window.setKeyRepeatEnabled(false);
		Script* playSetup = &assets.getScript("./data/scripts/play.lua");
		Script* pauseSetup = &assets.getScript("./data/scripts/pause.lua");

		if(playSetup == nullptr)
			std::cerr << "Play script isn't being loaded\n";
		if(pauseSetup == nullptr)
			std::cerr << "Pause script isn't being loaded\n";

		playSetup->setGUI(hud);
		playSetup->setStateReturn(returnType);
		playSetup->setKeyboard(keyboard);
		playSetup->setWorld(world);
		playSetup->start();

		pauseSetup->setGUI(pauseMenu);
		pauseSetup->setStateReturn(returnType);
		pauseSetup->setKeyboard(keyboard);
		pauseSetup->start();

		setupKeyBindings();

		// setup pause menu GUI
		cstr::Column& pauseColumn = pauseMenu.addContainer(new cstr::Column({static_cast<int>(window.getSize().x) / 2 - 50, static_cast<int>(window.getSize().y / 2) - 50, 100, 125}, false));
		pauseColumn.addWidget(new cstr::Button({100, 50}, assets.getTexture("./data/textures/button.png"), [&]()
		{
			state = SubState::Play;
		})).setString("Resume", assets.getFont("./data/fonts/segoeuisl.ttf"));

		pauseColumn.addWidget(new cstr::Spacer({100, 25}));

		pauseColumn.addWidget(new cstr::Button({100, 50}, assets.getTexture("./data/textures/button.png"), [&]()
		{
			returnType = State::Type::MainMenu;
		})).setString("Main Menu", assets.getFont("./data/fonts/segoeuisl.ttf"));

		// World test code
		world.load("");
		bool result = world.tilemap.loadFile("./data/maps/maze.map");

		if(!result)
			log << "Loading \'./data/maps/maze.map\' failed\n";

		result = world.tilemap.load(assets.getTexture(world.tilemap.getTextureFile()));

		if(!result)
			std::cout << "Setting up vertices for \'./data/maps/maze.map\' failed\n";

		// setup player
		player = world.addEntity();
		player->add<Drawable>();
		player->add<Physical>();
		player->add<Name>();
		player->get<Name>()->name = "player";
		player->add<Movable>();

		player->get<Drawable>()->sprite.setTexture(assets.getTexture("./data/textures/guy.png"));
		player->get<Drawable>()->sprite.setScale({0.5f, (player->get<Drawable>()->sprite.getGlobalBounds().height - 16) / player->get<Drawable>()->sprite.getGlobalBounds().height});

		player->get<Physical>()->position = {400, 300};
		player->get<Physical>()->size = {static_cast<unsigned>(player->get<Drawable>()->sprite.getGlobalBounds().width),
										static_cast<unsigned>(player->get<Drawable>()->sprite.getGlobalBounds().height)};

		player->get<Movable>()->moveVelocity = 100;
	}

	void Play::handleEvent(sf::Event& event)
	{
		switch(state)
		{
			case SubState::Play:
				hud.update(event);
				break;
			case SubState::Pause:
				pauseMenu.update(event);
				break;
			default:
				break;
		}

		keyboard(event);
		mouse(event);
	}

	void Play::update(sf::Time dt)
	{
		Script* playLogic = &assets.getScript("./data/scripts/play.lua");
		Script* pauseLogic = &assets.getScript("./data/scripts/pause.lua");

		switch(state)
		{
			case SubState::Play:
				world.update(dt.asSeconds());
				playLogic->run();
				break;
			case SubState::Pause:
				pauseLogic->run();
				break;
		}
	}

	void Play::draw(float /*e*/)
	{
		switch(state)
		{
			case SubState::Play:
				window.draw(world);
				window.draw(hud);
				break;
			case SubState::Pause:
				window.draw(pauseMenu);
				break;
			default:
				break;
		}
	}

	bool Play::switchFrom()
	{
		return returnType != State::Type::Play;
	}

	State::Type Play::finish()
	{
		world.save("");
		return returnType;
	}

	void Play::setupKeyBindings()
	{
		keyboard.newBinding("PauseMenu", sf::Keyboard::Escape, [&]()
		{
			state = (state == SubState::Pause) ? SubState::Play : SubState::Pause;
		}, false);

		// move up press and release
		keyboard.newBinding("moveUpStart", sf::Keyboard::Up, [&]()
		{
			if(player)
				if(player->has<Movable>())
					player->get<Movable>()->velocity += {0, -player->get<Movable>()->moveVelocity};
		}, true);

		keyboard.newBinding("moveUpStop", sf::Keyboard::Up, [&]()
		{
			if(player)
				if(player->has<Movable>())
					player->get<Movable>()->velocity += {0, player->get<Movable>()->moveVelocity};
		}, false);

		// move down press and release
		keyboard.newBinding("moveDownStart", sf::Keyboard::Down, [&]()
		{
			if(player)
				if(player->has<Movable>())
					player->get<Movable>()->velocity += {0, player->get<Movable>()->moveVelocity};
		}, true);

		keyboard.newBinding("moveDownStop", sf::Keyboard::Down, [&]()
		{
			if(player)
				if(player->has<Movable>())
					player->get<Movable>()->velocity += {0, -player->get<Movable>()->moveVelocity};
		}, false);

		// move left press and release
		keyboard.newBinding("moveLeftStart", sf::Keyboard::Left, [&]()
		{
			if(player)
				if(player->has<Movable>())
					player->get<Movable>()->velocity += {-player->get<Movable>()->moveVelocity, 0};
		}, true);

		keyboard.newBinding("moveLeftStop", sf::Keyboard::Left, [&]()
		{
			if(player)
				if(player->has<Movable>())
					player->get<Movable>()->velocity += {player->get<Movable>()->moveVelocity, 0};
		}, false);

		// move right press and release
		keyboard.newBinding("moveRightStart", sf::Keyboard::Right, [&]()
		{
			if(player)
				if(player->has<Movable>())
					player->get<Movable>()->velocity += {player->get<Movable>()->moveVelocity, 0};
		}, true);

		keyboard.newBinding("moveRightStop", sf::Keyboard::Right, [&]()
		{
			if(player)
				if(player->has<Movable>())
					player->get<Movable>()->velocity += {-player->get<Movable>()->moveVelocity, 0};
		}, false);
	}
}
<|endoftext|>


<commit_before>////////////////////////////////////////////////////////////////////////////////////
// Authors: Mateus Fogaca
//          (Ph.D. advisor: Ricardo Reis)
//          Jiajia Li
//          Andrew Kahng
// Based on:
//          K. Han, A. B. Kahng and J. Li, "Optimal Generalized H-Tree Topology and
//          Buffering for High-Performance and Low-Power Clock Distribution",
//          IEEE Trans. on CAD (2018), doi:10.1109/TCAD.2018.2889756.
//
//
// BSD 3-Clause License
//
// Copyright (c) 2018, The Regents of the University of California
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice, this
//   list of conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above copyright notice,
//   this list of conditions and the following disclaimer in the documentation
//   and/or other materials provided with the distribution.
//
// * Neither the name of the copyright holder nor the names of its
//   contributors may be used to endorse or promote products derived from
//   this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
////////////////////////////////////////////////////////////////////////////////////

#include "DbWrapper.h"
#include "TritonCTSKernel.h"
#include "HTreeBuilder.h"

// DB includes
#include "db.h"
#include "dbShape.h"
#include "dbTypes.h"

#include <iostream>
#include <sstream>

namespace TritonCTS {

DbWrapper::DbWrapper(CtsOptions& options,
                     TritonCTSKernel& kernel) {
        _options  = &options;
        _kernel = &kernel;
}

void DbWrapper::populateTritonCTS() {
       initDB();
       initAllClocks();
}

void DbWrapper::initDB() {
        _db    = odb::dbDatabase::getDatabase(_options->getDbId());
        _chip  = _db->getChip();
        _block = _chip->getBlock();
        _options->setDbUnits(_block->getDbUnitsPerMicron());
}

void DbWrapper::initAllClocks() {
        std::cout << " Initializing clock nets\n";

        std::vector<std::string> clockNetNames;
        parseClockNames(clockNetNames);

        std::cout << " Looking for clock nets in the design\n";
        for (const std::string& name: clockNetNames) {
                odb::dbNet* net = _block->findNet(name.c_str());
                if (!net) {
                        odb::dbITerm* iterm = _block->findITerm(name.c_str());
                        net = iterm->getNet();
                }
                if (!net) {
                        std::cout << " [WARNING] Net \"" << name << "\" not in design. Skipping...\n";
                        continue;
                }

                std::cout << " Net \"" << name << "\" found\n";
                initClock(net);
        }
}

void DbWrapper::initClock(odb::dbNet* net) {
        std::string driver = "";
        odb::dbITerm* iterm = net->getFirstOutput();
        int xPin, yPin;
        if (!iterm) {
                odb::dbBTerm* bterm = net->get1stBTerm(); // Clock pin
                driver = bterm->getConstName();
                bterm->getFirstPinLocation(xPin, yPin);
         } else {
                odb::dbInst* inst = iterm->getInst();
                odb::dbMTerm* mterm = iterm->getMTerm();
                std::string driver = std::string(inst->getConstName()) + "/" +
                                   std::string(mterm->getConstName());
                DBU xTmp, yTmp;
                computeITermPosition(iterm, xTmp, yTmp);
                xPin = xTmp; yPin = yTmp;
        }

        // Initialize clock net
        std::cout << net->getConstName() << std::endl;

        Clock clockNet(net->getConstName(),
                       driver,
                       xPin, yPin);

        odb::dbSet<odb::dbITerm> iterms = net->getITerms();
        odb::dbSet<odb::dbITerm>::iterator itr;
        for (itr = iterms.begin(); itr != iterms.end(); ++itr) {
                odb::dbITerm* iterm = *itr;
                odb::dbInst* inst = iterm->getInst();
                odb::dbMTerm* mterm = iterm->getMTerm();
                std::string name = std::string(inst->getConstName()) + "/" +
                                   std::string(mterm->getConstName());
                DBU x, y;
                computeITermPosition(iterm, x, y);
                clockNet.addSink(name, x, y);
        }

        if (clockNet.getNumSinks() < 2) {
                std::cout << "    [WARNING] Net \"" << clockNet.getName() << "\""
                          << " has " << clockNet.getNumSinks()  << " sinks. Skipping...\n";
                return;

        }

        _kernel->addBuilder(new HTreeBuilder(*_options, clockNet));
}

void DbWrapper::parseClockNames(std::vector<std::string>& clockNetNames) const {
        std::stringstream allNames(_options->getClockNets());

        std::string tmpName = "";
        while (allNames >> tmpName) {
                clockNetNames.push_back(tmpName);
        }

        unsigned numClocks = clockNetNames.size();
        std::cout << " Number of user-input clocks: " << numClocks;

        if (numClocks > 0) {
                std::cout << " (";
                for (const std::string& name: clockNetNames) {
                        std::cout << " \"" << name << "\"";
                }
                std::cout << " )\n";
        } else {
                std::cout << "\n";
                std::cout << " [ERROR] No clock nets have been found.\n";
                std::exit(1);

        }
}

void DbWrapper::computeITermPosition(odb::dbITerm* term, DBU &x, DBU &y) const {
        odb::dbITermShapeItr itr;

        odb::dbShape shape;
        x = 0;
        y = 0;
        unsigned numShapes = 0;
        for (itr.begin(term); itr.next(shape); ) {
                if (shape.isVia()) {
                        continue;
                } else {
                        x += shape.xMin() + (shape.xMax() - shape.xMin()) / 2;
                        y += shape.yMin() + (shape.yMax() - shape.yMin()) / 2;
                        ++numShapes;
                }
        }

        x /= numShapes;
        y /= numShapes;
};

void DbWrapper::writeClockNetsToDb(const Clock& clockNet) {
        std::cout << " Writing clock net \"" << clockNet.getName() << "\" to DB\n";

        disconnectAllSinksFromNet(clockNet.getName());

        createClockBuffers(clockNet);

        // connect top buffer on the clock pin
        odb::dbNet* topClockNet = _block->findNet(clockNet.getName().c_str());
        std::string topClockInstName = "clkbuf_0_" + clockNet.getName();
        odb::dbInst* topClockInst = _block->findInst(topClockInstName.c_str());
        odb::dbITerm* topClockInstInputPin = getFirstInput(topClockInst);
        odb::dbITerm::connect(topClockInstInputPin, topClockNet);
        topClockNet->setSigType(odb::dbSigType::CLOCK);

        // create subNets
        unsigned numClkNets = 0;
        clockNet.forEachSubNet( [&] (const Clock::SubNet& subNet) {
                        //std::cout << "    SubNet: " << subNet.getName() << "\n";
                        odb::dbNet* clkSubNet = odb::dbNet::create(_block, subNet.getName().c_str());
                        ++numClkNets;
                        clkSubNet->setSigType(odb::dbSigType::CLOCK);

                        //std::cout << "      Driver: " << subNet.getDriver()->getName() << "\n";

                        odb::dbInst* driver = _block->findInst(subNet.getDriver()->getName().c_str());
                        odb::dbITerm* outputPin = driver->getFirstOutput();
                        odb::dbITerm::connect(outputPin, clkSubNet);

                        subNet.forEachSink( [&] (ClockInst *inst) {
                                //std::cout << "      " << inst->getName() << "\n";
                                odb::dbITerm* inputPin = nullptr;
                                if (inst->isClockBuffer()) {
                                        odb::dbInst* sink = _block->findInst(inst->getName().c_str());
                                        inputPin = getFirstInput(sink);
                                } else {
                                        inputPin = _block->findITerm(inst->getName().c_str());
                                }
                                odb::dbITerm::connect(inputPin, clkSubNet);
                        });
                });

        if (_options->writeOnlyClockNets()) {
                removeNonClockNets();
        }

        std::cout << "    Created " << numClkNets << " clock nets.\n";
}

void DbWrapper::disconnectAllSinksFromNet(std::string netName) {
        odb::dbNet* net = _block->findNet(netName.c_str());
        odb::dbSet<odb::dbITerm> iterms = net->getITerms();
        odb::dbSet<odb::dbITerm>::iterator itr;
        for (itr = iterms.begin(); itr != iterms.end(); ++itr) {
                odb::dbITerm* iterm = *itr;
                if (iterm->getIoType() != odb::dbIoType::INPUT) {
                        continue;
                }
                odb::dbITerm::disconnect(iterm);
        }
}

void DbWrapper::createClockBuffers(const Clock& clockNet) {
        unsigned numBuffers = 0;
        clockNet.forEachClockBuffer([&] (const ClockInst& inst) {
                odb::dbMaster* master = _db->findMaster(inst.getMaster().c_str());
                odb::dbInst* newInst = odb::dbInst::create(_block, master, inst.getName().c_str());
                newInst->setLocation(inst.getX(), inst.getY());
                newInst->setPlacementStatus(odb::dbPlacementStatus::PLACED);
                ++numBuffers;
        });
        std::cout << "    Created " << numBuffers << " clock buffers.\n";
}

odb::dbITerm* DbWrapper::getFirstInput(odb::dbInst* inst) const {
        odb::dbSet<odb::dbITerm> iterms = inst->getITerms();
        odb::dbSet<odb::dbITerm>::iterator itr;

        for (itr = iterms.begin(); itr != iterms.end(); ++itr) {
                odb::dbITerm* iterm = *itr;
                if (iterm->isInputSignal()) {
                        return iterm;
                }
        }

        return nullptr;
}

bool DbWrapper::masterExists(const std::string& master) const {
        return _db->findMaster(master.c_str());
};

void DbWrapper::removeNonClockNets() {
        for (odb::dbNet* net : _block->getNets()) {
                if (net->getSigType() != odb::dbSigType::CLOCK) {
                        odb::dbNet::destroy(net);
                }
        }
}

}
<commit_msg>[TritonCTS] Fix crash due to cells placed out of code<commit_after>////////////////////////////////////////////////////////////////////////////////////
// Authors: Mateus Fogaca
//          (Ph.D. advisor: Ricardo Reis)
//          Jiajia Li
//          Andrew Kahng
// Based on:
//          K. Han, A. B. Kahng and J. Li, "Optimal Generalized H-Tree Topology and
//          Buffering for High-Performance and Low-Power Clock Distribution",
//          IEEE Trans. on CAD (2018), doi:10.1109/TCAD.2018.2889756.
//
//
// BSD 3-Clause License
//
// Copyright (c) 2018, The Regents of the University of California
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice, this
//   list of conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above copyright notice,
//   this list of conditions and the following disclaimer in the documentation
//   and/or other materials provided with the distribution.
//
// * Neither the name of the copyright holder nor the names of its
//   contributors may be used to endorse or promote products derived from
//   this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
////////////////////////////////////////////////////////////////////////////////////

#include "DbWrapper.h"
#include "TritonCTSKernel.h"
#include "HTreeBuilder.h"

// DB includes
#include "db.h"
#include "dbShape.h"
#include "dbTypes.h"

#include <iostream>
#include <sstream>

namespace TritonCTS {

DbWrapper::DbWrapper(CtsOptions& options,
                     TritonCTSKernel& kernel) {
        _options  = &options;
        _kernel = &kernel;
}

void DbWrapper::populateTritonCTS() {
       initDB();
       initAllClocks();
}

void DbWrapper::initDB() {
        _db    = odb::dbDatabase::getDatabase(_options->getDbId());
        _chip  = _db->getChip();
        _block = _chip->getBlock();
        _options->setDbUnits(_block->getDbUnitsPerMicron());
}

void DbWrapper::initAllClocks() {
        std::cout << " Initializing clock nets\n";

        std::vector<std::string> clockNetNames;
        parseClockNames(clockNetNames);

        std::cout << " Looking for clock nets in the design\n";
        for (const std::string& name: clockNetNames) {
                odb::dbNet* net = _block->findNet(name.c_str());
                if (!net) {
                        odb::dbITerm* iterm = _block->findITerm(name.c_str());
                        net = iterm->getNet();
                }
                if (!net) {
                        std::cout << " [WARNING] Net \"" << name << "\" not in design. Skipping...\n";
                        continue;
                }

                std::cout << " Net \"" << name << "\" found\n";
                initClock(net);
        }
}

void DbWrapper::initClock(odb::dbNet* net) {
        std::string driver = "";
        odb::dbITerm* iterm = net->getFirstOutput();
        int xPin, yPin;
        if (!iterm) {
                odb::dbBTerm* bterm = net->get1stBTerm(); // Clock pin
                driver = bterm->getConstName();
                bterm->getFirstPinLocation(xPin, yPin);
         } else {
                odb::dbInst* inst = iterm->getInst();
                odb::dbMTerm* mterm = iterm->getMTerm();
                std::string driver = std::string(inst->getConstName()) + "/" +
                                   std::string(mterm->getConstName());
                DBU xTmp, yTmp;
                computeITermPosition(iterm, xTmp, yTmp);
                xPin = xTmp; yPin = yTmp;
        }

        // Initialize clock net
        std::cout << net->getConstName() << std::endl;

        Clock clockNet(net->getConstName(),
                       driver,
                       xPin, yPin);

        odb::dbSet<odb::dbITerm> iterms = net->getITerms();
        odb::dbSet<odb::dbITerm>::iterator itr;
        for (itr = iterms.begin(); itr != iterms.end(); ++itr) {
                odb::dbITerm* iterm = *itr;

		if (iterm->getIoType() != odb::dbIoType::INPUT) {
                        continue;
                }

		odb::dbInst* inst = iterm->getInst();
                odb::dbMTerm* mterm = iterm->getMTerm();
                std::string name = std::string(inst->getConstName()) + "/" +
                                   std::string(mterm->getConstName());
                DBU x, y;
                computeITermPosition(iterm, x, y);
                clockNet.addSink(name, x, y);
        }

        if (clockNet.getNumSinks() < 2) {
                std::cout << "    [WARNING] Net \"" << clockNet.getName() << "\""
                          << " has " << clockNet.getNumSinks()  << " sinks. Skipping...\n";
                return;

        }

        _kernel->addBuilder(new HTreeBuilder(*_options, clockNet));
}

void DbWrapper::parseClockNames(std::vector<std::string>& clockNetNames) const {
        std::stringstream allNames(_options->getClockNets());

        std::string tmpName = "";
        while (allNames >> tmpName) {
                clockNetNames.push_back(tmpName);
        }

        unsigned numClocks = clockNetNames.size();
        std::cout << " Number of user-input clocks: " << numClocks;

        if (numClocks > 0) {
                std::cout << " (";
                for (const std::string& name: clockNetNames) {
                        std::cout << " \"" << name << "\"";
                }
                std::cout << " )\n";
        } else {
                std::cout << "\n";
                std::cout << " [ERROR] No clock nets have been found.\n";
                std::exit(1);

        }
}

void DbWrapper::computeITermPosition(odb::dbITerm* term, DBU &x, DBU &y) const {
        odb::dbITermShapeItr itr;

        odb::dbShape shape;
        x = 0;
        y = 0;
        unsigned numShapes = 0;
        for (itr.begin(term); itr.next(shape); ) {
                if (shape.isVia()) {
                        continue;
                } else {
                        x += shape.xMin() + (shape.xMax() - shape.xMin()) / 2;
                        y += shape.yMin() + (shape.yMax() - shape.yMin()) / 2;
                        ++numShapes;
                }
        }

        x /= numShapes;
        y /= numShapes;
};

void DbWrapper::writeClockNetsToDb(const Clock& clockNet) {
        std::cout << " Writing clock net \"" << clockNet.getName() << "\" to DB\n";

        disconnectAllSinksFromNet(clockNet.getName());

        createClockBuffers(clockNet);

        // connect top buffer on the clock pin
        odb::dbNet* topClockNet = _block->findNet(clockNet.getName().c_str());
        std::string topClockInstName = "clkbuf_0_" + clockNet.getName();
        odb::dbInst* topClockInst = _block->findInst(topClockInstName.c_str());
        odb::dbITerm* topClockInstInputPin = getFirstInput(topClockInst);
        odb::dbITerm::connect(topClockInstInputPin, topClockNet);
        topClockNet->setSigType(odb::dbSigType::CLOCK);

        // create subNets
        unsigned numClkNets = 0;
        clockNet.forEachSubNet( [&] (const Clock::SubNet& subNet) {
                        //std::cout << "    SubNet: " << subNet.getName() << "\n";
                        odb::dbNet* clkSubNet = odb::dbNet::create(_block, subNet.getName().c_str());
                        ++numClkNets;
                        clkSubNet->setSigType(odb::dbSigType::CLOCK);

                        //std::cout << "      Driver: " << subNet.getDriver()->getName() << "\n";

                        odb::dbInst* driver = _block->findInst(subNet.getDriver()->getName().c_str());
                        odb::dbITerm* outputPin = driver->getFirstOutput();
                        odb::dbITerm::connect(outputPin, clkSubNet);

                        subNet.forEachSink( [&] (ClockInst *inst) {
                                //std::cout << "      " << inst->getName() << "\n";
                                odb::dbITerm* inputPin = nullptr;
                                if (inst->isClockBuffer()) {
                                        odb::dbInst* sink = _block->findInst(inst->getName().c_str());
                                        inputPin = getFirstInput(sink);
                                } else {
                                        inputPin = _block->findITerm(inst->getName().c_str());
                                }
                                odb::dbITerm::connect(inputPin, clkSubNet);
                        });
                });

        if (_options->writeOnlyClockNets()) {
                removeNonClockNets();
        }

        std::cout << "    Created " << numClkNets << " clock nets.\n";
}

void DbWrapper::disconnectAllSinksFromNet(std::string netName) {
        odb::dbNet* net = _block->findNet(netName.c_str());
        odb::dbSet<odb::dbITerm> iterms = net->getITerms();
        odb::dbSet<odb::dbITerm>::iterator itr;
        for (itr = iterms.begin(); itr != iterms.end(); ++itr) {
                odb::dbITerm* iterm = *itr;
                if (iterm->getIoType() != odb::dbIoType::INPUT) {
                        continue;
                }
                odb::dbITerm::disconnect(iterm);
        }
}

void DbWrapper::createClockBuffers(const Clock& clockNet) {
        unsigned numBuffers = 0;
        clockNet.forEachClockBuffer([&] (const ClockInst& inst) {
                odb::dbMaster* master = _db->findMaster(inst.getMaster().c_str());
                odb::dbInst* newInst = odb::dbInst::create(_block, master, inst.getName().c_str());
                newInst->setLocation(inst.getX(), inst.getY());
                newInst->setPlacementStatus(odb::dbPlacementStatus::PLACED);
                ++numBuffers;
        });
        std::cout << "    Created " << numBuffers << " clock buffers.\n";
}

odb::dbITerm* DbWrapper::getFirstInput(odb::dbInst* inst) const {
        odb::dbSet<odb::dbITerm> iterms = inst->getITerms();
        odb::dbSet<odb::dbITerm>::iterator itr;

        for (itr = iterms.begin(); itr != iterms.end(); ++itr) {
                odb::dbITerm* iterm = *itr;
                if (iterm->isInputSignal()) {
                        return iterm;
                }
        }

        return nullptr;
}

bool DbWrapper::masterExists(const std::string& master) const {
        return _db->findMaster(master.c_str());
};

void DbWrapper::removeNonClockNets() {
        for (odb::dbNet* net : _block->getNets()) {
                if (net->getSigType() != odb::dbSigType::CLOCK) {
                        odb::dbNet::destroy(net);
                }
        }
}

}
<|endoftext|>


<commit_before>/*  This file is part of the KDE project
    Copyright (C) 2006 Matthias Kretz <kretz@kde.org>

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License version 2 as published by the Free Software Foundation.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public License
    along with this library; see the file COPYING.LIB.  If not, write to
    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
    Boston, MA 02110-1301, USA.

*/

#include "mediacontrols.h"
#include "../abstractmediaproducer.h"
#include "../audiooutput.h"
#include <kglobal.h>
#include <kiconloader.h>
#include <klocale.h>
#include <QHBoxLayout>
#include <QToolButton>
#include "seekslider.h"
#include "volumeslider.h"

namespace Phonon
{

class MediaControls::Private
{
	public:
		Private()
			: layout( 0 )
			, playButton( 0 )
			, pauseButton( 0 )
			, stopButton( 0 )
			, loopButton( 0 )
			, seekSlider( 0 )
			, volumeSlider( 0 )
			, media( 0 )
		{
		}

		QHBoxLayout* layout;
		QToolButton* playButton;
		QToolButton* pauseButton;
		QToolButton* stopButton;
		QToolButton* loopButton;
		SeekSlider*  seekSlider;
		VolumeSlider* volumeSlider;
		AbstractMediaProducer* media;
};

MediaControls::MediaControls( QWidget* parent )
	: QWidget( parent )
	, d( new Private )
{
	d->playButton = new QToolButton( this );
	d->playButton->setIcon( SmallIcon( "player_play" ) );
	d->playButton->setText( i18n( "&Play" ) );
	d->playButton->setFixedSize( 20, 20 );
	d->playButton->setAutoRaise( true );

	d->pauseButton = new QToolButton( this );
	d->pauseButton->setIcon( SmallIcon( "player_pause" ) );
	d->pauseButton->setText( i18n( "&Pause" ) );
	d->pauseButton->setEnabled( false );
	d->pauseButton->setFixedSize( 20, 20 );
	d->pauseButton->setAutoRaise( true );

	d->stopButton = new QToolButton( this );
	d->stopButton->setIcon( SmallIcon( "player_stop" ) );
	d->stopButton->setText( i18n( "&Stop" ) );
	d->stopButton->setFixedSize( 20, 20 );
	d->stopButton->setAutoRaise( true );

	d->seekSlider = new SeekSlider( this );

	d->volumeSlider = new VolumeSlider( this );
	d->volumeSlider->setOrientation( Qt::Horizontal );
	d->volumeSlider->setFixedWidth( 70 );
	d->volumeSlider->hide();

	d->layout = new QHBoxLayout( this );
	d->layout->setMargin( 0 );
	d->layout->setSpacing( 2 );
	d->layout->addWidget( d->playButton );
	d->layout->addWidget( d->pauseButton );
	d->layout->addWidget( d->stopButton );
	d->layout->addSpacing( 4 );
	d->layout->addWidget( d->seekSlider, 1 );
	d->layout->addSpacing( 4 );
	d->layout->addWidget( d->volumeSlider );
	d->layout->addStretch();
}

MediaControls::~MediaControls()
{
	delete d;
}

bool MediaControls::isSeekSliderVisible() const
{
	return d->seekSlider->isVisible();
}

bool MediaControls::isVolumeControlVisible() const
{
	return d->volumeSlider->isVisible();
}

bool MediaControls::isLoopControlVisible() const
{
	return d->loopButton->isVisible();
}

void MediaControls::setMediaProducer( AbstractMediaProducer* media )
{
	if( !media )
		return;

	d->media = media;
	connect( d->media, SIGNAL( destroyed() ), SLOT( mediaDestroyed() ) );
	connect( d->media, SIGNAL( stateChanged( Phonon::State, Phonon::State ) ),
		   	SLOT( stateChanged( Phonon::State, Phonon::State ) ) );
	connect( d->playButton, SIGNAL( clicked() ), d->media, SLOT( play() ) );
	connect( d->pauseButton, SIGNAL( clicked() ), d->media, SLOT( pause() ) );
	connect( d->stopButton, SIGNAL( clicked() ), d->media, SLOT( stop() ) );

	d->seekSlider->setMediaProducer( d->media );
}

void MediaControls::setAudioOutput( AudioOutput* audioOutput )
{
	d->volumeSlider->setAudioOutput( audioOutput );
	d->volumeSlider->show();
}

void MediaControls::setSeekSliderVisible( bool vis )
{
	d->seekSlider->setVisible( vis );
}

void MediaControls::setVolumeControlVisible( bool vis )
{
	d->volumeSlider->setVisible( vis );
}

void MediaControls::setLoopControlVisible( bool vis )
{
	d->loopButton->setVisible( vis );
}

void MediaControls::stateChanged( State newstate, State )
{
	switch( newstate )
	{
		case Phonon::LoadingState:
		case Phonon::PausedState:
		case Phonon::StoppedState:
			d->playButton->setEnabled( true );
			d->pauseButton->setEnabled( false );
			break;
		case Phonon::BufferingState:
		case Phonon::PlayingState:
			d->playButton->setEnabled( false );
			d->pauseButton->setEnabled( true );
			break;
		case Phonon::ErrorState:
			return;
	}
}

void MediaControls::mediaDestroyed()
{
	d->media = 0;
}

} // namespace Phonon

#include "mediacontrols.moc"
// vim: sw=4 ts=4 noet
<commit_msg>Max height<commit_after>/*  This file is part of the KDE project
    Copyright (C) 2006 Matthias Kretz <kretz@kde.org>

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License version 2 as published by the Free Software Foundation.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public License
    along with this library; see the file COPYING.LIB.  If not, write to
    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
    Boston, MA 02110-1301, USA.

*/

#include "mediacontrols.h"
#include "../abstractmediaproducer.h"
#include "../audiooutput.h"
#include <kglobal.h>
#include <kiconloader.h>
#include <klocale.h>
#include <QHBoxLayout>
#include <QToolButton>
#include "seekslider.h"
#include "volumeslider.h"

namespace Phonon
{

class MediaControls::Private
{
	public:
		Private()
			: layout( 0 )
			, playButton( 0 )
			, pauseButton( 0 )
			, stopButton( 0 )
			, loopButton( 0 )
			, seekSlider( 0 )
			, volumeSlider( 0 )
			, media( 0 )
		{
		}

		QHBoxLayout* layout;
		QToolButton* playButton;
		QToolButton* pauseButton;
		QToolButton* stopButton;
		QToolButton* loopButton;
		SeekSlider*  seekSlider;
		VolumeSlider* volumeSlider;
		AbstractMediaProducer* media;
};

MediaControls::MediaControls( QWidget* parent )
	: QWidget( parent )
	, d( new Private )
{
	d->playButton = new QToolButton( this );
	d->playButton->setIcon( SmallIcon( "player_play" ) );
	d->playButton->setText( i18n( "&Play" ) );
	d->playButton->setFixedSize( 20, 20 );
	d->playButton->setAutoRaise( true );

	d->pauseButton = new QToolButton( this );
	d->pauseButton->setIcon( SmallIcon( "player_pause" ) );
	d->pauseButton->setText( i18n( "&Pause" ) );
	d->pauseButton->setEnabled( false );
	d->pauseButton->setFixedSize( 20, 20 );
	d->pauseButton->setAutoRaise( true );

	d->stopButton = new QToolButton( this );
	d->stopButton->setIcon( SmallIcon( "player_stop" ) );
	d->stopButton->setText( i18n( "&Stop" ) );
	d->stopButton->setFixedSize( 20, 20 );
	d->stopButton->setAutoRaise( true );

	d->seekSlider = new SeekSlider( this );

	d->volumeSlider = new VolumeSlider( this );
	d->volumeSlider->setOrientation( Qt::Horizontal );
	d->volumeSlider->setFixedWidth( 70 );
	d->volumeSlider->hide();

	d->layout = new QHBoxLayout( this );
	d->layout->setMargin( 0 );
	d->layout->setSpacing( 2 );
	d->layout->addWidget( d->playButton );
	d->layout->addWidget( d->pauseButton );
	d->layout->addWidget( d->stopButton );
	d->layout->addSpacing( 4 );
	d->layout->addWidget( d->seekSlider, 1 );
	d->layout->addSpacing( 4 );
	d->layout->addWidget( d->volumeSlider );
	d->layout->addStretch();

	setMaximumHeight(20);

}

MediaControls::~MediaControls()
{
	delete d;
}

bool MediaControls::isSeekSliderVisible() const
{
	return d->seekSlider->isVisible();
}

bool MediaControls::isVolumeControlVisible() const
{
	return d->volumeSlider->isVisible();
}

bool MediaControls::isLoopControlVisible() const
{
	return d->loopButton->isVisible();
}

void MediaControls::setMediaProducer( AbstractMediaProducer* media )
{
	if( !media )
		return;

	d->media = media;
	connect( d->media, SIGNAL( destroyed() ), SLOT( mediaDestroyed() ) );
	connect( d->media, SIGNAL( stateChanged( Phonon::State, Phonon::State ) ),
		   	SLOT( stateChanged( Phonon::State, Phonon::State ) ) );
	connect( d->playButton, SIGNAL( clicked() ), d->media, SLOT( play() ) );
	connect( d->pauseButton, SIGNAL( clicked() ), d->media, SLOT( pause() ) );
	connect( d->stopButton, SIGNAL( clicked() ), d->media, SLOT( stop() ) );

	d->seekSlider->setMediaProducer( d->media );
}

void MediaControls::setAudioOutput( AudioOutput* audioOutput )
{
	d->volumeSlider->setAudioOutput( audioOutput );
	d->volumeSlider->show();
}

void MediaControls::setSeekSliderVisible( bool vis )
{
	d->seekSlider->setVisible( vis );
}

void MediaControls::setVolumeControlVisible( bool vis )
{
	d->volumeSlider->setVisible( vis );
}

void MediaControls::setLoopControlVisible( bool vis )
{
	d->loopButton->setVisible( vis );
}

void MediaControls::stateChanged( State newstate, State )
{
	switch( newstate )
	{
		case Phonon::LoadingState:
		case Phonon::PausedState:
		case Phonon::StoppedState:
			d->playButton->setEnabled( true );
			d->pauseButton->setEnabled( false );
			break;
		case Phonon::BufferingState:
		case Phonon::PlayingState:
			d->playButton->setEnabled( false );
			d->pauseButton->setEnabled( true );
			break;
		case Phonon::ErrorState:
			return;
	}
}

void MediaControls::mediaDestroyed()
{
	d->media = 0;
}

} // namespace Phonon

#include "mediacontrols.moc"
// vim: sw=4 ts=4 noet
<|endoftext|>


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

#include "CoreAudioOut.h"
#include <core/sdk/constants.h>
#include <iostream>

#define BUFFER_COUNT 24

using namespace musik::core::sdk;

void audioCallback(void *customData, AudioQueueRef queue, AudioQueueBufferRef buffer) {
    CoreAudioOut* output = (CoreAudioOut *) customData;
    CoreAudioOut::BufferContext* context = (CoreAudioOut::BufferContext *) buffer->mUserData;

    OSStatus result = AudioQueueFreeBuffer(queue, buffer);

    if (result != 0) {
        std::cerr << "AudioQueueFreeBuffer failed: " << result << "\n";
    }

    output->NotifyBufferCompleted(context);
}

void CoreAudioOut::NotifyBufferCompleted(BufferContext *context) {
    {
        std::unique_lock<std::recursive_mutex> lock(this->mutex);

        if (bufferCount > 0) {
            --bufferCount;
        }
    }

    context->provider->OnBufferProcessed(context->buffer);
    delete context;
}

CoreAudioOut::CoreAudioOut() {
    this->quit = false;
    this->state = StateStopped;
    this->volume = 1.0f;

    this->audioFormat = (AudioStreamBasicDescription) { 0 };

    this->audioFormat.mFormatID = kAudioFormatLinearPCM;
    this->audioFormat.mFormatFlags = kAudioFormatFlagIsFloat;
    this->audioFormat.mFramesPerPacket = 1;
    this->audioFormat.mBitsPerChannel = 32;
    this->audioFormat.mReserved = 0;

    /* these get filled in later */
    this->audioFormat.mChannelsPerFrame = -1;
    this->audioFormat.mSampleRate = -1;
    this->audioFormat.mBytesPerFrame = -1;
    this->audioFormat.mBytesPerPacket = -1;

    this->audioQueue = nullptr;
    this->bufferCount = 0;
}

int CoreAudioOut::Play(IBuffer *buffer, IBufferProvider *provider) {
    std::unique_lock<std::recursive_mutex> lock(this->mutex);

    if (this->state != StatePlaying) {
        return OutputInvalidState;
    }

    if (this->bufferCount >= BUFFER_COUNT) {
        /* enough buffers are already in the queue. bail, we'll notify the
        caller when there's more data available */
        return OutputBufferFull;
    }

    OSStatus result;

    if (buffer->SampleRate() != this->audioFormat.mSampleRate ||
        buffer->Channels() != this->audioFormat.mChannelsPerFrame ||
        this->audioQueue == nullptr)
    {
        this->audioFormat.mSampleRate = buffer->SampleRate();
        this->audioFormat.mChannelsPerFrame = buffer->Channels();
        this->audioFormat.mBytesPerFrame = (this->audioFormat.mBitsPerChannel / 8) * this->audioFormat.mChannelsPerFrame;
        this->audioFormat.mBytesPerPacket = this->audioFormat.mBytesPerFrame * this->audioFormat.mFramesPerPacket;

        this->Stop();

        result = AudioQueueNewOutput(
            &this->audioFormat,
            audioCallback,
            this,
            nullptr,
            kCFRunLoopCommonModes,
            0,
            &this->audioQueue);

        if (result != 0) {
            std::cerr << "AudioQueueNewOutput failed: " << result << "\n";
            return OutputInvalidState;
        }

        result = AudioQueueStart(this->audioQueue, nullptr);

        this->SetVolume(volume);

        if (result != 0) {
            std::cerr << "AudioQueueStart failed: " << result << "\n";
            return OutputInvalidState;
        }

        this->Resume();
    }

    AudioQueueBufferRef audioQueueBuffer = nullptr;

    size_t bytes = buffer->Bytes();

    result = AudioQueueAllocateBuffer(this->audioQueue, bytes, &audioQueueBuffer);

    BufferContext* context = new BufferContext();
    context->provider = provider;
    context->buffer = buffer;

    if (result != 0) {
        std::cerr << "AudioQueueAllocateBuffer failed: " << result << "\n";
        return OutputInvalidState;
    }

    audioQueueBuffer->mUserData = (void *) context;
    audioQueueBuffer->mAudioDataByteSize = bytes;

    memcpy(
        audioQueueBuffer->mAudioData,
        (void *) buffer->BufferPointer(),
        bytes);

    result = AudioQueueEnqueueBuffer(
        this->audioQueue, audioQueueBuffer, 0, nullptr);

    if (result != 0) {
        std::cerr << "AudioQueueEnqueueBuffer failed: " << result << "\n";
        delete context;
        return OutputInvalidState;
    }

    ++bufferCount;

    return OutputBufferWritten;
}

CoreAudioOut::~CoreAudioOut() {
    this->Stop();
}

void CoreAudioOut::Destroy() {
    delete this;
}

void CoreAudioOut::Drain() {
    std::unique_lock<std::recursive_mutex> lock(this->mutex);

    if (this->state != StateStopped && this->audioQueue) {
        std::cerr << "CoreAudioOut: draining...\n";
        AudioQueueFlush(this->audioQueue);
        std::cerr << "CoreAudioOut: drained.\n";
    }
}

void CoreAudioOut::Pause() {
    std::unique_lock<std::recursive_mutex> lock(this->mutex);

    if (this->audioQueue) {
        AudioQueuePause(this->audioQueue);
        this->state = StatePaused;
    }
}

void CoreAudioOut::Resume() {
    std::unique_lock<std::recursive_mutex> lock(this->mutex);

    if (this->audioQueue) {
        AudioQueueStart(this->audioQueue, nullptr);
    }

    this->state = StatePlaying;
}

void CoreAudioOut::SetVolume(double volume) {
    std::unique_lock<std::recursive_mutex> lock(this->mutex);

    this->volume = volume;

    if (this->audioQueue) {
        OSStatus result = AudioQueueSetParameter(
            this->audioQueue,
            kAudioQueueParam_Volume,
            volume);

        if (result != 0) {
            std::cerr << "AudioQueueSetParameter(volume) failed: " << result << "\n";
        }
    }
}

double CoreAudioOut::GetVolume() {
    return this->volume;
}

void CoreAudioOut::Stop() {
    AudioQueueRef queue = nullptr;

    {
        /* AudioQueueStop/AudioQueueDispose will trigger the callback, which
        will try to dispose of the samples on a separate thread and deadlock.
        cache the queue and reset outside of the critical section */
        std::unique_lock<std::recursive_mutex> lock(this->mutex);
        queue = this->audioQueue;
        this->audioQueue = nullptr;
        this->state = StateStopped;
        this->bufferCount = 0;
    }

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

#include "CoreAudioOut.h"
#include <core/sdk/constants.h>
#include <iostream>

#define BUFFER_COUNT 24

using namespace musik::core::sdk;

void audioCallback(void *customData, AudioQueueRef queue, AudioQueueBufferRef buffer) {
    CoreAudioOut* output = (CoreAudioOut *) customData;
    CoreAudioOut::BufferContext* context = (CoreAudioOut::BufferContext *) buffer->mUserData;

    OSStatus result = AudioQueueFreeBuffer(queue, buffer);

    if (result != 0) {
        std::cerr << "AudioQueueFreeBuffer failed: " << result << "\n";
    }

    output->NotifyBufferCompleted(context);
}

void CoreAudioOut::NotifyBufferCompleted(BufferContext *context) {
    {
        std::unique_lock<std::recursive_mutex> lock(this->mutex);

        if (bufferCount > 0) {
            --bufferCount;
        }
    }

    context->provider->OnBufferProcessed(context->buffer);
    delete context;
}

CoreAudioOut::CoreAudioOut() {
    this->quit = false;
    this->state = StateStopped;
    this->volume = 1.0f;

    this->audioFormat = (AudioStreamBasicDescription) { 0 };

    this->audioFormat.mFormatID = kAudioFormatLinearPCM;
    this->audioFormat.mFormatFlags = kAudioFormatFlagIsFloat;
    this->audioFormat.mFramesPerPacket = 1;
    this->audioFormat.mBitsPerChannel = 32;
    this->audioFormat.mReserved = 0;

    /* these get filled in later */
    this->audioFormat.mChannelsPerFrame = -1;
    this->audioFormat.mSampleRate = -1;
    this->audioFormat.mBytesPerFrame = -1;
    this->audioFormat.mBytesPerPacket = -1;

    this->audioQueue = nullptr;
    this->bufferCount = 0;
}

int CoreAudioOut::Play(IBuffer *buffer, IBufferProvider *provider) {
    std::unique_lock<std::recursive_mutex> lock(this->mutex);

    if (this->state != StatePlaying) {
        return OutputInvalidState;
    }

    if (this->bufferCount >= BUFFER_COUNT) {
        /* enough buffers are already in the queue. bail, we'll notify the
        caller when there's more data available */
        return OutputBufferFull;
    }

    OSStatus result;

    if (buffer->SampleRate() != this->audioFormat.mSampleRate ||
        buffer->Channels() != this->audioFormat.mChannelsPerFrame ||
        this->audioQueue == nullptr)
    {
        this->audioFormat.mSampleRate = buffer->SampleRate();
        this->audioFormat.mChannelsPerFrame = buffer->Channels();
        this->audioFormat.mBytesPerFrame = (this->audioFormat.mBitsPerChannel / 8) * this->audioFormat.mChannelsPerFrame;
        this->audioFormat.mBytesPerPacket = this->audioFormat.mBytesPerFrame * this->audioFormat.mFramesPerPacket;

        lock.unlock();
        this->Stop();
        lock.lock();

        result = AudioQueueNewOutput(
            &this->audioFormat,
            audioCallback,
            this,
            nullptr,
            kCFRunLoopCommonModes,
            0,
            &this->audioQueue);

        if (result != 0) {
            std::cerr << "AudioQueueNewOutput failed: " << result << "\n";
            return OutputInvalidState;
        }

        result = AudioQueueStart(this->audioQueue, nullptr);

        this->SetVolume(volume);

        if (result != 0) {
            std::cerr << "AudioQueueStart failed: " << result << "\n";
            return OutputInvalidState;
        }

        this->Resume();
    }

    AudioQueueBufferRef audioQueueBuffer = nullptr;

    size_t bytes = buffer->Bytes();

    result = AudioQueueAllocateBuffer(this->audioQueue, bytes, &audioQueueBuffer);

    BufferContext* context = new BufferContext();
    context->provider = provider;
    context->buffer = buffer;

    if (result != 0) {
        std::cerr << "AudioQueueAllocateBuffer failed: " << result << "\n";
        return OutputInvalidState;
    }

    audioQueueBuffer->mUserData = (void *) context;
    audioQueueBuffer->mAudioDataByteSize = bytes;

    memcpy(
        audioQueueBuffer->mAudioData,
        (void *) buffer->BufferPointer(),
        bytes);

    result = AudioQueueEnqueueBuffer(
        this->audioQueue, audioQueueBuffer, 0, nullptr);

    if (result != 0) {
        std::cerr << "AudioQueueEnqueueBuffer failed: " << result << "\n";
        delete context;
        return OutputInvalidState;
    }

    ++bufferCount;

    return OutputBufferWritten;
}

CoreAudioOut::~CoreAudioOut() {
    this->Stop();
}

void CoreAudioOut::Destroy() {
    delete this;
}

void CoreAudioOut::Drain() {
    std::unique_lock<std::recursive_mutex> lock(this->mutex);

    if (this->state != StateStopped && this->audioQueue) {
        std::cerr << "CoreAudioOut: draining...\n";
        AudioQueueFlush(this->audioQueue);
        std::cerr << "CoreAudioOut: drained.\n";
    }
}

void CoreAudioOut::Pause() {
    std::unique_lock<std::recursive_mutex> lock(this->mutex);

    if (this->audioQueue) {
        AudioQueuePause(this->audioQueue);
        this->state = StatePaused;
    }
}

void CoreAudioOut::Resume() {
    std::unique_lock<std::recursive_mutex> lock(this->mutex);

    if (this->audioQueue) {
        AudioQueueStart(this->audioQueue, nullptr);
    }

    this->state = StatePlaying;
}

void CoreAudioOut::SetVolume(double volume) {
    std::unique_lock<std::recursive_mutex> lock(this->mutex);

    this->volume = volume;

    if (this->audioQueue) {
        OSStatus result = AudioQueueSetParameter(
            this->audioQueue,
            kAudioQueueParam_Volume,
            volume);

        if (result != 0) {
            std::cerr << "AudioQueueSetParameter(volume) failed: " << result << "\n";
        }
    }
}

double CoreAudioOut::GetVolume() {
    return this->volume;
}

void CoreAudioOut::Stop() {
    AudioQueueRef queue = nullptr;

    {
        /* AudioQueueStop/AudioQueueDispose will trigger the callback, which
        will try to dispose of the samples on a separate thread and deadlock.
        cache the queue and reset outside of the critical section */
        std::unique_lock<std::recursive_mutex> lock(this->mutex);
        queue = this->audioQueue;
        this->audioQueue = nullptr;
        this->state = StateStopped;
        this->bufferCount = 0;
    }

    if (queue) {
        AudioQueueStop(queue, true);
        AudioQueueDispose(queue, true);
    }
}
<|endoftext|>


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

#include <grpc/impl/codegen/port_platform.h>

#include "src/core/lib/channel/channel_trace.h"
#include "src/core/lib/channel/channelz_registry.h"
#include "src/core/lib/gpr/useful.h"
#include "src/core/lib/gprpp/memory.h"

#include <grpc/support/alloc.h>
#include <grpc/support/log.h>

#include <cstring>

namespace grpc_core {
namespace {

// singleton instance of the registry.
ChannelzRegistry* g_channelz_registry = nullptr;

}  // anonymous namespace

void ChannelzRegistry::Init() { g_channelz_registry = New<ChannelzRegistry>(); }

void ChannelzRegistry::Shutdown() { Delete(g_channelz_registry); }

ChannelzRegistry* ChannelzRegistry::Default() {
  GPR_DEBUG_ASSERT(g_channelz_registry != nullptr);
  return g_channelz_registry;
}

ChannelzRegistry::ChannelzRegistry() {
  gpr_mu_init(&mu_);
  // init elements to nullptr
  memset(entities_.data(), 0, sizeof(void*) * entities_.capacity());
}

ChannelzRegistry::~ChannelzRegistry() {
  // null out all elements so that the destructors don't try to run.
  // this is a "view only" object.
  memset(entities_.data(), 0, sizeof(void*) * entities_.capacity());
  gpr_mu_destroy(&mu_);
}

void ChannelzRegistry::InternalUnregister(intptr_t uuid) {
  GPR_ASSERT(uuid >= 1);
  gpr_mu_lock(&mu_);
  GPR_ASSERT((size_t)uuid <= entities_.size());
  entities_[uuid - 1] = nullptr;
  gpr_mu_unlock(&mu_);
}

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

#include <grpc/impl/codegen/port_platform.h>

#include "src/core/lib/channel/channel_trace.h"
#include "src/core/lib/channel/channelz_registry.h"
#include "src/core/lib/gpr/useful.h"
#include "src/core/lib/gprpp/memory.h"

#include <grpc/support/alloc.h>
#include <grpc/support/log.h>

#include <cstring>

namespace grpc_core {
namespace {

// singleton instance of the registry.
ChannelzRegistry* g_channelz_registry = nullptr;

}  // anonymous namespace

void ChannelzRegistry::Init() { g_channelz_registry = New<ChannelzRegistry>(); }

void ChannelzRegistry::Shutdown() { Delete(g_channelz_registry); }

ChannelzRegistry* ChannelzRegistry::Default() {
  GPR_DEBUG_ASSERT(g_channelz_registry != nullptr);
  return g_channelz_registry;
}

ChannelzRegistry::ChannelzRegistry() { gpr_mu_init(&mu_); }

ChannelzRegistry::~ChannelzRegistry() { gpr_mu_destroy(&mu_); }

void ChannelzRegistry::InternalUnregister(intptr_t uuid) {
  GPR_ASSERT(uuid >= 1);
  gpr_mu_lock(&mu_);
  GPR_ASSERT(static_cast<size_t>(uuid) <= entities_.size());
  entities_[uuid - 1] = nullptr;
  gpr_mu_unlock(&mu_);
}

}  // namespace grpc_core
<|endoftext|>