<commit_before>#pragma once

#include <vector>
#include <map>
#include <string>
#include <memory>

#include <boost/variant.hpp>

namespace mstch {
namespace internal {

template<class N>
class object_t {
 public:
  const N& at(const std::string& name) const {
    cache[name] = (methods.at(name))();
    return cache[name];
  }

  bool has(const std::string name) const {
    return methods.count(name);
  }

 protected:
  template<class S>
  void register_methods(S* s, std::map<std::string,N(S::*)()> methods) {
    for(auto& item: methods)
      this->methods.insert({item.first, std::bind(item.second, s)});
  }

 private:
  std::map<std::string, std::function<N()>> methods;
  mutable std::map<std::string, N> cache;
};

}

using renderer = std::function<std::string(const std::string&)>;

class lambda {
 public:
  lambda(std::function<std::string()> fun):
      fun([fun](const std::string&, renderer){return fun();})
  {
  }

  lambda(std::function<std::string(const std::string&, renderer)> fun):
      fun(fun)
  {
  }

  std::string operator()(
      const std::string& text = "",
      renderer renderer = renderer()) const
  {
    return fun(text, renderer);
  }

 private:
  std::function<std::string(const std::string&, renderer)> fun;
};

using node = boost::make_recursive_variant<
    boost::blank, std::string, int, bool, lambda,
    std::shared_ptr<internal::object_t<boost::recursive_variant_>>,
    std::map<const std::string, boost::recursive_variant_>,
    std::vector<boost::recursive_variant_>>::type;
using object = internal::object_t<node>;
using map = std::map<const std::string, node>;
using array = std::vector<node>;

std::string render(
    const std::string& tmplt,
    const node& root,
    const std::map<std::string,std::string>& partials =
        std::map<std::string,std::string>());

}
<commit_msg>TMP magic to support gcc 4.7<commit_after>#pragma once

#include <vector>
#include <map>
#include <string>
#include <memory>

#include <boost/variant.hpp>

namespace mstch {

using renderer = std::function<std::string(const std::string&)>;

namespace internal {

template<class N>
class object_t {
 public:
  const N& at(const std::string& name) const {
    cache[name] = (methods.at(name))();
    return cache[name];
  }

  bool has(const std::string name) const {
    return methods.count(name);
  }

 protected:
  template<class S>
  void register_methods(S* s, std::map<std::string,N(S::*)()> methods) {
    for(auto& item: methods)
      this->methods.insert({item.first, std::bind(item.second, s)});
  }

 private:
  std::map<std::string, std::function<N()>> methods;
  mutable std::map<std::string, N> cache;
};

template <typename T>
class is_fun {
 private:
  using not_fun = char;
  using fun_without_args = char[2];
  using fun_with_args = char[3];
  template <typename U, U> struct really_has;
  template <typename C> static fun_without_args& test(
      really_has<std::string(C::*)() const, &C::operator()>*);
  template <typename C> static fun_with_args& test(
      really_has<std::string(C::*)(const std::string&,renderer) const,
      &C::operator()>*);
  template <typename> static not_fun& test(...);

 public:
  static bool const no_args = sizeof(test<T>(0)) == sizeof(fun_without_args);
  static bool const has_args = sizeof(test<T>(0)) == sizeof(fun_with_args);
};

}

class lambda {
 public:
  template<class F>
  lambda(F f, typename std::enable_if<internal::is_fun<F>::no_args>::type* =0):
      fun([f](const std::string&,renderer){return f();})
  {
  }

  template<class F>
  lambda(F f, typename std::enable_if<internal::is_fun<F>::has_args>::type* =0):
      fun(f)
  {
  }

  std::string operator()(
      const std::string& text = "",
      renderer renderer = renderer()) const
  {
    return fun(text, renderer);
  }

 private:
  std::function<std::string(const std::string&, renderer)> fun;
};

using node = boost::make_recursive_variant<
    boost::blank, std::string, int, bool, lambda,
    std::shared_ptr<internal::object_t<boost::recursive_variant_>>,
    std::map<const std::string, boost::recursive_variant_>,
    std::vector<boost::recursive_variant_>>::type;
using object = internal::object_t<node>;
using map = std::map<const std::string, node>;
using array = std::vector<node>;

std::string render(
    const std::string& tmplt,
    const node& root,
    const std::map<std::string,std::string>& partials =
        std::map<std::string,std::string>());

}
<|endoftext|>


<commit_before>#include "interpreterCore/managers/saveConvertionManager.h"

using namespace interpreterCore;
using namespace qReal;

QString SaveConvertionManager::editor()
{
	return "RobotsMetamodel";
}

QList<ProjectConverter> SaveConvertionManager::converters()
{
	return { before300Alpha1Converter()
		, from300Alpha4to300Alpha5Converter()
		, from300Beta2to300rc1Converter()
		, from300to301Converter()
	};
}

ProjectConverter SaveConvertionManager::before300Alpha1Converter()
{
	return ProjectConverter(editor(), Version(), Version::fromString("3.0.0-a1")
			, [=](const GraphicalModelAssistInterface &graphicalApi, LogicalModelAssistInterface &logicalApi)
	{
		Q_UNUSED(graphicalApi)
		Q_UNUSED(logicalApi)
		return ProjectConverter::VersionTooOld;
	});
}

ProjectConverter SaveConvertionManager::from300Alpha4to300Alpha5Converter()
{
	return constructConverter("3.0.0-a4", "3.0.0-a5"
			, {
				replace({
						{"JA1", "A1"}
						, {"JA2", "A2"}
						, {"JA3", "A3"}
						, {"JA4", "A4"}
						, {"JA5", "A5"}
						, {"JA6", "A6"}

						, {"JD1", "D1"}
						, {"JD2", "D2"}

						, {"JF1", "F1"}

						, {"JM1", "M1"}
						, {"JM2", "M2"}
						, {"JM3", "M3"}
						, {"JM4", "M4"}

						, {"JB1", "B1"}
						, {"JB2", "B2"}
						, {"JB3", "B3"}
						, {"JB4", "B4"}

						, {"JE1", "E1"}
						, {"JE2", "E2"}
						, {"JE3", "E3"}
						, {"JE4", "E4"}

						, {"JC1", "C1"}
						, {"JC2", "C2"}
						, {"JC3", "C3"}

						, {"sensor1", "sensorA1"}
						, {"sensor2", "sensorA2"}
						, {"sensor3", "sensorA3"}
						, {"sensor4", "sensorA4"}
						, {"sensor5", "sensorA5"}
						, {"sensor6", "sensorA6"}

						, {"digitSensor1", "sensorD1"}
						, {"digitSensor2", "sensorD2"}
				})
			}
			, [] (const Id &block) { return block.element().startsWith("Trik"); }
			);

}

ProjectConverter SaveConvertionManager::from300Beta2to300rc1Converter()
{
	return constructConverter("3.0.0-b2", "3.0.0-rc1"
			, { quote("TrikSay", "Text"), quote("PrintText", "PrintText") }
			);
}

qReal::ProjectConverter SaveConvertionManager::from300to301Converter()
{
	return constructConverter("3.0.0", "3.0.1"
			, {
				replace({
						{"enterButton", "buttonEnter"}
						, {"escapeButton", "buttonEscape"}
						, {"leftButton", "buttonLeft"}
						, {"rightButton", "buttonRight"}
						, {"backButton", "buttonBack"}
						, {"downButton", "buttonDown"}
						, {"enterButton", "buttonEnter"}
						, {"upButton", "buttonUp"}
						, {"powerButton", "buttonEsc"}
				  })
				, [=] (const Id &block, LogicalModelAssistInterface &logicalApi) {
						if (block.element().startsWith("Trik")) {
							return replace({{"buttonEscape", "buttonEsc"}})(block, logicalApi);
						}

						return false;
					}
				, deleteBlocks({"Ev3WaitForUp"
						, "Ev3WaitForEnter"
						, "Ev3WaitForDown"
						, "Ev3WaitForRight"
						, "Ev3WaitForLeft"
						, "Ev3WaitForBack"

						, "NxtWaitForEnter"
						, "NxtWaitForEscape"
						, "NxtWaitForLeft"
						, "NxtWaitForRight"

						, "TrikWaitForEnter"
						, "TrikWaitForLeft"
						, "TrikWaitForRight"
						, "TrikWaitForDown"
						, "TrikWaitForUp"
						, "TrikWaitForPower"
						})
			}
			);
}

qReal::ProjectConverter SaveConvertionManager::from301to302Converter()
{
	return constructConverter("3.0.1", "3.0.2", { quote("TrikSystem", "Command") } );
}

bool SaveConvertionManager::isRobotsDiagram(const Id &diagram)
{
	const QStringList robotsDiagrams = { "RobotsDiagram", "SubprogramDiagram" };
	return diagram.editor() == editor() && robotsDiagrams.contains(diagram.diagram());
}

IdList SaveConvertionManager::elementsOfRobotsDiagrams(const LogicalModelAssistInterface &logicalApi)
{
	IdList result;
	for (const Id &diagramId : logicalApi.children(Id::rootId())) {
		if (isRobotsDiagram(diagramId)) {
			result += logicalApi.children(diagramId);
		}
	}

	return result;
}

qReal::ProjectConverter SaveConvertionManager::constructConverter(const QString &oldVersion
		, const QString &newVersion
		, const QList<std::function<bool(const Id &, LogicalModelAssistInterface &)>> &filters
		, const std::function<bool(const qReal::Id &)> &condition
		)
{
	return ProjectConverter(editor(), Version::fromString(oldVersion), Version::fromString(newVersion)
			, [=](const GraphicalModelAssistInterface &graphicalApi, LogicalModelAssistInterface &logicalApi)
	{
		Q_UNUSED(graphicalApi);

		bool modificationsMade = false;

		for (const Id &graphicalBlock : elementsOfRobotsDiagrams(logicalApi)) {
			const Id block = graphicalApi.logicalId(graphicalBlock);

			if (!condition(block)) {
				continue;
			}

			for (const auto &filter : filters) {
				modificationsMade |= filter(block, logicalApi);
			}
		}

		return modificationsMade ? ProjectConverter::Success : ProjectConverter::NoModificationsMade;
	});
}

std::function<bool(const qReal::Id &, qReal::LogicalModelAssistInterface &)> SaveConvertionManager::replace(
		const QMap<QString, QString> &replacementRules)
{
	return [=] (const Id &block, LogicalModelAssistInterface &logicalApi) {
		bool modificationsMade = false;
		QMapIterator<QString, QVariant> iterator = logicalApi.logicalRepoApi().propertiesIterator(block);
		for (iterator.next(); iterator.hasNext(); iterator.next()) {
			const QString name = iterator.key();
			QString value = iterator.value().toString();
			bool replacementOccured = false;
			for (const QString &toReplace : replacementRules.keys()) {
				if (value.contains(toReplace)) {
					replacementOccured = true;
					modificationsMade = true;

					value.replace(toReplace, replacementRules[toReplace]);
				}
			}

			if (replacementOccured) {
				logicalApi.setPropertyByRoleName(block, value, name);
			}
		}

		 return modificationsMade;
	};
}

std::function<bool(const qReal::Id &, qReal::LogicalModelAssistInterface &)>
		SaveConvertionManager::deleteBlocks(const QStringList &blocks)
{
	return [=] (const Id &block, LogicalModelAssistInterface &logicalApi) {
		if (blocks.contains(block.element())) {
			logicalApi.removeElement(block);
			return true;
		}

		return false;
	};
}

std::function<bool(const qReal::Id &, qReal::LogicalModelAssistInterface &)> SaveConvertionManager::quote(
		const QString &blockType, const QString &property)
{
	return [blockType, property] (const qReal::Id &block, qReal::LogicalModelAssistInterface &logicalApi) {
		if (block.element() == blockType) {
			const QString oldValue = logicalApi.logicalRepoApi().property(block, property).toString();
			if (!oldValue.startsWith("\"")) {
				logicalApi.mutableLogicalRepoApi().setProperty(block, property, "\"" + oldValue + "\"");
				return true;
			}
		}

		return false;
	};
}
<commit_msg>added save converter to a list of converters<commit_after>#include "interpreterCore/managers/saveConvertionManager.h"

using namespace interpreterCore;
using namespace qReal;

QString SaveConvertionManager::editor()
{
	return "RobotsMetamodel";
}

QList<ProjectConverter> SaveConvertionManager::converters()
{
	return { before300Alpha1Converter()
		, from300Alpha4to300Alpha5Converter()
		, from300Beta2to300rc1Converter()
		, from300to301Converter()
		, from301to302Converter()
	};
}

ProjectConverter SaveConvertionManager::before300Alpha1Converter()
{
	return ProjectConverter(editor(), Version(), Version::fromString("3.0.0-a1")
			, [=](const GraphicalModelAssistInterface &graphicalApi, LogicalModelAssistInterface &logicalApi)
	{
		Q_UNUSED(graphicalApi)
		Q_UNUSED(logicalApi)
		return ProjectConverter::VersionTooOld;
	});
}

ProjectConverter SaveConvertionManager::from300Alpha4to300Alpha5Converter()
{
	return constructConverter("3.0.0-a4", "3.0.0-a5"
			, {
				replace({
						{"JA1", "A1"}
						, {"JA2", "A2"}
						, {"JA3", "A3"}
						, {"JA4", "A4"}
						, {"JA5", "A5"}
						, {"JA6", "A6"}

						, {"JD1", "D1"}
						, {"JD2", "D2"}

						, {"JF1", "F1"}

						, {"JM1", "M1"}
						, {"JM2", "M2"}
						, {"JM3", "M3"}
						, {"JM4", "M4"}

						, {"JB1", "B1"}
						, {"JB2", "B2"}
						, {"JB3", "B3"}
						, {"JB4", "B4"}

						, {"JE1", "E1"}
						, {"JE2", "E2"}
						, {"JE3", "E3"}
						, {"JE4", "E4"}

						, {"JC1", "C1"}
						, {"JC2", "C2"}
						, {"JC3", "C3"}

						, {"sensor1", "sensorA1"}
						, {"sensor2", "sensorA2"}
						, {"sensor3", "sensorA3"}
						, {"sensor4", "sensorA4"}
						, {"sensor5", "sensorA5"}
						, {"sensor6", "sensorA6"}

						, {"digitSensor1", "sensorD1"}
						, {"digitSensor2", "sensorD2"}
				})
			}
			, [] (const Id &block) { return block.element().startsWith("Trik"); }
			);

}

ProjectConverter SaveConvertionManager::from300Beta2to300rc1Converter()
{
	return constructConverter("3.0.0-b2", "3.0.0-rc1"
			, { quote("TrikSay", "Text"), quote("PrintText", "PrintText") }
			);
}

qReal::ProjectConverter SaveConvertionManager::from300to301Converter()
{
	return constructConverter("3.0.0", "3.0.1"
			, {
				replace({
						{"enterButton", "buttonEnter"}
						, {"escapeButton", "buttonEscape"}
						, {"leftButton", "buttonLeft"}
						, {"rightButton", "buttonRight"}
						, {"backButton", "buttonBack"}
						, {"downButton", "buttonDown"}
						, {"enterButton", "buttonEnter"}
						, {"upButton", "buttonUp"}
						, {"powerButton", "buttonEsc"}
				  })
				, [=] (const Id &block, LogicalModelAssistInterface &logicalApi) {
						if (block.element().startsWith("Trik")) {
							return replace({{"buttonEscape", "buttonEsc"}})(block, logicalApi);
						}

						return false;
					}
				, deleteBlocks({"Ev3WaitForUp"
						, "Ev3WaitForEnter"
						, "Ev3WaitForDown"
						, "Ev3WaitForRight"
						, "Ev3WaitForLeft"
						, "Ev3WaitForBack"

						, "NxtWaitForEnter"
						, "NxtWaitForEscape"
						, "NxtWaitForLeft"
						, "NxtWaitForRight"

						, "TrikWaitForEnter"
						, "TrikWaitForLeft"
						, "TrikWaitForRight"
						, "TrikWaitForDown"
						, "TrikWaitForUp"
						, "TrikWaitForPower"
						})
			}
			);
}

qReal::ProjectConverter SaveConvertionManager::from301to302Converter()
{
	return constructConverter("3.0.1", "3.0.2", { quote("TrikSystem", "Command") } );
}

bool SaveConvertionManager::isRobotsDiagram(const Id &diagram)
{
	const QStringList robotsDiagrams = { "RobotsDiagram", "SubprogramDiagram" };
	return diagram.editor() == editor() && robotsDiagrams.contains(diagram.diagram());
}

IdList SaveConvertionManager::elementsOfRobotsDiagrams(const LogicalModelAssistInterface &logicalApi)
{
	IdList result;
	for (const Id &diagramId : logicalApi.children(Id::rootId())) {
		if (isRobotsDiagram(diagramId)) {
			result += logicalApi.children(diagramId);
		}
	}

	return result;
}

qReal::ProjectConverter SaveConvertionManager::constructConverter(const QString &oldVersion
		, const QString &newVersion
		, const QList<std::function<bool(const Id &, LogicalModelAssistInterface &)>> &filters
		, const std::function<bool(const qReal::Id &)> &condition
		)
{
	return ProjectConverter(editor(), Version::fromString(oldVersion), Version::fromString(newVersion)
			, [=](const GraphicalModelAssistInterface &graphicalApi, LogicalModelAssistInterface &logicalApi)
	{
		Q_UNUSED(graphicalApi);

		bool modificationsMade = false;

		for (const Id &graphicalBlock : elementsOfRobotsDiagrams(logicalApi)) {
			const Id block = graphicalApi.logicalId(graphicalBlock);

			if (!condition(block)) {
				continue;
			}

			for (const auto &filter : filters) {
				modificationsMade |= filter(block, logicalApi);
			}
		}

		return modificationsMade ? ProjectConverter::Success : ProjectConverter::NoModificationsMade;
	});
}

std::function<bool(const qReal::Id &, qReal::LogicalModelAssistInterface &)> SaveConvertionManager::replace(
		const QMap<QString, QString> &replacementRules)
{
	return [=] (const Id &block, LogicalModelAssistInterface &logicalApi) {
		bool modificationsMade = false;
		QMapIterator<QString, QVariant> iterator = logicalApi.logicalRepoApi().propertiesIterator(block);
		for (iterator.next(); iterator.hasNext(); iterator.next()) {
			const QString name = iterator.key();
			QString value = iterator.value().toString();
			bool replacementOccured = false;
			for (const QString &toReplace : replacementRules.keys()) {
				if (value.contains(toReplace)) {
					replacementOccured = true;
					modificationsMade = true;

					value.replace(toReplace, replacementRules[toReplace]);
				}
			}

			if (replacementOccured) {
				logicalApi.setPropertyByRoleName(block, value, name);
			}
		}

		 return modificationsMade;
	};
}

std::function<bool(const qReal::Id &, qReal::LogicalModelAssistInterface &)>
		SaveConvertionManager::deleteBlocks(const QStringList &blocks)
{
	return [=] (const Id &block, LogicalModelAssistInterface &logicalApi) {
		if (blocks.contains(block.element())) {
			logicalApi.removeElement(block);
			return true;
		}

		return false;
	};
}

std::function<bool(const qReal::Id &, qReal::LogicalModelAssistInterface &)> SaveConvertionManager::quote(
		const QString &blockType, const QString &property)
{
	return [blockType, property] (const qReal::Id &block, qReal::LogicalModelAssistInterface &logicalApi) {
		if (block.element() == blockType) {
			const QString oldValue = logicalApi.logicalRepoApi().property(block, property).toString();
			if (!oldValue.startsWith("\"")) {
				logicalApi.mutableLogicalRepoApi().setProperty(block, property, "\"" + oldValue + "\"");
				return true;
			}
		}

		return false;
	};
}
<|endoftext|>


<commit_before>/*
**  Copyright (C) 2012 Aldebaran Robotics
**  See COPYING for the license
*/
#include <event2/event.h>
#include <event2/bufferevent.h>
#include <event2/thread.h>

#include <boost/thread.hpp>

#include <qi/log.hpp>
#include <qi/application.hpp>

#include <qi/eventloop.hpp>

#include "eventloop_p.hpp"

namespace qi {

  EventLoopPrivate::EventLoopPrivate()
  : _destroyMe(false)
  , _running(false)
  , _threaded(false)
  {
    static bool libevent_init = false;

  #ifdef _WIN32
      // libevent does not call WSAStartup
      WSADATA WSAData;
      // TODO: handle return code
      ::WSAStartup(MAKEWORD(1, 0), &WSAData);
  #endif

    if (!libevent_init)
    {
  #ifdef EVTHREAD_USE_WINDOWS_THREADS_IMPLEMENTED
      evthread_use_windows_threads();
  #endif
  #ifdef EVTHREAD_USE_PTHREADS_IMPLEMENTED
      evthread_use_pthreads();
  #endif
      libevent_init = !libevent_init;
    }

    if (!(_base = event_base_new()))
      return;
  }

  void EventLoopPrivate::start()
  {
    if (_running || _threaded)
      return;
    _threaded = true;
    _thd = boost::thread(&EventLoopPrivate::run, this);
    while (!_running)
      qi::os::msleep(0);
  }

  EventLoopPrivate::~EventLoopPrivate()
  {
    if (_running && boost::this_thread::get_id() != _id)
      qiLogError("Destroying EventLoopPrivate from itself while running");
    stop();
    join();

  #ifdef _WIN32
    // TODO handle return code
    ::WSACleanup();
  #endif
  }

  void EventLoopPrivate::destroy(bool join)
  {
    bool needJoin;
    bool needDelete;
    {
      boost::recursive_mutex::scoped_lock sl(_mutex);
      needJoin = join && _running && (boost::this_thread::get_id() != _id);
      needDelete = needJoin || !_running;
      _destroyMe = !needDelete;
    }
    stop(); // Deadlock if called within the scoped_lock
    if (needJoin)
      this->join();

    if (needDelete)
      delete this;
  }

  void EventLoopPrivate::run()
  {
    qiLogDebug("qi.EventLoop") << this << "run starting";
    _running = true;
    _id = boost::this_thread::get_id();
    // stop will set _base to 0 to delect usage attempts after stop
    // so use a local copy.
    event_base* base = _base;
    // libevent needs a dummy op to perform otherwise dispatch exits immediately
    struct bufferevent *bev = bufferevent_socket_new(base, -1, BEV_OPT_CLOSE_ON_FREE | BEV_OPT_THREADSAFE);
    //bufferevent_setcb(bev, NULL, NULL, ::qi::errorcb, this);
    bufferevent_enable(bev, EV_READ|EV_WRITE);

    event_base_dispatch(base);
    qiLogDebug("qi.EventLoop") << this << "run ending";
    bufferevent_free(bev);
    event_base_free(base);
    _base = 0;
    {
      boost::recursive_mutex::scoped_lock sl(_mutex);
      _running = false;
      if (_destroyMe)
        delete this;
    }
  }

  bool EventLoopPrivate::isInEventLoopThread()
  {
    return boost::this_thread::get_id() == _id;
  }

  void EventLoopPrivate::stop()
  {
    qiLogDebug("qi.EventLoop") << this << "stopping";
    event_base* base = 0;
    { // Ensure no multipe calls are made.
      boost::recursive_mutex::scoped_lock sl(_mutex);
      if (_base && _running)
      {
        base = _base;
        _base = 0;
      }
    }
    if (base)
      if (event_base_loopexit(base, NULL) != 0)
        qiLogError("networkThread") << "Can't stop the EventLoopPrivate";

  }

  void EventLoopPrivate::join()
  {
    if (_base)
      qiLogError("EventLoop") << "join() called before stop()";
    if (boost::this_thread::get_id() == _id)
      return;
    if (_threaded)
      _thd.join();
    else
      while (_running)
        qi::os::msleep(0);
  }

  static void async_call(evutil_socket_t,
    short what,
    void *context)
  {
    EventLoop::AsyncCallHandle* handle = (EventLoop::AsyncCallHandle*)context;
    if (!handle->_p->cancelled)
      handle->_p->callback();
    event_del(handle->_p->ev);
    event_free(handle->_p->ev);
    delete handle;
  }

  static void fduse_call(evutil_socket_t socket,
    short what,
    void *context)
  {
    EventLoop::AsyncCallHandle* handle = (EventLoop::AsyncCallHandle*)context;
    if (!handle->_p->cancelled) {
      if (what & EV_READ)
        handle->_p->fdcallback(socket, EventLoop::FileOperation_Read);
      else if (what & EV_WRITE)
        handle->_p->fdcallback(socket, EventLoop::FileOperation_Write);
      /// If this event is persistant and was not cancelled, do not delete.
      if (handle->_p->persistant)
        return;
    }
    event_del(handle->_p->ev);
    event_free(handle->_p->ev);
    delete handle;
  }

  EventLoop::AsyncCallHandle EventLoopPrivate::asyncCall(uint64_t usDelay, boost::function<void ()> cb)
  {
    EventLoop::AsyncCallHandle res;
    if (!_base) {
      qiLogDebug("eventloop") << "Discarding asyncCall after loop destruction.";
      return res;
    }
    struct timeval period;
    period.tv_sec = static_cast<long>(usDelay / 1000000ULL);
    period.tv_usec = usDelay % 1000000ULL;
    struct event *ev = event_new(_base, -1, 0, async_call,
      new EventLoop::AsyncCallHandle(res));
    // Order is important.
    res._p->ev = ev;
    res._p->cancelled = false;
    std::swap(res._p->callback,cb);
    event_add(ev, &period);
    return res;
  }

  EventLoop::AsyncCallHandle EventLoopPrivate::notifyFd(evutil_socket_t fd, EventLoop::NotifyFdCallbackFunction cb, short evflags, bool persistant)
  {
    EventLoop::AsyncCallHandle res;
    if (!_base) {
      qiLogDebug("eventloop") << "Discarding notifyChange after loop destruction.";
      return res;
    }
    if (persistant)
      evflags |= EV_PERSIST;
    struct event *ev = event_new(_base,
                                 fd,
                                 evflags,
                                 fduse_call,
                                 new EventLoop::AsyncCallHandle(res));
    res._p->ev = ev;
    res._p->cancelled = false;
    res._p->persistant = persistant;
    std::swap(res._p->fdcallback,cb);
    event_add(ev, NULL);
    return res;
  }

   // Basic pimpl bouncers.
  EventLoop::AsyncCallHandle::AsyncCallHandle()
  {
    _p = boost::shared_ptr<AsyncCallHandlePrivate>(new AsyncCallHandlePrivate());
  }

  EventLoop::AsyncCallHandle::~AsyncCallHandle()
  {
  }

  void EventLoop::AsyncCallHandle::cancel()
  {
    _p->cancel();
  }

  EventLoop::EventLoop()
  {
    _p = new EventLoopPrivate();
  }

  EventLoop::~EventLoop()
  {
    _p->destroy(false);
    _p = 0;
  }

  bool EventLoop::isInEventLoopThread()
  {
    return _p->isInEventLoopThread();
  }

  void EventLoop::join()
  {
    _p->join();
  }

  void EventLoop::start()
  {
    _p->start();
  }

  void EventLoop::stop()
  {
    _p->stop();
  }

  void EventLoop::run()
  {
    _p->run();
  }

  void *EventLoop::nativeHandle() {
    return static_cast<void *>(_p->getEventBase());
  }

  EventLoop::AsyncCallHandle
  EventLoop::asyncCall(
    uint64_t usDelay,
    boost::function<void ()> callback)
  {
    return _p->asyncCall(usDelay, callback);
  }

  EventLoop::AsyncCallHandle
  EventLoop::notifyFd(int fileDescriptor,
                      NotifyFdCallbackFunction callback,
                      FileOperation fdUsage)
  {
    switch (fdUsage)
    {
      case FileOperation_Read:
        return _p->notifyFd(static_cast<evutil_socket_t>(fileDescriptor), callback, EV_READ, true);
      case FileOperation_Write:
        return _p->notifyFd(static_cast<evutil_socket_t>(fileDescriptor), callback, EV_WRITE, true);
      case FileOperation_ReadOrWrite:
        return _p->notifyFd(static_cast<evutil_socket_t>(fileDescriptor), callback, EV_READ|EV_WRITE, true);
    }
    return _p->notifyFd(static_cast<evutil_socket_t>(fileDescriptor), callback, EV_READ|EV_WRITE, true);
  }

  static void eventloop_stop(EventLoop* ctx)
  {
    ctx->stop();
    ctx->join();
    delete ctx;
  }

  static EventLoop* _get(EventLoop* &ctx)
  {
    if (!ctx)
    {
      if (! qi::Application::initialized())
      {
        qiLogError("EventLoop") << "EventLoop created before qi::Application()";
      }
      ctx = new EventLoop();
      ctx->start();
      Application::atExit(boost::bind(&eventloop_stop, ctx));
    }
    return ctx;
  }

  static EventLoop* _netEventLoop = 0;
  static EventLoop* _objEventLoop = 0;
  EventLoop* getDefaultNetworkEventLoop()
  {
    return _get(_netEventLoop);
  }

  EventLoop* getDefaultObjectEventLoop()
  {
    return _get(_objEventLoop);
  }

}
<commit_msg>Change log for event loop creation before qi::application initialization<commit_after>/*
**  Copyright (C) 2012 Aldebaran Robotics
**  See COPYING for the license
*/
#include <event2/event.h>
#include <event2/bufferevent.h>
#include <event2/thread.h>

#include <boost/thread.hpp>

#include <qi/log.hpp>
#include <qi/application.hpp>

#include <qi/eventloop.hpp>

#include "eventloop_p.hpp"

namespace qi {

  EventLoopPrivate::EventLoopPrivate()
  : _destroyMe(false)
  , _running(false)
  , _threaded(false)
  {
    static bool libevent_init = false;

  #ifdef _WIN32
      // libevent does not call WSAStartup
      WSADATA WSAData;
      // TODO: handle return code
      ::WSAStartup(MAKEWORD(1, 0), &WSAData);
  #endif

    if (!libevent_init)
    {
  #ifdef EVTHREAD_USE_WINDOWS_THREADS_IMPLEMENTED
      evthread_use_windows_threads();
  #endif
  #ifdef EVTHREAD_USE_PTHREADS_IMPLEMENTED
      evthread_use_pthreads();
  #endif
      libevent_init = !libevent_init;
    }

    if (!(_base = event_base_new()))
      return;
  }

  void EventLoopPrivate::start()
  {
    if (_running || _threaded)
      return;
    _threaded = true;
    _thd = boost::thread(&EventLoopPrivate::run, this);
    while (!_running)
      qi::os::msleep(0);
  }

  EventLoopPrivate::~EventLoopPrivate()
  {
    if (_running && boost::this_thread::get_id() != _id)
      qiLogError("Destroying EventLoopPrivate from itself while running");
    stop();
    join();

  #ifdef _WIN32
    // TODO handle return code
    ::WSACleanup();
  #endif
  }

  void EventLoopPrivate::destroy(bool join)
  {
    bool needJoin;
    bool needDelete;
    {
      boost::recursive_mutex::scoped_lock sl(_mutex);
      needJoin = join && _running && (boost::this_thread::get_id() != _id);
      needDelete = needJoin || !_running;
      _destroyMe = !needDelete;
    }
    stop(); // Deadlock if called within the scoped_lock
    if (needJoin)
      this->join();

    if (needDelete)
      delete this;
  }

  void EventLoopPrivate::run()
  {
    qiLogDebug("qi.EventLoop") << this << "run starting";
    _running = true;
    _id = boost::this_thread::get_id();
    // stop will set _base to 0 to delect usage attempts after stop
    // so use a local copy.
    event_base* base = _base;
    // libevent needs a dummy op to perform otherwise dispatch exits immediately
    struct bufferevent *bev = bufferevent_socket_new(base, -1, BEV_OPT_CLOSE_ON_FREE | BEV_OPT_THREADSAFE);
    //bufferevent_setcb(bev, NULL, NULL, ::qi::errorcb, this);
    bufferevent_enable(bev, EV_READ|EV_WRITE);

    event_base_dispatch(base);
    qiLogDebug("qi.EventLoop") << this << "run ending";
    bufferevent_free(bev);
    event_base_free(base);
    _base = 0;
    {
      boost::recursive_mutex::scoped_lock sl(_mutex);
      _running = false;
      if (_destroyMe)
        delete this;
    }
  }

  bool EventLoopPrivate::isInEventLoopThread()
  {
    return boost::this_thread::get_id() == _id;
  }

  void EventLoopPrivate::stop()
  {
    qiLogDebug("qi.EventLoop") << this << "stopping";
    event_base* base = 0;
    { // Ensure no multipe calls are made.
      boost::recursive_mutex::scoped_lock sl(_mutex);
      if (_base && _running)
      {
        base = _base;
        _base = 0;
      }
    }
    if (base)
      if (event_base_loopexit(base, NULL) != 0)
        qiLogError("networkThread") << "Can't stop the EventLoopPrivate";

  }

  void EventLoopPrivate::join()
  {
    if (_base)
      qiLogError("EventLoop") << "join() called before stop()";
    if (boost::this_thread::get_id() == _id)
      return;
    if (_threaded)
      _thd.join();
    else
      while (_running)
        qi::os::msleep(0);
  }

  static void async_call(evutil_socket_t,
    short what,
    void *context)
  {
    EventLoop::AsyncCallHandle* handle = (EventLoop::AsyncCallHandle*)context;
    if (!handle->_p->cancelled)
      handle->_p->callback();
    event_del(handle->_p->ev);
    event_free(handle->_p->ev);
    delete handle;
  }

  static void fduse_call(evutil_socket_t socket,
    short what,
    void *context)
  {
    EventLoop::AsyncCallHandle* handle = (EventLoop::AsyncCallHandle*)context;
    if (!handle->_p->cancelled) {
      if (what & EV_READ)
        handle->_p->fdcallback(socket, EventLoop::FileOperation_Read);
      else if (what & EV_WRITE)
        handle->_p->fdcallback(socket, EventLoop::FileOperation_Write);
      /// If this event is persistant and was not cancelled, do not delete.
      if (handle->_p->persistant)
        return;
    }
    event_del(handle->_p->ev);
    event_free(handle->_p->ev);
    delete handle;
  }

  EventLoop::AsyncCallHandle EventLoopPrivate::asyncCall(uint64_t usDelay, boost::function<void ()> cb)
  {
    EventLoop::AsyncCallHandle res;
    if (!_base) {
      qiLogDebug("eventloop") << "Discarding asyncCall after loop destruction.";
      return res;
    }
    struct timeval period;
    period.tv_sec = static_cast<long>(usDelay / 1000000ULL);
    period.tv_usec = usDelay % 1000000ULL;
    struct event *ev = event_new(_base, -1, 0, async_call,
      new EventLoop::AsyncCallHandle(res));
    // Order is important.
    res._p->ev = ev;
    res._p->cancelled = false;
    std::swap(res._p->callback,cb);
    event_add(ev, &period);
    return res;
  }

  EventLoop::AsyncCallHandle EventLoopPrivate::notifyFd(evutil_socket_t fd, EventLoop::NotifyFdCallbackFunction cb, short evflags, bool persistant)
  {
    EventLoop::AsyncCallHandle res;
    if (!_base) {
      qiLogDebug("eventloop") << "Discarding notifyChange after loop destruction.";
      return res;
    }
    if (persistant)
      evflags |= EV_PERSIST;
    struct event *ev = event_new(_base,
                                 fd,
                                 evflags,
                                 fduse_call,
                                 new EventLoop::AsyncCallHandle(res));
    res._p->ev = ev;
    res._p->cancelled = false;
    res._p->persistant = persistant;
    std::swap(res._p->fdcallback,cb);
    event_add(ev, NULL);
    return res;
  }

   // Basic pimpl bouncers.
  EventLoop::AsyncCallHandle::AsyncCallHandle()
  {
    _p = boost::shared_ptr<AsyncCallHandlePrivate>(new AsyncCallHandlePrivate());
  }

  EventLoop::AsyncCallHandle::~AsyncCallHandle()
  {
  }

  void EventLoop::AsyncCallHandle::cancel()
  {
    _p->cancel();
  }

  EventLoop::EventLoop()
  {
    _p = new EventLoopPrivate();
  }

  EventLoop::~EventLoop()
  {
    _p->destroy(false);
    _p = 0;
  }

  bool EventLoop::isInEventLoopThread()
  {
    return _p->isInEventLoopThread();
  }

  void EventLoop::join()
  {
    _p->join();
  }

  void EventLoop::start()
  {
    _p->start();
  }

  void EventLoop::stop()
  {
    _p->stop();
  }

  void EventLoop::run()
  {
    _p->run();
  }

  void *EventLoop::nativeHandle() {
    return static_cast<void *>(_p->getEventBase());
  }

  EventLoop::AsyncCallHandle
  EventLoop::asyncCall(
    uint64_t usDelay,
    boost::function<void ()> callback)
  {
    return _p->asyncCall(usDelay, callback);
  }

  EventLoop::AsyncCallHandle
  EventLoop::notifyFd(int fileDescriptor,
                      NotifyFdCallbackFunction callback,
                      FileOperation fdUsage)
  {
    switch (fdUsage)
    {
      case FileOperation_Read:
        return _p->notifyFd(static_cast<evutil_socket_t>(fileDescriptor), callback, EV_READ, true);
      case FileOperation_Write:
        return _p->notifyFd(static_cast<evutil_socket_t>(fileDescriptor), callback, EV_WRITE, true);
      case FileOperation_ReadOrWrite:
        return _p->notifyFd(static_cast<evutil_socket_t>(fileDescriptor), callback, EV_READ|EV_WRITE, true);
    }
    return _p->notifyFd(static_cast<evutil_socket_t>(fileDescriptor), callback, EV_READ|EV_WRITE, true);
  }

  static void eventloop_stop(EventLoop* ctx)
  {
    ctx->stop();
    ctx->join();
    delete ctx;
  }

  static EventLoop* _get(EventLoop* &ctx)
  {
    if (!ctx)
    {
      if (! qi::Application::initialized())
      {
        qiLogInfo("EventLoop") << "Creating event loop while no qi::Application() is running";
      }
      ctx = new EventLoop();
      ctx->start();
      Application::atExit(boost::bind(&eventloop_stop, ctx));
    }
    return ctx;
  }

  static EventLoop* _netEventLoop = 0;
  static EventLoop* _objEventLoop = 0;
  EventLoop* getDefaultNetworkEventLoop()
  {
    return _get(_netEventLoop);
  }

  EventLoop* getDefaultObjectEventLoop()
  {
    return _get(_objEventLoop);
  }

}
<|endoftext|>


<commit_before>//
//  TargetPlatforms.h
//  Clock Signal
//
//  Created by Thomas Harte on 27/08/2017.
//  Copyright 2017 Thomas Harte. All rights reserved.
//

#ifndef TargetPlatforms_hpp
#define TargetPlatforms_hpp

namespace TargetPlatform {

typedef int IntType;

// The below is somehwat overspecified because some of the file formats already supported by this
// emulator can self-specify platforms beyond those the emulator otherwise implements.
enum Type: IntType {
	AmstradCPC		=	1 << 0,
	AppleII			=	1 << 1,
	AppleIIgs		=	1 << 2,
	Atari2600		=	1 << 3,
	AtariST			=	1 << 4,
	AcornAtom		=	1 << 5,
	AcornElectron	=	1 << 6,
	BBCMaster		=	1 << 7,
	BBCModelA		=	1 << 8,
	BBCModelB		=	1 << 9,
	Coleco			=	1 << 10,
	Commodore		=	1 << 11,
	DiskII			=	1 << 12,
	Sega			=	1 << 13,
	Macintosh		=	1 << 14,
	MSX				=	1 << 15,
	Oric			=	1 << 16,
	ZX80			=	1 << 17,
	ZX81			=	1 << 18,
	ZXSpectrum		=	1 << 19,

	Acorn			=	AcornAtom | AcornElectron | BBCMaster | BBCModelA | BBCModelB,
	ZX8081			=	ZX80 | ZX81,
	AllCartridge	=	Atari2600 | AcornElectron | Coleco | MSX,
	AllDisk			=	Acorn | AmstradCPC | Commodore | Oric | MSX,	// TODO: | AtariST
	AllTape			=	Acorn | AmstradCPC | Commodore | Oric | ZX80 | ZX81 | MSX | ZXSpectrum,
};

class TypeDistinguisher {
	public:
		virtual Type target_platform_type() = 0;
};

}

#endif /* TargetPlatforms_h */
<commit_msg>Update AllDisk and AllTape.<commit_after>//
//  TargetPlatforms.h
//  Clock Signal
//
//  Created by Thomas Harte on 27/08/2017.
//  Copyright 2017 Thomas Harte. All rights reserved.
//

#ifndef TargetPlatforms_hpp
#define TargetPlatforms_hpp

namespace TargetPlatform {

typedef int IntType;

// The below is somehwat overspecified because some of the file formats already supported by this
// emulator can self-specify platforms beyond those the emulator otherwise implements.
enum Type: IntType {
	AmstradCPC		=	1 << 0,
	AppleII			=	1 << 1,
	AppleIIgs		=	1 << 2,
	Atari2600		=	1 << 3,
	AtariST			=	1 << 4,
	AcornAtom		=	1 << 5,
	AcornElectron	=	1 << 6,
	BBCMaster		=	1 << 7,
	BBCModelA		=	1 << 8,
	BBCModelB		=	1 << 9,
	Coleco			=	1 << 10,
	Commodore		=	1 << 11,
	DiskII			=	1 << 12,
	Sega			=	1 << 13,
	Macintosh		=	1 << 14,
	MSX				=	1 << 15,
	Oric			=	1 << 16,
	ZX80			=	1 << 17,
	ZX81			=	1 << 18,
	ZXSpectrum		=	1 << 19,

	Acorn			=	AcornAtom | AcornElectron | BBCMaster | BBCModelA | BBCModelB,
	ZX8081			=	ZX80 | ZX81,
	AllCartridge	=	Atari2600 | AcornElectron | Coleco | MSX,
	AllDisk			=	Acorn | AmstradCPC | Commodore | Oric | MSX | ZXSpectrum | Macintosh | AtariST | DiskII,
	AllTape			=	Acorn | AmstradCPC | Commodore | Oric | ZX8081 | MSX | ZXSpectrum,
};

class TypeDistinguisher {
	public:
		virtual Type target_platform_type() = 0;
};

}

#endif /* TargetPlatforms_h */
<|endoftext|>


<commit_before>//
//  exchanger.cpp
//  integral
//
//  Copyright (C) 2013, 2014, 2016  André Pereira Henriques
//  aphenriques (at) outlook (dot) com
//
//  This file is part of integral.
//
//  integral is free software: you can redistribute it and/or modify
//  it under the terms of the GNU General Public License as published by
//  the Free Software Foundation, either version 3 of the License, or
//  (at your option) any later version.
//
//  integral 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 General Public License for more details.
//
//  You should have received a copy of the GNU General Public License
//  along with integral.  If not, see <http://www.gnu.org/licenses/>.
//

#include "exchanger.h"

namespace integral {
    namespace detail {
        namespace exchanger {
            const char * Exchanger<const char *>::get(lua_State *luaState, int index) {
                if (lua_isuserdata(luaState, index) == 0) {
                    const char * const string = lua_tostring(luaState, index);
                    if (string == nullptr) {
                        throw ArgumentException::createTypeErrorException(luaState, index, lua_typename(luaState, LUA_TSTRING));
                    }
                    return string;
                } else {
                    const char **userData = type_manager::getConvertibleType<const char *>(luaState, index);
                    if (userData != nullptr) {
                        return *userData;
                    } else {
                        throw ArgumentException::createTypeErrorException(luaState, index, lua_typename(luaState, LUA_TSTRING));
                    }
                }
            }

            std::string Exchanger<std::string>::get(lua_State *luaState, int index) {
                if (lua_isuserdata(luaState, index) == 0) {
                    const char * const string = lua_tostring(luaState, index);
                    if (string != nullptr) {
                        return string;
                    } else {
                        throw ArgumentException::createTypeErrorException(luaState, index, lua_typename(luaState, LUA_TSTRING));
                    }
                } else {
                    std::string *userData = type_manager::getConvertibleType<std::string>(luaState, index);
                    if (userData != nullptr) {
                        return *userData;
                    } else {
                        throw ArgumentException::createTypeErrorException(luaState, index, lua_typename(luaState, LUA_TSTRING));
                    }
                }
            }

            bool Exchanger<bool>::get(lua_State *luaState, int index) {
                if (lua_isuserdata(luaState, index) == 0) {
                    return lua_toboolean(luaState, index);
                } else {
                    bool *userData = type_manager::getConvertibleType<bool>(luaState, index);
                    if (userData != nullptr) {
                        return *userData;
                    } else {
                        throw ArgumentException::createTypeErrorException(luaState, index, lua_typename(luaState, LUA_TBOOLEAN));
                    }
                }
            }
        }
    }
}
<commit_msg>most frequent code placed first<commit_after>//
//  exchanger.cpp
//  integral
//
//  Copyright (C) 2013, 2014, 2016  André Pereira Henriques
//  aphenriques (at) outlook (dot) com
//
//  This file is part of integral.
//
//  integral is free software: you can redistribute it and/or modify
//  it under the terms of the GNU General Public License as published by
//  the Free Software Foundation, either version 3 of the License, or
//  (at your option) any later version.
//
//  integral 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 General Public License for more details.
//
//  You should have received a copy of the GNU General Public License
//  along with integral.  If not, see <http://www.gnu.org/licenses/>.
//

#include "exchanger.h"

namespace integral {
    namespace detail {
        namespace exchanger {
            const char * Exchanger<const char *>::get(lua_State *luaState, int index) {
                if (lua_isuserdata(luaState, index) == 0) {
                    const char * const string = lua_tostring(luaState, index);
                    if (string != nullptr) {
                        return string;
                    } else {
                        throw ArgumentException::createTypeErrorException(luaState, index, lua_typename(luaState, LUA_TSTRING));
                    }
                } else {
                    const char **userData = type_manager::getConvertibleType<const char *>(luaState, index);
                    if (userData != nullptr) {
                        return *userData;
                    } else {
                        throw ArgumentException::createTypeErrorException(luaState, index, lua_typename(luaState, LUA_TSTRING));
                    }
                }
            }

            std::string Exchanger<std::string>::get(lua_State *luaState, int index) {
                if (lua_isuserdata(luaState, index) == 0) {
                    const char * const string = lua_tostring(luaState, index);
                    if (string != nullptr) {
                        return string;
                    } else {
                        throw ArgumentException::createTypeErrorException(luaState, index, lua_typename(luaState, LUA_TSTRING));
                    }
                } else {
                    std::string *userData = type_manager::getConvertibleType<std::string>(luaState, index);
                    if (userData != nullptr) {
                        return *userData;
                    } else {
                        throw ArgumentException::createTypeErrorException(luaState, index, lua_typename(luaState, LUA_TSTRING));
                    }
                }
            }

            bool Exchanger<bool>::get(lua_State *luaState, int index) {
                if (lua_isuserdata(luaState, index) == 0) {
                    return lua_toboolean(luaState, index);
                } else {
                    bool *userData = type_manager::getConvertibleType<bool>(luaState, index);
                    if (userData != nullptr) {
                        return *userData;
                    } else {
                        throw ArgumentException::createTypeErrorException(luaState, index, lua_typename(luaState, LUA_TBOOLEAN));
                    }
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>/****************************************************************************
 **
 ** Copyright (C) Qxt Foundation. Some rights reserved.
 **
 ** This file is part of the QxtGui module of the Qxt library.
 **
 ** This library is free software; you can redistribute it and/or modify it
 ** under the terms of the Common Public License, version 1.0, as published
 ** by IBM, and/or under the terms of the GNU Lesser General Public License,
 ** version 2.1, as published by the Free Software Foundation.
 **
 ** This file is provided "AS IS", without WARRANTIES OR CONDITIONS OF ANY
 ** KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY
 ** WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR
 ** FITNESS FOR A PARTICULAR PURPOSE.
 **
 ** You should have received a copy of the CPL and the LGPL along with this
 ** file. See the LICENSE file and the cpl1.0.txt/lgpl-2.1.txt files
 ** included with the source distribution for more information.
 ** If you did not receive a copy of the licenses, contact the Qxt Foundation.
 **
 ** <http://libqxt.org>  <foundation@libqxt.org>
 **
 ****************************************************************************/
#include "qxtgroupbox.h"

#include <QChildEvent>

class QxtGroupBoxPrivate : public QxtPrivate<QxtGroupBox>
{
public:
    QXT_DECLARE_PUBLIC(QxtGroupBox);

    QxtGroupBoxPrivate();
    bool collapsive;
    bool flat; // so we can restore it when expanding
};

QxtGroupBoxPrivate::QxtGroupBoxPrivate() : collapsive(true), flat(false)
{}

/*!
    \class QxtGroupBox
    \inmodule QxtGui
    \brief The QxtGroupBox widget is a collapsive and checkable QGroupBox.

    QxtGroupBox is a checkable group box automatically expanding/collapsing
    its content according to the check state. QxtGroupBox shows its children
    when checked and hides its children when unchecked.

    \image qxtgroupbox.png "Two QxtGroupBoxes - an expanded and a collapsed - on top of each other."
 */

/*!
    Constructs a new QxtGroupBox with \a parent.
 */
QxtGroupBox::QxtGroupBox(QWidget* parent)
        : QGroupBox(parent)
{
    QXT_INIT_PRIVATE(QxtGroupBox);
    setCheckable(true);
    setChecked(true);
    connect(this, SIGNAL(toggled(bool)), this, SLOT(setExpanded(bool)));

}

/*!
    Constructs a new QxtGroupBox with \a title and \a parent.
 */
QxtGroupBox::QxtGroupBox(const QString& title, QWidget* parent)
        : QGroupBox(title, parent)
{
    QXT_INIT_PRIVATE(QxtGroupBox);
    setCheckable(true);
    setChecked(true);
    connect(this, SIGNAL(toggled(bool)), this, SLOT(setExpanded(bool)));
}

/*!
    Destructs the group box.
 */
QxtGroupBox::~QxtGroupBox()
{}

/*!
    \property QxtGroupBox::collapsive
    \brief whether the group box is collapsive
 */
bool QxtGroupBox::isCollapsive() const
{
    return qxt_d().collapsive;
}

void QxtGroupBox::setCollapsive(bool enable)
{
    if (qxt_d().collapsive != enable)
    {
        qxt_d().collapsive = enable;
        if (!enable)
            setExpanded(true);
        else if (!isChecked())
            setExpanded(false);
    }
}

/*!
    Sets the group box \a collapsed.

    A collapsed group box hides its children.

    \sa setExpanded(), QGroupBox::toggled()
 */
void QxtGroupBox::setCollapsed(bool collapsed)
{
    setExpanded(!collapsed);
}

/*!
    Sets the group box \a expanded.

    An expanded group box shows its children.

    \sa setCollapsed(), QGroupBox::toggled()
 */
void QxtGroupBox::setExpanded(bool expanded)
{
    if (qxt_d().collapsive || expanded)
    {
        // show/hide direct children
        foreach(QObject* child, children())
        {
            if (child->isWidgetType())
                static_cast<QWidget*>(child)->setVisible(expanded);
        }
        if (expanded) {
          setFlat(qxt_d().flat);
        } else {
          qxt_d().flat = isFlat();
          setFlat(true);
        }
    }
}

/*!
    \reimp
 */
void QxtGroupBox::childEvent(QChildEvent* event)
{
    QObject* child = event->child();
    if (event->added() && child->isWidgetType())
    {
        QWidget* widget = static_cast<QWidget*>(child);
        if (qxt_d().collapsive && !isChecked())
            widget->hide();
    }
}
<commit_msg>Revised QxtGroupBox docs.<commit_after>/****************************************************************************
 **
 ** Copyright (C) Qxt Foundation. Some rights reserved.
 **
 ** This file is part of the QxtGui module of the Qxt library.
 **
 ** This library is free software; you can redistribute it and/or modify it
 ** under the terms of the Common Public License, version 1.0, as published
 ** by IBM, and/or under the terms of the GNU Lesser General Public License,
 ** version 2.1, as published by the Free Software Foundation.
 **
 ** This file is provided "AS IS", without WARRANTIES OR CONDITIONS OF ANY
 ** KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY
 ** WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR
 ** FITNESS FOR A PARTICULAR PURPOSE.
 **
 ** You should have received a copy of the CPL and the LGPL along with this
 ** file. See the LICENSE file and the cpl1.0.txt/lgpl-2.1.txt files
 ** included with the source distribution for more information.
 ** If you did not receive a copy of the licenses, contact the Qxt Foundation.
 **
 ** <http://libqxt.org>  <foundation@libqxt.org>
 **
 ****************************************************************************/
#include "qxtgroupbox.h"

#include <QChildEvent>

class QxtGroupBoxPrivate : public QxtPrivate<QxtGroupBox>
{
public:
    QXT_DECLARE_PUBLIC(QxtGroupBox);

    QxtGroupBoxPrivate();
    bool collapsive;
    bool flat; // so we can restore it when expanding
};

QxtGroupBoxPrivate::QxtGroupBoxPrivate() : collapsive(true), flat(false)
{}

/*!
    \class QxtGroupBox
    \inmodule QxtGui
    \brief The QxtGroupBox widget is a collapsive and checkable QGroupBox.

    QxtGroupBox is a checkable group box automatically expanding/collapsing
    its content according to the check state. QxtGroupBox shows its children
    when checked and hides its children when unchecked.

    \image qxtgroupbox.png "Two QxtGroupBoxes - an expanded and a collapsed - on top of each other."
 */

/*!
    Constructs a new QxtGroupBox with \a parent.
 */
QxtGroupBox::QxtGroupBox(QWidget* parent)
        : QGroupBox(parent)
{
    QXT_INIT_PRIVATE(QxtGroupBox);
    setCheckable(true);
    setChecked(true);
    connect(this, SIGNAL(toggled(bool)), this, SLOT(setExpanded(bool)));

}

/*!
    Constructs a new QxtGroupBox with \a title and \a parent.
 */
QxtGroupBox::QxtGroupBox(const QString& title, QWidget* parent)
        : QGroupBox(title, parent)
{
    QXT_INIT_PRIVATE(QxtGroupBox);
    setCheckable(true);
    setChecked(true);
    connect(this, SIGNAL(toggled(bool)), this, SLOT(setExpanded(bool)));
}

/*!
    Destructs the group box.
 */
QxtGroupBox::~QxtGroupBox()
{}

/*!
    \property QxtGroupBox::collapsive
    \brief whether the group box is collapsive

    The default value is \c true.
 */
bool QxtGroupBox::isCollapsive() const
{
    return qxt_d().collapsive;
}

void QxtGroupBox::setCollapsive(bool enable)
{
    if (qxt_d().collapsive != enable)
    {
        qxt_d().collapsive = enable;
        if (!enable)
            setExpanded(true);
        else if (!isChecked())
            setExpanded(false);
    }
}

/*!
    Sets the group box \a collapsed.

    A collapsed group box hides its children.

    \sa setExpanded(), QGroupBox::toggled()
 */
void QxtGroupBox::setCollapsed(bool collapsed)
{
    setExpanded(!collapsed);
}

/*!
    Sets the group box \a expanded.

    An expanded group box shows its children.

    \sa setCollapsed(), QGroupBox::toggled()
 */
void QxtGroupBox::setExpanded(bool expanded)
{
    if (qxt_d().collapsive || expanded)
    {
        // show/hide direct children
        foreach(QObject* child, children())
        {
            if (child->isWidgetType())
                static_cast<QWidget*>(child)->setVisible(expanded);
        }
        if (expanded) {
          setFlat(qxt_d().flat);
        } else {
          qxt_d().flat = isFlat();
          setFlat(true);
        }
    }
}

/*!
    \reimp
 */
void QxtGroupBox::childEvent(QChildEvent* event)
{
    QObject* child = event->child();
    if (event->added() && child->isWidgetType())
    {
        QWidget* widget = static_cast<QWidget*>(child);
        if (qxt_d().collapsive && !isChecked())
            widget->hide();
    }
}
<|endoftext|>


<commit_before>#include "cnn/cnn.h"
#include "cnn/training.h"
#include "cnn/expr.h"
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/algorithm/string.hpp>

#include <sys/types.h>
#include <sys/wait.h>
#include <sys/shm.h>
#include <iostream>
#include <fstream>
#include <vector>
#include <utility>
#include <sstream>
#include <random>
/*
TODO:
- Can we move the data vector into shared memory so that we can shuffle it
  between iterations and not have to send huge vectors of integers around?
- Can we use some sort of shared memory queue to allow threads to spread
  work more evenly?
- The shadow params in the trainers need to be shared.
*/

using namespace std;
using namespace cnn;
using namespace cnn::expr;

typedef pair<cnn::real, cnn::real> Datum;
const unsigned num_children = 8;

// This shared object/shared memory stuff is junk now
// It used to be useful, but now I'm just leaving it here
// so that I don't have to look up how to do all tis stuff
// in case I ever need to use it again.
struct SharedObject {
  cnn::real fake;
};
SharedObject* shared_memory = nullptr;
SharedObject* GetSharedMemory() {
  unsigned shm_size = 1024;
  assert (sizeof(SharedObject) < shm_size);
  key_t shm_key = ftok("/Users/austinma/shared2", 'R');
  if (shm_key == -1) {
    cerr << "Unable to get shared memory key" << endl;
    return NULL;
  }
  int shm_id = shmget(shm_key, shm_size, 0644 | IPC_CREAT);
  if (shm_id == -1) {
    cerr << "Unable to create shared memory" << endl;
    return NULL;
  }
  void* shm_p = shmat(shm_id, nullptr, 0);
  if (shm_p == (void*)-1) {
    cerr << "Unable to get shared memory pointer";
    return NULL;
  }
  return (SharedObject*)shm_p;
}

// Some simple functions that do IO to/from pipes.
// These are used to send data from child processes
// to the parent process or vice/versa.
cnn::real ReadReal(int pipe) {
  cnn::real v;
  read(pipe, &v, sizeof(cnn::real));
  return v;
}

void WriteReal(int pipe, cnn::real v) {
  write(pipe, &v, sizeof(cnn::real));
}

template <typename T>
void WriteIntVector(int pipe, const vector<T>& vec) {
  unsigned length = vec.size();
  write(pipe, &length, sizeof(unsigned));
  for (T v : vec) {
    write(pipe, &v, sizeof(T));
  }
}

template<typename T>
vector<T> ReadIntVector(int pipe) {
  unsigned length;
  read(pipe, &length, sizeof(unsigned));
  vector<T> vec(length);
  for (unsigned i = 0; i < length; ++i) {
    read(pipe, &vec[i], sizeof(T));
  }
  return vec;
}

cnn::real SumValues(const vector<cnn::real>& values) {
  return accumulate(values.begin(), values.end(), 0.0);
}

cnn::real Mean(const vector<cnn::real>& values) {
  return SumValues(values) / values.size();
}

struct Workload {
  pid_t pid;
  int c2p[2]; // Child to parent pipe
  int p2c[2]; // Parent to child pipe
};

struct ModelParameters {
  Parameters* m;
  Parameters* b;
};

void BuildComputationGraph(ComputationGraph& cg, ModelParameters& model_parameters, cnn::real* x_value, cnn::real* y_value) {
  Expression m = parameter(cg, model_parameters.m);
  Expression b = parameter(cg, model_parameters.b);

  Expression x = input(cg, x_value);
  Expression y_star = input(cg, y_value);
  Expression y = m * x + b;
  Expression loss = squared_distance(y, y_star);
}

vector<Datum> ReadData(string filename) {
  vector<Datum> data;
  ifstream fs(filename);
  if (!fs.is_open()) {
    cerr << "ERROR: Unable to open " << filename << endl;
    exit(1);
  }
  string line;
  while (getline(fs, line)) {
    if (line.size() > 0 && line[0] == '#') {
      continue;
    }
    vector<string> parts;
    boost::split(parts, line, boost::is_any_of("\t"));
    data.push_back(make_pair(atof(parts[0].c_str()), atof(parts[1].c_str())));
  }
  return data;
}

unsigned SpawnChildren(vector<Workload>& workloads) {
  assert (workloads.size() == num_children);
  pid_t pid;
  unsigned cid;
  for (cid = 0; cid < num_children; ++cid) {
    pid = fork();
    if (pid == -1) {
      cerr << "Fork failed. Exiting ...";
      return 1;
    }
    else if (pid == 0) {
      // children shouldn't continue looping
      break;
    }
    workloads[cid].pid = pid;
  }
  return cid;
}

int RunChild(unsigned cid, ComputationGraph& cg, Trainer* trainer, vector<Workload>& workloads,
    const vector<Datum>& data, cnn::real& x_value, cnn::real& y_value, ModelParameters& model_params) {
  assert (cid >= 0 && cid < num_children);
  while (true) {
    // Check if the parent wants us to exit
    bool cont = false;
    read(workloads[cid].p2c[0], &cont, sizeof(bool));
    if (!cont) {
      break;
    }

    // Read in our workload and update our local model
    vector<unsigned> indices = ReadIntVector<unsigned>(workloads[cid].p2c[0]);

    // Run the actual training loop
    cnn::real loss = 0;
    for (unsigned i : indices) {
      assert (i < data.size());
      auto p = data[i];
      x_value = get<0>(p);
      y_value = get<1>(p);
      loss += as_scalar(cg.forward());
      cg.backward();
      trainer->update(1.0);
    }
    trainer->update_epoch();

    cnn::real m = as_scalar(model_params.m->values);
    cnn::real b = as_scalar(model_params.b->values);

    // Let the parent know that we're done and return the loss value
    WriteReal(workloads[cid].c2p[1], m);
    WriteReal(workloads[cid].c2p[1], b);
    WriteReal(workloads[cid].c2p[1], loss);
  }
  return 0;
}

void RunParent(vector<Datum>& data, unsigned num_iterations, vector<Workload>& workloads, ModelParameters& model_params, Trainer* trainer) {
  for (unsigned iter = 0; iter < num_iterations; ++iter) {
    vector<cnn::real> ms(num_children);
    vector<cnn::real> bs(num_children);
    vector<cnn::real> losses(num_children);
    vector<unsigned> indices(data.size());
    for (unsigned i = 0; i < data.size(); ++i) {
      indices[i] = i;
    }
    random_shuffle(indices.begin(), indices.end());

    for(unsigned cid = 0; cid < num_children; ++cid) {
      // work out the indices of the data points we want this child to consider
      unsigned start = (unsigned)(1.0 * cid / num_children * data.size() + 0.5);
      unsigned end = (unsigned)(1.0 * (cid + 1) / num_children * data.size() + 0.5);
      vector<unsigned> child_indices;
      child_indices.reserve(end - start);
      for (unsigned i = start; i < end; ++i) {
        child_indices.push_back(indices[i]);
      }
      // Tell the child it's not time to quit yet
      bool cont = true;
      write(workloads[cid].p2c[1], &cont, sizeof(bool));
      WriteIntVector(workloads[cid].p2c[1], child_indices);
    }

    // Wait for each child to finish training its load
    for(unsigned cid = 0; cid < num_children; ++cid) {
      ms[cid] = ReadReal(workloads[cid].c2p[0]);
      bs[cid] = ReadReal(workloads[cid].c2p[0]);
      losses[cid] = ReadReal(workloads[cid].c2p[0]);
    }

    cerr << "ID\tm\tb\tloss" << endl;
    cerr << "============================" << endl;
    for (unsigned cid = 0; cid < num_children; ++cid) {
      cerr << cid << "\t" << ms[cid] << "\t" << bs[cid] << "\t" << losses[cid] << endl;
    }

    // TODO: This is currently uneffective because it doesn't affect the Trainers on the child processes
    trainer->update_epoch();

    cnn::real loss = SumValues(losses) / data.size();
    cerr << iter << "\t" << "loss = " << loss << endl;
  }

  // Kill all children one by one and wait for them to exit
  for (unsigned cid = 0; cid < num_children; ++cid) {
    bool cont = false;
    write(workloads[cid].p2c[1], &cont, sizeof(cont));
    wait(NULL);
  }

  cnn::Cleanup();
}

int main(int argc, char** argv) {
  cnn::Initialize(argc, argv, 0, true);

  if (argc < 2) {
    cerr << "Usage: " << argv[0] << " data.txt" << endl;
    cerr << "Where data.txt contains tab-delimited pairs of floats." << endl;
    return 1;
  }
  unsigned num_iterations = (argc >= 3) ? atoi(argv[2]) : 10;
  vector<Datum> data = ReadData(argv[1]);
  vector<Workload> workloads(num_children);

  Model model;
  //SimpleSGDTrainer sgd(&model, 0.0, 0.001);
  AdamTrainer sgd(&model, 0.0);

  ComputationGraph cg;
  cnn::real x_value, y_value;
  Parameters* m_param = model.add_parameters({1, 1});
  Parameters* b_param = model.add_parameters({1});
  ModelParameters model_params = {m_param, b_param};
  BuildComputationGraph(cg, model_params, &x_value, &y_value);

  shared_memory = GetSharedMemory();

  for (unsigned cid = 0; cid < num_children; cid++) {
    pipe(workloads[cid].p2c);
    pipe(workloads[cid].c2p);
  }

  unsigned cid = SpawnChildren(workloads);
  if (cid < num_children) {
    return RunChild(cid, cg, &sgd, workloads, data, x_value, y_value, model_params);
  }
  else {
    RunParent(data, num_iterations, workloads, model_params, &sgd);
  }
}
<commit_msg>mp example now trains an RNN language model<commit_after>#include "cnn/cnn.h"
#include "cnn/training.h"
#include "cnn/expr.h"
#include "cnn/dict.h"
#include "cnn/lstm.h"
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/algorithm/string.hpp>

#include <sys/types.h>
#include <sys/wait.h>
#include <sys/shm.h>
#include <iostream>
#include <fstream>
#include <vector>
#include <utility>
#include <sstream>
#include <random>
/*
TODO:
- Can we move the data vector into shared memory so that we can shuffle it
  between iterations and not have to send huge vectors of integers around?
- Can we use some sort of shared memory queue to allow threads to spread
  work more evenly?
- The shadow params in the trainers need to be shared.
*/

using namespace std;
using namespace cnn;
using namespace cnn::expr;

typedef vector<int> Datum;
unsigned num_children = 1;

// Some simple functions that do IO to/from pipes.
// These are used to send data from child processes
// to the parent process or vice/versa.
cnn::real ReadReal(int pipe) {
  cnn::real v;
  read(pipe, &v, sizeof(cnn::real));
  return v;
}

void WriteReal(int pipe, cnn::real v) {
  write(pipe, &v, sizeof(cnn::real));
}

template <typename T>
void WriteIntVector(int pipe, const vector<T>& vec) {
  unsigned length = vec.size();
  write(pipe, &length, sizeof(unsigned));
  for (T v : vec) {
    write(pipe, &v, sizeof(T));
  }
}

template<typename T>
vector<T> ReadIntVector(int pipe) {
  unsigned length;
  read(pipe, &length, sizeof(unsigned));
  vector<T> vec(length);
  for (unsigned i = 0; i < length; ++i) {
    read(pipe, &vec[i], sizeof(T));
  }
  return vec;
}

cnn::real SumValues(const vector<cnn::real>& values) {
  return accumulate(values.begin(), values.end(), 0.0);
}

cnn::real Mean(const vector<cnn::real>& values) {
  return SumValues(values) / values.size();
}

struct Workload {
  pid_t pid;
  int c2p[2]; // Child to parent pipe
  int p2c[2]; // Parent to child pipe
};

unsigned LAYERS = 2;
unsigned INPUT_DIM = 8;  //256
unsigned HIDDEN_DIM = 24;  // 1024
unsigned VOCAB_SIZE = 5500;

cnn::Dict d;
int kSOS;
int kEOS;

template <class Builder>
struct RNNLanguageModel {
  LookupParameters* p_c;
  Parameters* p_R;
  Parameters* p_bias;
  Builder builder;
  explicit RNNLanguageModel(Model& model) : builder(LAYERS, INPUT_DIM, HIDDEN_DIM, &model) {
    p_c = model.add_lookup_parameters(VOCAB_SIZE, {INPUT_DIM});
    p_R = model.add_parameters({VOCAB_SIZE, HIDDEN_DIM});
    p_bias = model.add_parameters({VOCAB_SIZE});
  }

  // return Expression of total loss
  Expression BuildLMGraph(const vector<int>& sent, ComputationGraph& cg) {
    const unsigned slen = sent.size() - 1;
    builder.new_graph(cg);  // reset RNN builder for new graph
    builder.start_new_sequence();
    Expression i_R = parameter(cg, p_R); // hidden -> word rep parameter
    Expression i_bias = parameter(cg, p_bias);  // word bias
    vector<Expression> errs;
    for (unsigned t = 0; t < slen; ++t) {
      Expression i_x_t = lookup(cg, p_c, sent[t]);
      // y_t = RNN(x_t)
      Expression i_y_t = builder.add_input(i_x_t);
      Expression i_r_t =  i_bias + i_R * i_y_t;

      // LogSoftmax followed by PickElement can be written in one step
      // using PickNegLogSoftmax
      Expression i_err = pickneglogsoftmax(i_r_t, sent[t+1]);
      errs.push_back(i_err);
    }
    Expression i_nerr = sum(errs);
    return i_nerr;
  }

  // return Expression for total loss
  void RandomSample(int max_len = 150) {
    cerr << endl;
    ComputationGraph cg;
    builder.new_graph(cg);  // reset RNN builder for new graph
    builder.start_new_sequence();

    Expression i_R = parameter(cg, p_R);
    Expression i_bias = parameter(cg, p_bias);
    vector<Expression> errs;
    int len = 0;
    int cur = kSOS;
    while(len < max_len && cur != kEOS) {
      ++len;
      Expression i_x_t = lookup(cg, p_c, cur);
      // y_t = RNN(x_t)
      Expression i_y_t = builder.add_input(i_x_t);
      Expression i_r_t = i_bias + i_R * i_y_t;

      Expression ydist = softmax(i_r_t);

      unsigned w = 0;
      while (w == 0 || (int)w == kSOS) {
        auto dist = as_vector(cg.incremental_forward());
        double p = rand01();
        for (; w < dist.size(); ++w) {
          p -= dist[w];
          if (p < 0.0) { break; }
        }
        if (w == dist.size()) w = kEOS;
      }
      cerr << (len == 1 ? "" : " ") << d.Convert(w);
      cur = w;
    }
    cerr << endl;
  }
};

vector<Datum> ReadData(string filename) {
  vector<Datum> data;
  ifstream fs(filename);
  if (!fs.is_open()) {
    cerr << "ERROR: Unable to open " << filename << endl;
    exit(1);
  }
  string line;
  while (getline(fs, line)) {
    data.push_back(ReadSentence(line, &d));
  }
  return data;
}

unsigned SpawnChildren(vector<Workload>& workloads) {
  assert (workloads.size() == num_children);
  pid_t pid;
  unsigned cid;
  for (cid = 0; cid < num_children; ++cid) {
    pid = fork();
    if (pid == -1) {
      cerr << "Fork failed. Exiting ...";
      return 1;
    }
    else if (pid == 0) {
      // children shouldn't continue looping
      break;
    }
    workloads[cid].pid = pid;
  }
  return cid;
}

template <class T>
int RunChild(unsigned cid, RNNLanguageModel<T>& rnnlm, Trainer* trainer, vector<Workload>& workloads,
    const vector<Datum>& data) {
  assert (cid >= 0 && cid < num_children);
  while (true) {
    // Check if the parent wants us to exit
    bool cont = false;
    read(workloads[cid].p2c[0], &cont, sizeof(bool));
    if (!cont) {
      break;
    }

    // Read in our workload and update our local model
    vector<unsigned> indices = ReadIntVector<unsigned>(workloads[cid].p2c[0]);

    // Run the actual training loop
    cnn::real loss = 0;
    for (unsigned i : indices) {
      assert (i < data.size());
      const Datum& datum = data[i];
      ComputationGraph cg;
      rnnlm.BuildLMGraph(datum, cg);
      loss += as_scalar(cg.forward());
      cg.backward();
      trainer->update(1.0);
    }
    trainer->update_epoch();

    // Let the parent know that we're done and return the loss value
    WriteReal(workloads[cid].c2p[1], loss);
  }
  return 0;
}

void RunParent(vector<Datum>& data, vector<Datum>& dev_data, vector<Workload>& workloads) {
  for (unsigned iter = 0; iter < 0; ++iter) {
    vector<unsigned> indices(data.size());
    for (unsigned i = 0; i < data.size(); ++i) {
      indices[i] = i;
    }
    random_shuffle(indices.begin(), indices.end());

    for(unsigned cid = 0; cid < num_children; ++cid) {
      // work out the indices of the data points we want this child to consider
      unsigned start = (unsigned)(1.0 * cid / num_children * data.size() + 0.5);
      unsigned end = (unsigned)(1.0 * (cid + 1) / num_children * data.size() + 0.5);
      vector<unsigned> child_indices;
      child_indices.reserve(end - start);
      for (unsigned i = start; i < end; ++i) {
        child_indices.push_back(indices[i]);
      }
      // Tell the child it's not time to quit yet
      bool cont = true;
      write(workloads[cid].p2c[1], &cont, sizeof(bool));
      WriteIntVector(workloads[cid].p2c[1], child_indices);
    }

    // Wait for each child to finish training its load
    vector<cnn::real> losses(num_children);
    for(unsigned cid = 0; cid < num_children; ++cid) {
      losses[cid] = ReadReal(workloads[cid].c2p[0]);
    }

    cnn::real loss = SumValues(losses) / data.size();
    cerr << iter << "\t" << "loss = " << loss << endl;
  }

  // Kill all children one by one and wait for them to exit
  for (unsigned cid = 0; cid < num_children; ++cid) {
    bool cont = false;
    write(workloads[cid].p2c[1], &cont, sizeof(cont));
    wait(NULL);
  }

  cnn::Cleanup();
}

int main(int argc, char** argv) {
  cnn::Initialize(argc, argv, 0, true);

  if (argc < 4) {
    cerr << "Usage: " << argv[0] << " cores corpus.txt dev.txt" << endl;
    return 1;
  }
  num_children = atoi(argv[1]);
  kSOS = d.Convert("<s>");
  kEOS = d.Convert("</s>");
  assert (num_children > 0 && num_children <= 64);

  vector<Datum> data = ReadData(argv[2]);
  vector<Datum> dev_data = ReadData(argv[3]);
  vector<Workload> workloads(num_children);

  Model model;
  SimpleSGDTrainer sgd(&model, 0.0);
  //AdamTrainer sgd(&model, 0.0);

  RNNLanguageModel<LSTMBuilder> rnnlm(model);

  for (unsigned cid = 0; cid < num_children; cid++) {
    pipe(workloads[cid].p2c);
    pipe(workloads[cid].c2p);
  }

  unsigned cid = SpawnChildren(workloads);
  if (cid < num_children) {
    return RunChild(cid, rnnlm, &sgd, workloads, data);
  }
  else {
    RunParent(data, dev_data, workloads);
  }
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2017-2018 Daniel Nicoletti <dantti12@gmail.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */
#include "enginerequest.h"

#include "common.h"

#include <Cutelyst/response_p.h>
#include <Cutelyst/Context>

#include <QLoggingCategory>
Q_LOGGING_CATEGORY(CUTELYST_ENGINEREQUEST, "cutelyst.engine_request", QtWarningMsg)

using namespace Cutelyst;

EngineRequest::EngineRequest()
{

}

EngineRequest::~EngineRequest()
{
    delete body;
    delete context;
}

void EngineRequest::finalizeBody()
{
    if (!(status & EngineRequest::Chunked)) {
        Response *response = context->response();
        QIODevice *body = response->bodyDevice();

        if (body) {
            body->seek(0);
            char block[64 * 1024];
            while (!body->atEnd()) {
                qint64 in = body->read(block, sizeof(block));
                if (in <= 0) {
                    break;
                }

                if (write(block, in) != in) {
                    qCWarning(CUTELYST_ENGINEREQUEST) << "Failed to write body";
                    break;
                }
            }
        } else {
            const QByteArray bodyByteArray = response->body();
            write(bodyByteArray.constData(), bodyByteArray.size());
        }
    } else if (!(status & EngineRequest::ChunkedDone)) {
        // Write the final '0' chunk
        doWrite("0\r\n\r\n", 5);
    }
}

void EngineRequest::finalizeError()
{
    Response *res = context->response();

    res->setContentType(QStringLiteral("text/html; charset=utf-8"));

    QByteArray body;

    // Trick IE. Old versions of IE would display their own error page instead
    // of ours if we'd give it less than 512 bytes.
    body.reserve(512);

    body.append(context->errors().join(QLatin1Char('\n')).toUtf8());

    res->setBody(body);

    // Return 500
    res->setStatus(Response::InternalServerError);
}

void EngineRequest::finalize()
{
    if (context->error()) {
        finalizeError();
    }

    if (!(status & EngineRequest::FinalizedHeaders) && !finalizeHeaders()) {
        return;
    }

    finalizeBody();
}

void EngineRequest::finalizeCookies()
{
    Response *res = context->response();
    Headers &headers = res->headers();
    const auto cookies = res->cookies();
    for (const QNetworkCookie &cookie : cookies) {
        headers.pushHeader(QStringLiteral("SET_COOKIE"), QString::fromLatin1(cookie.toRawForm()));
    }
}

bool EngineRequest::finalizeHeaders()
{
    Response *response = context->response();
    Headers &headers = response->headers();

    // Fix missing content length
    if (headers.contentLength() < 0) {
        qint64 size = response->size();
        if (size >= 0) {
            headers.setContentLength(size);
        }
    }

    finalizeCookies();

    // Done
    status |= EngineRequest::FinalizedHeaders;
    return writeHeaders(response->status(), headers);
}

qint64 EngineRequest::write(const char *data, qint64 len)
{
    if (!(status & EngineRequest::Chunked)) {
        return doWrite(data, len);
    } else if (!(status & EngineRequest::ChunkedDone)) {
        const QByteArray chunkSize = QByteArray::number(len, 16).toUpper();
        QByteArray chunk;
        chunk.reserve(len + chunkSize.size() + 4);
        chunk.append(chunkSize).append("\r\n", 2)
                .append(data, len).append("\r\n", 2);

        qint64 retWrite = doWrite(chunk.data(), chunk.size());

        // Flag if we wrote an empty chunk
        if (!len) {
            status |= EngineRequest::ChunkedDone;
        }

        return retWrite == chunk.size() ? len : -1;
    }
    return -1;
}

bool EngineRequest::webSocketHandshake(const QString &key, const QString &origin, const QString &protocol)
{
    if (status & EngineRequest::FinalizedHeaders) {
        return false;
    }

    if (webSocketHandshakeDo(key, origin, protocol)) {
        status |= EngineRequest::FinalizedHeaders;
        return true;
    }

    return false;
}

bool EngineRequest::webSocketSendTextMessage(const QString &message)
{
    Q_UNUSED(message)
    return false;
}

bool EngineRequest::webSocketSendBinaryMessage(const QByteArray &message)
{
    Q_UNUSED(message)
    return false;
}

bool EngineRequest::webSocketSendPing(const QByteArray &payload)
{
    Q_UNUSED(payload)
    return false;
}

bool EngineRequest::webSocketClose(quint16 code, const QString &reason)
{
    Q_UNUSED(code)
    Q_UNUSED(reason)
    return false;
}

void EngineRequest::processingFinished()
{
}

bool EngineRequest::webSocketHandshakeDo(const QString &key, const QString &origin, const QString &protocol)
{
    Q_UNUSED(key)
    Q_UNUSED(origin)
    Q_UNUSED(protocol)
    return false;
}

void EngineRequest::setPath(char *rawPath, const int len)
{
    qDebug() << "PATH" << QByteArray(rawPath, len);
    if (len == 0) {
        return;
    }

    char *data = rawPath;
    const char *inputPtr = data;

    bool skipUtf8 = true;
    int outlen = 0;
    for (int i = 0; i < len; ++i, ++outlen) {
        const char c = inputPtr[i];
        if (c == '%' && i + 2 < len) {
            int a = inputPtr[++i];
            int b = inputPtr[++i];

            if (a >= '0' && a <= '9') a -= '0';
            else if (a >= 'a' && a <= 'f') a = a - 'a' + 10;
            else if (a >= 'A' && a <= 'F') a = a - 'A' + 10;

            if (b >= '0' && b <= '9') b -= '0';
            else if (b >= 'a' && b <= 'f') b  = b - 'a' + 10;
            else if (b >= 'A' && b <= 'F') b  = b - 'A' + 10;

            *data++ = (char)((a << 4) | b);
            skipUtf8 = false;
        } else if (c == '+') {
            *data++ = ' ';
        } else {
            *data++ = c;
        }
    }

    if (skipUtf8) {
        path = QString::fromLatin1(rawPath, outlen);
    } else {
        path = QString::fromUtf8(rawPath, outlen);
    }
}

#include "moc_enginerequest.cpp"
<commit_msg>remove debug info<commit_after>/*
 * Copyright (C) 2017-2018 Daniel Nicoletti <dantti12@gmail.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */
#include "enginerequest.h"

#include "common.h"

#include <Cutelyst/response_p.h>
#include <Cutelyst/Context>

#include <QLoggingCategory>
Q_LOGGING_CATEGORY(CUTELYST_ENGINEREQUEST, "cutelyst.engine_request", QtWarningMsg)

using namespace Cutelyst;

EngineRequest::EngineRequest()
{

}

EngineRequest::~EngineRequest()
{
    delete body;
    delete context;
}

void EngineRequest::finalizeBody()
{
    if (!(status & EngineRequest::Chunked)) {
        Response *response = context->response();
        QIODevice *body = response->bodyDevice();

        if (body) {
            body->seek(0);
            char block[64 * 1024];
            while (!body->atEnd()) {
                qint64 in = body->read(block, sizeof(block));
                if (in <= 0) {
                    break;
                }

                if (write(block, in) != in) {
                    qCWarning(CUTELYST_ENGINEREQUEST) << "Failed to write body";
                    break;
                }
            }
        } else {
            const QByteArray bodyByteArray = response->body();
            write(bodyByteArray.constData(), bodyByteArray.size());
        }
    } else if (!(status & EngineRequest::ChunkedDone)) {
        // Write the final '0' chunk
        doWrite("0\r\n\r\n", 5);
    }
}

void EngineRequest::finalizeError()
{
    Response *res = context->response();

    res->setContentType(QStringLiteral("text/html; charset=utf-8"));

    QByteArray body;

    // Trick IE. Old versions of IE would display their own error page instead
    // of ours if we'd give it less than 512 bytes.
    body.reserve(512);

    body.append(context->errors().join(QLatin1Char('\n')).toUtf8());

    res->setBody(body);

    // Return 500
    res->setStatus(Response::InternalServerError);
}

void EngineRequest::finalize()
{
    if (context->error()) {
        finalizeError();
    }

    if (!(status & EngineRequest::FinalizedHeaders) && !finalizeHeaders()) {
        return;
    }

    finalizeBody();
}

void EngineRequest::finalizeCookies()
{
    Response *res = context->response();
    Headers &headers = res->headers();
    const auto cookies = res->cookies();
    for (const QNetworkCookie &cookie : cookies) {
        headers.pushHeader(QStringLiteral("SET_COOKIE"), QString::fromLatin1(cookie.toRawForm()));
    }
}

bool EngineRequest::finalizeHeaders()
{
    Response *response = context->response();
    Headers &headers = response->headers();

    // Fix missing content length
    if (headers.contentLength() < 0) {
        qint64 size = response->size();
        if (size >= 0) {
            headers.setContentLength(size);
        }
    }

    finalizeCookies();

    // Done
    status |= EngineRequest::FinalizedHeaders;
    return writeHeaders(response->status(), headers);
}

qint64 EngineRequest::write(const char *data, qint64 len)
{
    if (!(status & EngineRequest::Chunked)) {
        return doWrite(data, len);
    } else if (!(status & EngineRequest::ChunkedDone)) {
        const QByteArray chunkSize = QByteArray::number(len, 16).toUpper();
        QByteArray chunk;
        chunk.reserve(len + chunkSize.size() + 4);
        chunk.append(chunkSize).append("\r\n", 2)
                .append(data, len).append("\r\n", 2);

        qint64 retWrite = doWrite(chunk.data(), chunk.size());

        // Flag if we wrote an empty chunk
        if (!len) {
            status |= EngineRequest::ChunkedDone;
        }

        return retWrite == chunk.size() ? len : -1;
    }
    return -1;
}

bool EngineRequest::webSocketHandshake(const QString &key, const QString &origin, const QString &protocol)
{
    if (status & EngineRequest::FinalizedHeaders) {
        return false;
    }

    if (webSocketHandshakeDo(key, origin, protocol)) {
        status |= EngineRequest::FinalizedHeaders;
        return true;
    }

    return false;
}

bool EngineRequest::webSocketSendTextMessage(const QString &message)
{
    Q_UNUSED(message)
    return false;
}

bool EngineRequest::webSocketSendBinaryMessage(const QByteArray &message)
{
    Q_UNUSED(message)
    return false;
}

bool EngineRequest::webSocketSendPing(const QByteArray &payload)
{
    Q_UNUSED(payload)
    return false;
}

bool EngineRequest::webSocketClose(quint16 code, const QString &reason)
{
    Q_UNUSED(code)
    Q_UNUSED(reason)
    return false;
}

void EngineRequest::processingFinished()
{
}

bool EngineRequest::webSocketHandshakeDo(const QString &key, const QString &origin, const QString &protocol)
{
    Q_UNUSED(key)
    Q_UNUSED(origin)
    Q_UNUSED(protocol)
    return false;
}

void EngineRequest::setPath(char *rawPath, const int len)
{
    if (len == 0) {
        return;
    }

    char *data = rawPath;
    const char *inputPtr = data;

    bool skipUtf8 = true;
    int outlen = 0;
    for (int i = 0; i < len; ++i, ++outlen) {
        const char c = inputPtr[i];
        if (c == '%' && i + 2 < len) {
            int a = inputPtr[++i];
            int b = inputPtr[++i];

            if (a >= '0' && a <= '9') a -= '0';
            else if (a >= 'a' && a <= 'f') a = a - 'a' + 10;
            else if (a >= 'A' && a <= 'F') a = a - 'A' + 10;

            if (b >= '0' && b <= '9') b -= '0';
            else if (b >= 'a' && b <= 'f') b  = b - 'a' + 10;
            else if (b >= 'A' && b <= 'F') b  = b - 'A' + 10;

            *data++ = (char)((a << 4) | b);
            skipUtf8 = false;
        } else if (c == '+') {
            *data++ = ' ';
        } else {
            *data++ = c;
        }
    }

    if (skipUtf8) {
        path = QString::fromLatin1(rawPath, outlen);
    } else {
        path = QString::fromUtf8(rawPath, outlen);
    }
}

#include "moc_enginerequest.cpp"
<|endoftext|>


<commit_before>// This file is part of the dune-grid-multiscale project:
//   http://users.dune-project.org/projects/dune-grid-multiscale
// Copyright holders: Felix Albrecht
// License: BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause)

#ifndef DUNE_GRID_PART_ITERATOR_CODIM0_HH
#define DUNE_GRID_PART_ITERATOR_CODIM0_HH

#ifdef HAVE_CMAKE_CONFIG
  #include "cmake_config.h"
#elif defined (HAVE_CONFIG_H)
  #include <config.h>
#endif // ifdef HAVE_CMAKE_CONFIG

// system
#include <map>

// dune-common
#include <dune/common/exceptions.hh>
#include <dune/common/shared_ptr.hh>

// dune-geometry
#include <dune/geometry/type.hh>

// dune-grid
#include <dune/grid/common/grid.hh>

namespace Dune {
namespace grid {
namespace Part {
namespace Iterator {
namespace Local {

/**
 *  \brief  Iterates over those entities of a grid part, the indices of which match predefined ones.
 *  \todo   Replace GlobalGridPartImp with Interface< GlobalGridPartTraitsImp >!
 *  \todo   Document!
 */
template< class GlobalGridPartImp, int codim, Dune::PartitionIteratorType pitype >
class IndexBased
  : public GlobalGridPartImp::template Codim< codim >::template Partition< pitype >::IteratorType
{
public:
  typedef GlobalGridPartImp GlobalGridPartType;

  typedef IndexBased< GlobalGridPartType, codim, pitype > ThisType;

  typedef typename GlobalGridPartImp::template Codim< codim >::template Partition< pitype >::IteratorType BaseType;

  typedef typename GlobalGridPartType::IndexSetType::IndexType IndexType;

  typedef Dune::GeometryType GeometryType;

private:
  typedef std::map< IndexType, IndexType > IndexMapType;

public:
  typedef std::map< GeometryType, std::map< IndexType, IndexType > > IndexContainerType;

  typedef typename BaseType::Entity Entity;

  IndexBased(const GlobalGridPartType& globalGridPart,
             const Dune::shared_ptr< const IndexContainerType > indexContainer,
             const bool end = false)
    : BaseType(end ? globalGridPart.template end< codim, pitype >() : globalGridPart.template begin< codim, pitype >()),
      globalGridPart_(globalGridPart),
      indexContainer_(indexContainer),
      workAtAll_(0)
  {
    if (!end) {
      // loop over all GeometryTypes
      for (typename IndexContainerType::const_iterator iterator = indexContainer_->begin();
           iterator != indexContainer_->end();
           ++iterator) {
        // treat only the codim 0 ones
        if (iterator->first.dim() == (GlobalGridPartType::GridType::dimension - codim)) {
          ++workAtAll_;
          last_.insert(std::make_pair(iterator->first, iterator->second.rbegin()->first));
          end_.insert(std::make_pair(iterator->first, iterator->second.end()));
        } // treat only the codim 0 ones
      } // loop over all GeometryTypes
      forward();
    } // if (!end)
  } // IndexBased

  ThisType& operator++()
  {
    if (workAtAll_ > 0) {
      BaseType::operator++();
      forward();
    } else
      BaseType::operator=(globalGridPart_.template end< codim, pitype >());
    return *this;
  } // ThisType& operator++()

private:
  //! iterates forward until we find the next entity that belongs to the local grid part
  void forward()
  {
    bool found = false;
    while (!found && (workAtAll_ > 0)) {
      const Entity& entity = BaseType::operator*();
      const IndexType& index = globalGridPart_.indexSet().index(entity);
      const GeometryType& geometryType = entity.type();
      typename IndexContainerType::const_iterator indexMap = indexContainer_->find(geometryType);
      if (indexMap != indexContainer_->end()) {
        const typename IndexMapType::const_iterator result = indexMap->second.find(index);
        if ((result != end_.find(geometryType)->second)) {
          found = true;
          if (result->first == last_.find(geometryType)->second)
            --workAtAll_;
        } else
          BaseType::operator++();
      } else
        BaseType::operator++();
    }
  } // void forward()

  const GlobalGridPartType& globalGridPart_;
  const Dune::shared_ptr< const IndexContainerType > indexContainer_;
  unsigned int workAtAll_;
  std::map< GeometryType, IndexType > last_;
  std::map< GeometryType, typename IndexMapType::const_iterator > end_;
}; // class IndexBased

} // namespace Local
} // namespace Iterator
} // namespace Part
} // namespace grid
} // namespace Dune

#endif // DUNE_GRID_PART_ITERATOR_CODIM0_HH
<commit_msg>[grid.part] drop config.h include<commit_after>// This file is part of the dune-grid-multiscale project:
//   http://users.dune-project.org/projects/dune-grid-multiscale
// Copyright holders: Felix Albrecht
// License: BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause)

#ifndef DUNE_GRID_PART_ITERATOR_CODIM0_HH
#define DUNE_GRID_PART_ITERATOR_CODIM0_HH

// system
#include <map>

// dune-common
#include <dune/common/exceptions.hh>
#include <dune/common/shared_ptr.hh>

// dune-geometry
#include <dune/geometry/type.hh>

// dune-grid
#include <dune/grid/common/grid.hh>

namespace Dune {
namespace grid {
namespace Part {
namespace Iterator {
namespace Local {

/**
 *  \brief  Iterates over those entities of a grid part, the indices of which match predefined ones.
 *  \todo   Replace GlobalGridPartImp with Interface< GlobalGridPartTraitsImp >!
 *  \todo   Document!
 */
template< class GlobalGridPartImp, int codim, Dune::PartitionIteratorType pitype >
class IndexBased
  : public GlobalGridPartImp::template Codim< codim >::template Partition< pitype >::IteratorType
{
public:
  typedef GlobalGridPartImp GlobalGridPartType;

  typedef IndexBased< GlobalGridPartType, codim, pitype > ThisType;

  typedef typename GlobalGridPartImp::template Codim< codim >::template Partition< pitype >::IteratorType BaseType;

  typedef typename GlobalGridPartType::IndexSetType::IndexType IndexType;

  typedef Dune::GeometryType GeometryType;

private:
  typedef std::map< IndexType, IndexType > IndexMapType;

public:
  typedef std::map< GeometryType, std::map< IndexType, IndexType > > IndexContainerType;

  typedef typename BaseType::Entity Entity;

  IndexBased(const GlobalGridPartType& globalGridPart,
             const Dune::shared_ptr< const IndexContainerType > indexContainer,
             const bool end = false)
    : BaseType(end ? globalGridPart.template end< codim, pitype >() : globalGridPart.template begin< codim, pitype >()),
      globalGridPart_(globalGridPart),
      indexContainer_(indexContainer),
      workAtAll_(0)
  {
    if (!end) {
      // loop over all GeometryTypes
      for (typename IndexContainerType::const_iterator iterator = indexContainer_->begin();
           iterator != indexContainer_->end();
           ++iterator) {
        // treat only the codim 0 ones
        if (iterator->first.dim() == (GlobalGridPartType::GridType::dimension - codim)) {
          ++workAtAll_;
          last_.insert(std::make_pair(iterator->first, iterator->second.rbegin()->first));
          end_.insert(std::make_pair(iterator->first, iterator->second.end()));
        } // treat only the codim 0 ones
      } // loop over all GeometryTypes
      forward();
    } // if (!end)
  } // IndexBased

  ThisType& operator++()
  {
    if (workAtAll_ > 0) {
      BaseType::operator++();
      forward();
    } else
      BaseType::operator=(globalGridPart_.template end< codim, pitype >());
    return *this;
  } // ThisType& operator++()

private:
  //! iterates forward until we find the next entity that belongs to the local grid part
  void forward()
  {
    bool found = false;
    while (!found && (workAtAll_ > 0)) {
      const Entity& entity = BaseType::operator*();
      const IndexType& index = globalGridPart_.indexSet().index(entity);
      const GeometryType& geometryType = entity.type();
      typename IndexContainerType::const_iterator indexMap = indexContainer_->find(geometryType);
      if (indexMap != indexContainer_->end()) {
        const typename IndexMapType::const_iterator result = indexMap->second.find(index);
        if ((result != end_.find(geometryType)->second)) {
          found = true;
          if (result->first == last_.find(geometryType)->second)
            --workAtAll_;
        } else
          BaseType::operator++();
      } else
        BaseType::operator++();
    }
  } // void forward()

  const GlobalGridPartType& globalGridPart_;
  const Dune::shared_ptr< const IndexContainerType > indexContainer_;
  unsigned int workAtAll_;
  std::map< GeometryType, IndexType > last_;
  std::map< GeometryType, typename IndexMapType::const_iterator > end_;
}; // class IndexBased

} // namespace Local
} // namespace Iterator
} // namespace Part
} // namespace grid
} // namespace Dune

#endif // DUNE_GRID_PART_ITERATOR_CODIM0_HH
<|endoftext|>