<commit_before>// [WriteFile Name=ListTransformations, Category=Geometry]
// [Legal]
// Copyright 2017 Esri.

// 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.
// [Legal]

#include "ListTransformations.h"

#include "Map.h"
#include "MapQuickView.h"
#include "TransformationCatalog.h"
#include "GeometryEngine.h"
#include "GraphicsOverlay.h"
#include "Graphic.h"
#include "Point.h"
#include "SimpleMarkerSymbol.h"
#include "DatumTransformation.h"
#include "GeographicTransformationStep.h"
#include "GeographicTransformation.h"

#include <QUrl>
#include <QQmlProperty>
#include <QVariantMap>

using namespace Esri::ArcGISRuntime;

ListTransformations::ListTransformations(QQuickItem* parent /* = nullptr */):
  QQuickItem(parent)
{
}

void ListTransformations::init()
{
  // Register the map view for QML
  qmlRegisterType<MapQuickView>("Esri.Samples", 1, 0, "MapView");
  qmlRegisterType<ListTransformations>("Esri.Samples", 1, 0, "ListTransformationsSample");
}

void ListTransformations::componentComplete()
{
  QQuickItem::componentComplete();

  // get data path
  const QUrl dataPath = QUrl(QQmlProperty::read(this, "dataPath").toString()).toLocalFile();

  // connect to TransformationCatalog error signal
  connect(TransformationCatalog::instance(), &TransformationCatalog::errorOccurred, this, [this](Error e)
  {
    if (e.isEmpty())
      return;

    emit showStatusBar(QString("Error setting projection engine directory: %1. %2").arg(e.message()).arg(e.additionalMessage()));
  });

  // Set the TransformationCatalog path
  TransformationCatalog::setProjectionEngineDirectory(dataPath.toString());
  showStatusBar();

  // Create a geometry located in the Greenwich observatory courtyard in London, UK, the location of the
  // Greenwich prime meridian. This will be projected using the selected transformation.
  const double x = 538985.355;
  const double y = 177329.516;
  m_originalPoint = Point(x, y, SpatialReference(27700));

  // find QML MapView component
  m_mapView = findChild<MapQuickView*>("mapView");

  // Create a map using the light gray canvas basemap
  m_map = new Map(Basemap::lightGrayCanvas(this), this);

  // Set initial viewpoint of the map
  m_map->setInitialViewpoint(Viewpoint(m_originalPoint, 5000));

  // connect to map loaded signal
  connect(m_map, &Map::doneLoading, this, [this, dataPath]
  {
    // get the initial list of transformations
    refreshTransformationList(true);
  });

  // add graphics to the map view
  addGraphics();

  // set map to map view
  m_mapView->setMap(m_map);
}

// Create a GraphicsOverlay with two Graphics - one to hold the default
// transformed geometry, and the other to use the selected transformation
void ListTransformations::addGraphics()
{
  // Create the original graphic
  SimpleMarkerSymbol* blueSquare = new SimpleMarkerSymbol(SimpleMarkerSymbolStyle::Square, QColor("blue"), 20.f, this);
  m_originalGraphic = new Graphic(m_originalPoint, blueSquare, this);

  // Create the projected graphic
  SimpleMarkerSymbol* redCross = new SimpleMarkerSymbol(SimpleMarkerSymbolStyle::Cross, QColor("red"), 20.f, this);
  m_projectedGraphic = new Graphic(m_originalPoint, redCross, this);

  // Create the Overlay
  GraphicsOverlay* overlay = new GraphicsOverlay(this);
  m_mapView->graphicsOverlays()->append(overlay);
  overlay->graphics()->append(m_originalGraphic);
  overlay->graphics()->append(m_projectedGraphic);
}

void ListTransformations::refreshTransformationList(bool orderBySuitability)
{
  // get the input/output spatial reference
  SpatialReference inSpatialReference = m_originalGraphic->geometry().spatialReference();
  SpatialReference outSpatialReference = m_map->spatialReference();

  // request the transformations
  if (orderBySuitability)
    m_transformations = TransformationCatalog::transformationsBySuitability(inSpatialReference, outSpatialReference, m_mapView->visibleArea().extent());
  else
    m_transformations = TransformationCatalog::transformationsBySuitability(inSpatialReference, outSpatialReference);

  // update the QML property list
  m_transformationList.clear();
  for (DatumTransformation* transformation : m_transformations)
  {
    QVariantMap transformationMap;
    transformationMap["name"] = transformation->name();
    transformationMap["isMissingProjectionEngineFiles"] = transformation->isMissingProjectionEngineFiles();
    m_transformationList.append(transformationMap);
  }

  // update the property
  emit transformationListChanged();
}

void ListTransformations::updateGraphicTransformation(int index)
{
  GeographicTransformation* transform = static_cast<GeographicTransformation*>(m_transformations.at(index));
  if (transform->isMissingProjectionEngineFiles())
  {
    QString missingFiles = "Missing grid files: ";
    const QList<GeographicTransformationStep> steps = transform->steps();
    for (GeographicTransformationStep step : steps)
    {
      for (const QString& filename : step.projectionEngineFilenames())
      {
        missingFiles += filename;
      }
    }
    emit showStatusBar(missingFiles);
  }
  else
  {
    Geometry projectedPoint = GeometryEngine::project(m_originalPoint, m_map->spatialReference(), transform);
    m_projectedGraphic->setGeometry(projectedPoint);
  }
}
<commit_msg>fixing a timing issue with the error display<commit_after>// [WriteFile Name=ListTransformations, Category=Geometry]
// [Legal]
// Copyright 2017 Esri.

// 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.
// [Legal]

#include "ListTransformations.h"

#include "Map.h"
#include "MapQuickView.h"
#include "TransformationCatalog.h"
#include "GeometryEngine.h"
#include "GraphicsOverlay.h"
#include "Graphic.h"
#include "Point.h"
#include "SimpleMarkerSymbol.h"
#include "DatumTransformation.h"
#include "GeographicTransformationStep.h"
#include "GeographicTransformation.h"

#include <QUrl>
#include <QQmlProperty>
#include <QVariantMap>

using namespace Esri::ArcGISRuntime;

ListTransformations::ListTransformations(QQuickItem* parent /* = nullptr */):
  QQuickItem(parent)
{
}

void ListTransformations::init()
{
  // Register the map view for QML
  qmlRegisterType<MapQuickView>("Esri.Samples", 1, 0, "MapView");
  qmlRegisterType<ListTransformations>("Esri.Samples", 1, 0, "ListTransformationsSample");
}

void ListTransformations::componentComplete()
{
  QQuickItem::componentComplete();

  // get data path
  const QUrl dataPath = QUrl(QQmlProperty::read(this, "dataPath").toString()).toLocalFile();

  // connect to TransformationCatalog error signal
  connect(TransformationCatalog::instance(), &TransformationCatalog::errorOccurred, this, [this](Error e)
  {
    if (e.isEmpty())
      return;

    emit showStatusBar(QString("Error setting projection engine directory: %1. %2").arg(e.message()).arg(e.additionalMessage()));
  });

  // Create a geometry located in the Greenwich observatory courtyard in London, UK, the location of the
  // Greenwich prime meridian. This will be projected using the selected transformation.
  const double x = 538985.355;
  const double y = 177329.516;
  m_originalPoint = Point(x, y, SpatialReference(27700));

  // find QML MapView component
  m_mapView = findChild<MapQuickView*>("mapView");

  // Create a map using the light gray canvas basemap
  m_map = new Map(Basemap::lightGrayCanvas(this), this);

  // Set initial viewpoint of the map
  m_map->setInitialViewpoint(Viewpoint(m_originalPoint, 5000));

  // connect to map loaded signal
  connect(m_map, &Map::doneLoading, this, [this, dataPath]
  {
    // Set the TransformationCatalog path
    TransformationCatalog::setProjectionEngineDirectory(dataPath.toString());
    if (TransformationCatalog::projectionEngineDirectory().length() > 0)
      showStatusBar();

    // get the initial list of transformations
    refreshTransformationList(true);
  });

  // add graphics to the map view
  addGraphics();

  // set map to map view
  m_mapView->setMap(m_map);
}

// Create a GraphicsOverlay with two Graphics - one to hold the default
// transformed geometry, and the other to use the selected transformation
void ListTransformations::addGraphics()
{
  // Create the original graphic
  SimpleMarkerSymbol* blueSquare = new SimpleMarkerSymbol(SimpleMarkerSymbolStyle::Square, QColor("blue"), 20.f, this);
  m_originalGraphic = new Graphic(m_originalPoint, blueSquare, this);

  // Create the projected graphic
  SimpleMarkerSymbol* redCross = new SimpleMarkerSymbol(SimpleMarkerSymbolStyle::Cross, QColor("red"), 20.f, this);
  m_projectedGraphic = new Graphic(m_originalPoint, redCross, this);

  // Create the Overlay
  GraphicsOverlay* overlay = new GraphicsOverlay(this);
  m_mapView->graphicsOverlays()->append(overlay);
  overlay->graphics()->append(m_originalGraphic);
  overlay->graphics()->append(m_projectedGraphic);
}

void ListTransformations::refreshTransformationList(bool orderBySuitability)
{
  // get the input/output spatial reference
  SpatialReference inSpatialReference = m_originalGraphic->geometry().spatialReference();
  SpatialReference outSpatialReference = m_map->spatialReference();

  // request the transformations
  if (orderBySuitability)
    m_transformations = TransformationCatalog::transformationsBySuitability(inSpatialReference, outSpatialReference, m_mapView->visibleArea().extent());
  else
    m_transformations = TransformationCatalog::transformationsBySuitability(inSpatialReference, outSpatialReference);

  // update the QML property list
  m_transformationList.clear();
  for (DatumTransformation* transformation : m_transformations)
  {
    QVariantMap transformationMap;
    transformationMap["name"] = transformation->name();
    transformationMap["isMissingProjectionEngineFiles"] = transformation->isMissingProjectionEngineFiles();
    m_transformationList.append(transformationMap);
  }

  // update the property
  emit transformationListChanged();
}

void ListTransformations::updateGraphicTransformation(int index)
{
  GeographicTransformation* transform = static_cast<GeographicTransformation*>(m_transformations.at(index));
  if (transform->isMissingProjectionEngineFiles())
  {
    QString missingFiles = "Missing grid files: ";
    const QList<GeographicTransformationStep> steps = transform->steps();
    for (GeographicTransformationStep step : steps)
    {
      for (const QString& filename : step.projectionEngineFilenames())
      {
        missingFiles += filename;
      }
    }
    emit showStatusBar(missingFiles);
  }
  else
  {
    Geometry projectedPoint = GeometryEngine::project(m_originalPoint, m_map->spatialReference(), transform);
    m_projectedGraphic->setGeometry(projectedPoint);
  }
}
<|endoftext|>


<commit_before>/*
**  Copyright (C) 2012 Aldebaran Robotics
**  See COPYING for the license
*/

// Disable "'this': used in base member initializer list"
#ifdef _MSC_VER
# pragma warning( push )
# pragma warning(disable: 4355)
#endif

#include <qimessaging/session.hpp>
#include <qimessaging/message.hpp>
#include <qimessaging/transportsocket.hpp>
#include <qitype/genericobject.hpp>
#include <qimessaging/serviceinfo.hpp>
#include <qitype/objectfactory.hpp>
#include "remoteobject_p.hpp"
#include "session_p.hpp"

qiLogCategory("qimessaging.session");

namespace qi {

  SessionPrivate::SessionPrivate(qi::Session *session)
    : _self(session)
    , _sdClient()
    , _serverObject(&_sdClient)
    , _serviceHandler(&_socketsCache, &_sdClient, &_serverObject)
    , _servicesHandler(&_sdClient, &_serverObject)
  {
    _self->connected.setCallType(qi::MetaCallType_Queued);
    _self->disconnected.setCallType(qi::MetaCallType_Queued);
    _self->serviceRegistered.setCallType(qi::MetaCallType_Queued);
    _self->serviceUnregistered.setCallType(qi::MetaCallType_Queued);

    _sdClientConnectedLink    = _sdClient.connected.connect(boost::bind<void>(&SessionPrivate::onConnected, this));
    _sdClientDisconnectedLink = _sdClient.disconnected.connect(boost::bind<void>(&SessionPrivate::onDisconnected, this, _1));
    _sdClientServiceAddedLink = _sdClient.serviceAdded.connect(boost::bind<void>(&SessionPrivate::onServiceAdded, this, _1, _2));
    _sdClientServiceRemovedLink = _sdClient.serviceRemoved.connect(boost::bind<void>(&SessionPrivate::onServiceRemoved, this, _1, _2));
  }

  SessionPrivate::~SessionPrivate() {
    _sdClient.connected.disconnect(_sdClientConnectedLink);
    _sdClient.disconnected.disconnect(_sdClientDisconnectedLink);
    _sdClient.serviceAdded.disconnect(_sdClientServiceAddedLink);
    _sdClient.serviceRemoved.disconnect(_sdClientServiceRemovedLink);
    _self->disconnected.disconnectAll();
    _self->connected.disconnectAll();
    close();
  }

  void SessionPrivate::onConnected() {
    _self->connected();
  }

  void SessionPrivate::onDisconnected(int error) {
    _self->disconnected(error);

    /*
     * Remove all proxies to services if the SD is fallen.
     */
    _serviceHandler.close();
  }

  void SessionPrivate::onServiceAdded(unsigned int idx, const std::string &name) {
    _self->serviceRegistered(idx, name);
  }

  void SessionPrivate::onServiceRemoved(unsigned int idx, const std::string &name) {
    _self->serviceUnregistered(idx, name);
  }

  qi::FutureSync<bool> SessionPrivate::connect(const qi::Url &serviceDirectoryURL)
  {
    if (isConnected()) {
      qiLogInfo() << "Session is already connected";
      return qi::Future<bool>(false);
    }
    _socketsCache.init();
    return _sdClient.connect(serviceDirectoryURL);
  }

  qi::FutureSync<void> SessionPrivate::close()
  {
    _serviceHandler.close();
    _serverObject.close();
    _socketsCache.close();
    return _sdClient.close();
  }

  bool SessionPrivate::isConnected() const {
    return _sdClient.isConnected();
  }

  // ###### Session
  Session::Session()
    : _p(new SessionPrivate(this))
  {
  }

  Session::~Session()
  {
    close();
    delete _p;
  }

  // ###### Client
  qi::FutureSync<bool> Session::connect(const qi::Url &serviceDirectoryURL)
  {
    return _p->connect(serviceDirectoryURL);
  }

  qi::FutureSync<void> Session::close() {
    return _p->close();
  }

  bool Session::isConnected() const {
    return _p->isConnected();
  }

  qi::Url Session::url() const {
    return _p->_sdClient.url();
  }

  //3 cases:
  //  - local service => just return the vector
  //  - remote => ask the sd return the result
  //  - all => ask the sd, append local services, return the result
  qi::Future< std::vector<ServiceInfo> > Session::services(ServiceLocality locality)
  {
    return _p->_servicesHandler.services(locality);
  }

  qi::Future< qi::ObjectPtr > Session::service(const std::string &service,
                                               ServiceLocality locality)
  {
    return _p->_serviceHandler.service(service, locality);
  }

  qi::Future<void> Session::listen(const qi::Url &address)
  {
    return _p->_serverObject.listen(address);
  }

  bool Session::setIdentity(const std::string& key, const std::string& crt)
  {
    return _p->_serverObject.setIdentity(key, crt);
  }

  qi::FutureSync<unsigned int> Session::registerService(const std::string &name, qi::ObjectPtr obj)
  {
    if (endpoints().empty()) {
      qi::Url listeningAddress("tcp://0.0.0.0:0");
      qiLogVerbose() << listeningAddress.str() << "." << std::endl;
      listen(listeningAddress);
    }

    return _p->_serverObject.registerService(name, obj);
  }

  qi::FutureSync<void> Session::unregisterService(unsigned int idx)
  {
    return _p->_serverObject.unregisterService(idx);
  }

  std::vector<qi::Url> Session::endpoints() const
  {
    return _p->_serverObject.endpoints();
  }

  std::vector<std::string> Session::loadService(const std::string& name, int flags)
  {
    std::vector<std::string> names = ::qi::loadObject(name, flags);
    for (unsigned int i = 0; i < names.size(); ++i)
      registerService(names[i], createObject(names[i]));
    return names;
  }

  namespace details {

    // Only needed for ALModule.
    // (metacall should be direct when called in local, and threaded when coming from a server)
    void setSessionServerDefaultCallType(qi::Session *session, qi::MetaCallType callType) {
      session->_p->_serverObject.setDefaultCallType(callType);
    }
  };

}

#ifdef _MSC_VER
# pragma warning( pop )
#endif
<commit_msg>No verbose logs unless QIMESSAGING_DEBUG.<commit_after>/*
**  Copyright (C) 2012 Aldebaran Robotics
**  See COPYING for the license
*/

// Disable "'this': used in base member initializer list"
#ifdef _MSC_VER
# pragma warning( push )
# pragma warning(disable: 4355)
#endif

#include <qimessaging/session.hpp>
#include <qimessaging/message.hpp>
#include <qimessaging/transportsocket.hpp>
#include <qitype/genericobject.hpp>
#include <qimessaging/serviceinfo.hpp>
#include <qitype/objectfactory.hpp>
#include "remoteobject_p.hpp"
#include "session_p.hpp"

qiLogCategory("qimessaging.session");

namespace qi {

  SessionPrivate::SessionPrivate(qi::Session *session)
    : _self(session)
    , _sdClient()
    , _serverObject(&_sdClient)
    , _serviceHandler(&_socketsCache, &_sdClient, &_serverObject)
    , _servicesHandler(&_sdClient, &_serverObject)
  {
    _self->connected.setCallType(qi::MetaCallType_Queued);
    _self->disconnected.setCallType(qi::MetaCallType_Queued);
    _self->serviceRegistered.setCallType(qi::MetaCallType_Queued);
    _self->serviceUnregistered.setCallType(qi::MetaCallType_Queued);

    _sdClientConnectedLink    = _sdClient.connected.connect(boost::bind<void>(&SessionPrivate::onConnected, this));
    _sdClientDisconnectedLink = _sdClient.disconnected.connect(boost::bind<void>(&SessionPrivate::onDisconnected, this, _1));
    _sdClientServiceAddedLink = _sdClient.serviceAdded.connect(boost::bind<void>(&SessionPrivate::onServiceAdded, this, _1, _2));
    _sdClientServiceRemovedLink = _sdClient.serviceRemoved.connect(boost::bind<void>(&SessionPrivate::onServiceRemoved, this, _1, _2));
  }

  SessionPrivate::~SessionPrivate() {
    _sdClient.connected.disconnect(_sdClientConnectedLink);
    _sdClient.disconnected.disconnect(_sdClientDisconnectedLink);
    _sdClient.serviceAdded.disconnect(_sdClientServiceAddedLink);
    _sdClient.serviceRemoved.disconnect(_sdClientServiceRemovedLink);
    _self->disconnected.disconnectAll();
    _self->connected.disconnectAll();
    close();
  }

  void SessionPrivate::onConnected() {
    _self->connected();
  }

  void SessionPrivate::onDisconnected(int error) {
    _self->disconnected(error);

    /*
     * Remove all proxies to services if the SD is fallen.
     */
    _serviceHandler.close();
  }

  void SessionPrivate::onServiceAdded(unsigned int idx, const std::string &name) {
    _self->serviceRegistered(idx, name);
  }

  void SessionPrivate::onServiceRemoved(unsigned int idx, const std::string &name) {
    _self->serviceUnregistered(idx, name);
  }

  qi::FutureSync<bool> SessionPrivate::connect(const qi::Url &serviceDirectoryURL)
  {
    if (isConnected()) {
      qiLogInfo() << "Session is already connected";
      return qi::Future<bool>(false);
    }
    _socketsCache.init();
    return _sdClient.connect(serviceDirectoryURL);
  }

  qi::FutureSync<void> SessionPrivate::close()
  {
    _serviceHandler.close();
    _serverObject.close();
    _socketsCache.close();
    return _sdClient.close();
  }

  bool SessionPrivate::isConnected() const {
    return _sdClient.isConnected();
  }

  // ###### Session
  Session::Session()
    : _p(new SessionPrivate(this))
  {
  }

  Session::~Session()
  {
    close();
    delete _p;
  }

  // ###### Client
  qi::FutureSync<bool> Session::connect(const qi::Url &serviceDirectoryURL)
  {
    return _p->connect(serviceDirectoryURL);
  }

  qi::FutureSync<void> Session::close() {
    return _p->close();
  }

  bool Session::isConnected() const {
    return _p->isConnected();
  }

  qi::Url Session::url() const {
    return _p->_sdClient.url();
  }

  //3 cases:
  //  - local service => just return the vector
  //  - remote => ask the sd return the result
  //  - all => ask the sd, append local services, return the result
  qi::Future< std::vector<ServiceInfo> > Session::services(ServiceLocality locality)
  {
    return _p->_servicesHandler.services(locality);
  }

  qi::Future< qi::ObjectPtr > Session::service(const std::string &service,
                                               ServiceLocality locality)
  {
    return _p->_serviceHandler.service(service, locality);
  }

  qi::Future<void> Session::listen(const qi::Url &address)
  {
    return _p->_serverObject.listen(address);
  }

  bool Session::setIdentity(const std::string& key, const std::string& crt)
  {
    return _p->_serverObject.setIdentity(key, crt);
  }

  qi::FutureSync<unsigned int> Session::registerService(const std::string &name, qi::ObjectPtr obj)
  {
    if (endpoints().empty()) {
      qi::Url listeningAddress("tcp://0.0.0.0:0");
      qiLogVerbose() << listeningAddress.str() << "." << std::endl;
      listen(listeningAddress);
    }

    return _p->_serverObject.registerService(name, obj);
  }

  qi::FutureSync<void> Session::unregisterService(unsigned int idx)
  {
    return _p->_serverObject.unregisterService(idx);
  }

  std::vector<qi::Url> Session::endpoints() const
  {
    return _p->_serverObject.endpoints();
  }

  std::vector<std::string> Session::loadService(const std::string& name, int flags)
  {
    std::vector<std::string> names = ::qi::loadObject(name, flags);
    for (unsigned int i = 0; i < names.size(); ++i)
      registerService(names[i], createObject(names[i]));
    return names;
  }

  namespace details {

    // Only needed for ALModule.
    // (metacall should be direct when called in local, and threaded when coming from a server)
    void setSessionServerDefaultCallType(qi::Session *session, qi::MetaCallType callType) {
      session->_p->_serverObject.setDefaultCallType(callType);
    }
  };

}

namespace
{
  // trick to avoid wrapping in a function: setCategory returns void so can't
  // be used in expr.
  static bool __unused = qi::os::getenv("QIMESSAGING_DEBUG").empty()
    && (::qi::log::setCategory("qimessaging.*", ::qi::log::info), false);
}

#ifdef _MSC_VER
# pragma warning( pop )
#endif
<|endoftext|>


<commit_before>#include <dawgdic/dawg-builder.h>
#include <dawgdic/dictionary-builder.h>
#include <dawgdic/guide-builder.h>
#include <dawgdic/ranked-guide-builder.h>

#include <cstdlib>
#include <fstream>
#include <iostream>
#include <limits>
#include <string>

namespace {

class CommandOptions
{
public:
	CommandOptions() : help_(false), tab_(false), guide_(false),
		ranked_(false), lexicon_file_name_(), dic_file_name_() {}

	// Reads options.
	bool help() const { return help_; }
	bool tab() const { return tab_; }
	bool guide() const { return guide_; }
	bool ranked() const { return ranked_; }
	const std::string &lexicon_file_name() const
	{
		return lexicon_file_name_;
	}
	const std::string &dic_file_name() const { return dic_file_name_; }

	bool Parse(int argc, char *argv[])
	{
		for (int i = 1; i < argc; ++i)
		{
			// Parses options.
			if (argv[i][0] == '-' && argv[i][1] != '\0')
			{
				for (int j = 1; argv[i][j] != '\0'; ++j)
				{
					switch (argv[i][j])
					{
					case 'h':
						help_ = true;
						break;
					case 't':
						tab_ = true;
						break;
					case 'g':
						guide_ = true;
						break;
					case 'r':
						ranked_ = true;
						break;
					default:
						// Invalid option.
						return false;
					}
				}
			}
			else if (lexicon_file_name_.empty())
				lexicon_file_name_ = argv[i];
			else if (dic_file_name_.empty())
				dic_file_name_ = argv[i];
			else
			{
				// Too many arguments.
				return false;
			}
		}

		// Uses default settings for file names.
		if (lexicon_file_name_.empty())
			lexicon_file_name_ = "-";
		if (dic_file_name_.empty())
			dic_file_name_ = "-";
		return true;
	}

	static void ShowUsage(std::ostream *output)
	{
		*output << "Usage: - [Options] [LexiconFile] [DicFile]\n"
			"\n"
			"Options:\n"
			"  -h  display this help and exit\n"
			"  -t  handle tab as separater\n"
			"  -g  build dictionary with guide\n"
			"  -r  build dictionary with ranked guide\n";
		*output << std::endl;
	}

private:
	bool help_;
	bool tab_;
	bool guide_;
	bool ranked_;
	std::string lexicon_file_name_;
	std::string dic_file_name_;

	// Disallows copies.
	CommandOptions(const CommandOptions &);
	CommandOptions &operator=(const CommandOptions &);
};

// Builds a dawg from a sorted lexicon.
bool BuildDawg(std::istream *lexicon_stream, dawgdic::Dawg *dawg, bool tab_on)
{
	dawgdic::DawgBuilder dawg_builder;

	// Reads keys from an input stream and inserts them into a dawg.
	std::string key;
	std::size_t key_count = 0;
	while (std::getline(*lexicon_stream, key))
	{
		std::string::size_type delim_pos = std::string::npos;
		if (tab_on)
			delim_pos = key.find_first_of('\t');

		if (delim_pos == std::string::npos)
		{
			if (!dawg_builder.Insert(key.c_str()))
			{
				std::cerr << "error: failed to insert key: "
					<< key << std::endl;
				return false;
			}
		}
		else
		{
			static const dawgdic::ValueType MAX_VALUE =
				std::numeric_limits<dawgdic::ValueType>::max();

			// Fixes an invalid record value.
			long long record = std::strtoll(
				key.c_str() + delim_pos + 1, NULL, 10);
			dawgdic::ValueType value =
				static_cast<dawgdic::ValueType>(record);
			if (record < 0)
			{
				std::cerr << "warning: negative value is replaced by 0: "
					<< record << std::endl;
				value = 0;
			}
			else if (record > MAX_VALUE)
			{
				std::cerr << "warning: too large value is replaced by "
					<< MAX_VALUE << ": " << record << std::endl;
				value = MAX_VALUE;
			}

			if (!dawg_builder.Insert(key.c_str(), delim_pos, value))
			{
				std::cerr << "error: failed to insert key: "
					<< key << std::endl;
				return false;
			}
		}

		if (++key_count % 10000 == 0)
			std::cerr << "no. keys: " << key_count << '\r';
	}

	dawg_builder.Finish(dawg);

	std::cerr << "no. keys: " << key_count << std::endl;
	std::cerr << "no. states: "
		<< dawg->num_of_states() << std::endl;
	std::cerr << "no. transitions: "
		<< dawg->num_of_transitions() << std::endl;
	std::cerr << "no. merged states: "
		<< dawg->num_of_merged_states() << std::endl;
	std::cerr << "no. merging states: "
		<< dawg->num_of_merging_states() << std::endl;
	std::cerr << "no. merged transitions: "
		<< dawg->num_of_merged_transitions() << std::endl;

	return true;
}

// Builds a dictionary from a dawg.
bool BuildDictionary(const dawgdic::Dawg &dawg, dawgdic::Dictionary *dic)
{
	dawgdic::BaseType num_of_unused_units = 0;
	if (!dawgdic::DictionaryBuilder::Build(dawg, dic, &num_of_unused_units))
	{
		std::cerr << "error: failed to build Dictionary" << std::endl;
		return false;
	}
	double unused_ratio = 100.0 * num_of_unused_units / dic->size();

	std::cerr << "no. elements: " << dic->size() << std::endl;
	std::cerr << "no. unused elements: " << num_of_unused_units
		<< " (" << unused_ratio << "%)" << std::endl;
	std::cerr << "dictionary size: " << dic->total_size() << std::endl;

	return true;
}

// Builds a ranked guide from a dawg and its dictionary.
bool BuildRankedGuide(const dawgdic::Dawg &dawg,
	const dawgdic::Dictionary &dic, dawgdic::RankedGuide *guide)
{
	if (!dawgdic::RankedGuideBuilder::Build(dawg, dic, guide))
	{
		std::cerr << "failed to build RankedGuide" << std::endl;
		return false;
	}

	std::cerr << "no. units: " << guide->size() << std::endl;
	std::cerr << "guide size: " << guide->total_size() << std::endl;

	return true;
}

// Builds a guide from a dawg and its dictionary.
bool BuildGuide(const dawgdic::Dawg &dawg,
	const dawgdic::Dictionary &dic, dawgdic::Guide *guide)
{
	if (!dawgdic::GuideBuilder::Build(dawg, dic, guide))
	{
		std::cerr << "failed to build Guide" << std::endl;
		return false;
	}

	std::cerr << "no. units: " << guide->size() << std::endl;
	std::cerr << "guide size: " << guide->total_size() << std::endl;

	return true;
}

}  // namespace

int main(int argc, char *argv[])
{
	CommandOptions options;
	if (!options.Parse(argc, argv))
	{
		CommandOptions::ShowUsage(&std::cerr);
		return 1;
	}
	else if (options.help())
	{
		CommandOptions::ShowUsage(&std::cerr);
		return 0;
	}

	const std::string &lexicon_file_name = options.lexicon_file_name();
	const std::string &dic_file_name = options.dic_file_name();

	std::istream *lexicon_stream = &std::cin;
	std::ostream *dic_stream = &std::cout;

	// Opens a lexicon file.
	std::ifstream lexicon_file;
	if (lexicon_file_name != "-")
	{
		lexicon_file.open(lexicon_file_name.c_str(), std::ios::binary);
		if (!lexicon_file)
		{
			std::cerr << "error: failed to open LexiconFile: "
				<< lexicon_file_name << std::endl;
			return 1;
		}
		lexicon_stream = &lexicon_file;
	}

	// Opens a dictionary file.
	std::ofstream dic_file;
	if (dic_file_name != "-")
	{
		dic_file.open(dic_file_name.c_str(), std::ios::binary);
		if (!dic_file)
		{
			std::cerr << "error: failed to open DicFile: "
				<< dic_file_name << std::endl;
			return 1;
		}
		dic_stream = &dic_file;
	}

	dawgdic::Dawg dawg;
	if (!BuildDawg(lexicon_stream, &dawg, options.tab()))
		return 1;

	dawgdic::Dictionary dic;
	if (!BuildDictionary(dawg, &dic))
		return 1;

	if (!dic.Write(dic_stream))
	{
		std::cerr << "error: failed to write Dictionary" << std::endl;
		return 1;
	}

	// Builds a guide.
	if (options.ranked())
	{
		dawgdic::RankedGuide guide;
		if (!BuildRankedGuide(dawg, dic, &guide))
			return 1;
		if (!guide.Write(dic_stream))
		{
			std::cerr << "error: failed to write RankedGuide" << std::endl;
			return 1;
		}
	}
	else if (options.guide())
	{
		dawgdic::Guide guide;
		if (!BuildGuide(dawg, dic, &guide))
			return 1;
		if (!guide.Write(dic_stream))
		{
			std::cerr << "error: failed to write Guide" << std::endl;
			return 1;
		}
	}

	return 0;
}
<commit_msg>fixed a typo (Issue 2), thanks to jwilk.<commit_after>#include <dawgdic/dawg-builder.h>
#include <dawgdic/dictionary-builder.h>
#include <dawgdic/guide-builder.h>
#include <dawgdic/ranked-guide-builder.h>

#include <cstdlib>
#include <fstream>
#include <iostream>
#include <limits>
#include <string>

namespace {

class CommandOptions
{
public:
	CommandOptions() : help_(false), tab_(false), guide_(false),
		ranked_(false), lexicon_file_name_(), dic_file_name_() {}

	// Reads options.
	bool help() const { return help_; }
	bool tab() const { return tab_; }
	bool guide() const { return guide_; }
	bool ranked() const { return ranked_; }
	const std::string &lexicon_file_name() const
	{
		return lexicon_file_name_;
	}
	const std::string &dic_file_name() const { return dic_file_name_; }

	bool Parse(int argc, char *argv[])
	{
		for (int i = 1; i < argc; ++i)
		{
			// Parses options.
			if (argv[i][0] == '-' && argv[i][1] != '\0')
			{
				for (int j = 1; argv[i][j] != '\0'; ++j)
				{
					switch (argv[i][j])
					{
					case 'h':
						help_ = true;
						break;
					case 't':
						tab_ = true;
						break;
					case 'g':
						guide_ = true;
						break;
					case 'r':
						ranked_ = true;
						break;
					default:
						// Invalid option.
						return false;
					}
				}
			}
			else if (lexicon_file_name_.empty())
				lexicon_file_name_ = argv[i];
			else if (dic_file_name_.empty())
				dic_file_name_ = argv[i];
			else
			{
				// Too many arguments.
				return false;
			}
		}

		// Uses default settings for file names.
		if (lexicon_file_name_.empty())
			lexicon_file_name_ = "-";
		if (dic_file_name_.empty())
			dic_file_name_ = "-";
		return true;
	}

	static void ShowUsage(std::ostream *output)
	{
		*output << "Usage: - [Options] [LexiconFile] [DicFile]\n"
			"\n"
			"Options:\n"
			"  -h  display this help and exit\n"
			"  -t  handle tab as separator\n"
			"  -g  build dictionary with guide\n"
			"  -r  build dictionary with ranked guide\n";
		*output << std::endl;
	}

private:
	bool help_;
	bool tab_;
	bool guide_;
	bool ranked_;
	std::string lexicon_file_name_;
	std::string dic_file_name_;

	// Disallows copies.
	CommandOptions(const CommandOptions &);
	CommandOptions &operator=(const CommandOptions &);
};

// Builds a dawg from a sorted lexicon.
bool BuildDawg(std::istream *lexicon_stream, dawgdic::Dawg *dawg, bool tab_on)
{
	dawgdic::DawgBuilder dawg_builder;

	// Reads keys from an input stream and inserts them into a dawg.
	std::string key;
	std::size_t key_count = 0;
	while (std::getline(*lexicon_stream, key))
	{
		std::string::size_type delim_pos = std::string::npos;
		if (tab_on)
			delim_pos = key.find_first_of('\t');

		if (delim_pos == std::string::npos)
		{
			if (!dawg_builder.Insert(key.c_str()))
			{
				std::cerr << "error: failed to insert key: "
					<< key << std::endl;
				return false;
			}
		}
		else
		{
			static const dawgdic::ValueType MAX_VALUE =
				std::numeric_limits<dawgdic::ValueType>::max();

			// Fixes an invalid record value.
			long long record = std::strtoll(
				key.c_str() + delim_pos + 1, NULL, 10);
			dawgdic::ValueType value =
				static_cast<dawgdic::ValueType>(record);
			if (record < 0)
			{
				std::cerr << "warning: negative value is replaced by 0: "
					<< record << std::endl;
				value = 0;
			}
			else if (record > MAX_VALUE)
			{
				std::cerr << "warning: too large value is replaced by "
					<< MAX_VALUE << ": " << record << std::endl;
				value = MAX_VALUE;
			}

			if (!dawg_builder.Insert(key.c_str(), delim_pos, value))
			{
				std::cerr << "error: failed to insert key: "
					<< key << std::endl;
				return false;
			}
		}

		if (++key_count % 10000 == 0)
			std::cerr << "no. keys: " << key_count << '\r';
	}

	dawg_builder.Finish(dawg);

	std::cerr << "no. keys: " << key_count << std::endl;
	std::cerr << "no. states: "
		<< dawg->num_of_states() << std::endl;
	std::cerr << "no. transitions: "
		<< dawg->num_of_transitions() << std::endl;
	std::cerr << "no. merged states: "
		<< dawg->num_of_merged_states() << std::endl;
	std::cerr << "no. merging states: "
		<< dawg->num_of_merging_states() << std::endl;
	std::cerr << "no. merged transitions: "
		<< dawg->num_of_merged_transitions() << std::endl;

	return true;
}

// Builds a dictionary from a dawg.
bool BuildDictionary(const dawgdic::Dawg &dawg, dawgdic::Dictionary *dic)
{
	dawgdic::BaseType num_of_unused_units = 0;
	if (!dawgdic::DictionaryBuilder::Build(dawg, dic, &num_of_unused_units))
	{
		std::cerr << "error: failed to build Dictionary" << std::endl;
		return false;
	}
	double unused_ratio = 100.0 * num_of_unused_units / dic->size();

	std::cerr << "no. elements: " << dic->size() << std::endl;
	std::cerr << "no. unused elements: " << num_of_unused_units
		<< " (" << unused_ratio << "%)" << std::endl;
	std::cerr << "dictionary size: " << dic->total_size() << std::endl;

	return true;
}

// Builds a ranked guide from a dawg and its dictionary.
bool BuildRankedGuide(const dawgdic::Dawg &dawg,
	const dawgdic::Dictionary &dic, dawgdic::RankedGuide *guide)
{
	if (!dawgdic::RankedGuideBuilder::Build(dawg, dic, guide))
	{
		std::cerr << "failed to build RankedGuide" << std::endl;
		return false;
	}

	std::cerr << "no. units: " << guide->size() << std::endl;
	std::cerr << "guide size: " << guide->total_size() << std::endl;

	return true;
}

// Builds a guide from a dawg and its dictionary.
bool BuildGuide(const dawgdic::Dawg &dawg,
	const dawgdic::Dictionary &dic, dawgdic::Guide *guide)
{
	if (!dawgdic::GuideBuilder::Build(dawg, dic, guide))
	{
		std::cerr << "failed to build Guide" << std::endl;
		return false;
	}

	std::cerr << "no. units: " << guide->size() << std::endl;
	std::cerr << "guide size: " << guide->total_size() << std::endl;

	return true;
}

}  // namespace

int main(int argc, char *argv[])
{
	CommandOptions options;
	if (!options.Parse(argc, argv))
	{
		CommandOptions::ShowUsage(&std::cerr);
		return 1;
	}
	else if (options.help())
	{
		CommandOptions::ShowUsage(&std::cerr);
		return 0;
	}

	const std::string &lexicon_file_name = options.lexicon_file_name();
	const std::string &dic_file_name = options.dic_file_name();

	std::istream *lexicon_stream = &std::cin;
	std::ostream *dic_stream = &std::cout;

	// Opens a lexicon file.
	std::ifstream lexicon_file;
	if (lexicon_file_name != "-")
	{
		lexicon_file.open(lexicon_file_name.c_str(), std::ios::binary);
		if (!lexicon_file)
		{
			std::cerr << "error: failed to open LexiconFile: "
				<< lexicon_file_name << std::endl;
			return 1;
		}
		lexicon_stream = &lexicon_file;
	}

	// Opens a dictionary file.
	std::ofstream dic_file;
	if (dic_file_name != "-")
	{
		dic_file.open(dic_file_name.c_str(), std::ios::binary);
		if (!dic_file)
		{
			std::cerr << "error: failed to open DicFile: "
				<< dic_file_name << std::endl;
			return 1;
		}
		dic_stream = &dic_file;
	}

	dawgdic::Dawg dawg;
	if (!BuildDawg(lexicon_stream, &dawg, options.tab()))
		return 1;

	dawgdic::Dictionary dic;
	if (!BuildDictionary(dawg, &dic))
		return 1;

	if (!dic.Write(dic_stream))
	{
		std::cerr << "error: failed to write Dictionary" << std::endl;
		return 1;
	}

	// Builds a guide.
	if (options.ranked())
	{
		dawgdic::RankedGuide guide;
		if (!BuildRankedGuide(dawg, dic, &guide))
			return 1;
		if (!guide.Write(dic_stream))
		{
			std::cerr << "error: failed to write RankedGuide" << std::endl;
			return 1;
		}
	}
	else if (options.guide())
	{
		dawgdic::Guide guide;
		if (!BuildGuide(dawg, dic, &guide))
			return 1;
		if (!guide.Write(dic_stream))
		{
			std::cerr << "error: failed to write Guide" << std::endl;
			return 1;
		}
	}

	return 0;
}
<|endoftext|>


<commit_before>/*
* this file is part of the oxygen gtk engine
* Copyright (c) 2010 Hugo Pereira Da Costa <hugo@oxygen-icons.org>
* Copyright (c) 2010 Ruslan Kabatsayev <b7.10110111@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 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 St, Fifth Floor, Boston,
* MA 02110-1301, USA.
*/

#include "oxygenscrolledwindowdata.h"
#include "../oxygengtkutils.h"
#include "../config.h"

#include <cassert>
#include <iostream>

namespace Oxygen
{

    //_____________________________________________
    void ScrolledWindowData::connect( GtkWidget* widget )
    {
        assert( GTK_IS_SCROLLED_WINDOW( widget ) );
        assert( !_target );

        // store target
        _target = widget;

        // register scrollbars
        GtkScrolledWindow* scrolledWindow( GTK_SCROLLED_WINDOW( widget ) );

        if( GtkWidget* hScrollBar = gtk_scrolled_window_get_hscrollbar( scrolledWindow ) )
        { registerChild( hScrollBar ); }

        if( GtkWidget* vScrollBar = gtk_scrolled_window_get_vscrollbar( scrolledWindow ) )
        { registerChild( vScrollBar ); }

        // check child
        GtkWidget* child( gtk_bin_get_child( GTK_BIN( widget ) ) );
        if( !child ) return;

        #if OXYGEN_DEBUG
        std::cerr
            << "Oxygen::ScrolledWindowData::connect -"
            << " child: " << child << " (" << G_OBJECT_TYPE_NAME( child ) << ")"
            << std::endl;
        #endif

        if( GTK_IS_TREE_VIEW( child ) || GTK_IS_TEXT_VIEW( child ) || GTK_IS_ICON_VIEW( child ) )
        {

            registerChild( child );

        } else {

            // list widget types for which scrolled window needs register
            static const char* widgetTypes[] = { "ExoIconView", "FMIconContainer", 0L };
            for( unsigned int i = 0; widgetTypes[i]; i++ )
            {
                if( Gtk::g_object_is_a( G_OBJECT( child ), widgetTypes[i] ) )
                {
                    registerChild( child );
                    break;
                }
            }

        }

    }

    //_____________________________________________
    void ScrolledWindowData::disconnect( GtkWidget* widget )
    {
        _target = 0;
        for( ChildDataMap::iterator iter = _childrenData.begin(); iter != _childrenData.end(); ++iter )
        { iter->second.disconnect( iter->first ); }

        _childrenData.clear();
    }

    //________________________________________________________________________________
    void ScrolledWindowData::setHovered( GtkWidget* widget, bool value )
    {

        bool oldHover( hovered() );
        ChildDataMap::iterator iter( _childrenData.find( widget ) );
        if( iter != _childrenData.end() ) iter->second._hovered = value;
        else return;

        // need to schedule repaint of the whole widget
        if( oldHover != hovered() && _target ) gtk_widget_queue_draw( _target );

    }

    //________________________________________________________________________________
    void ScrolledWindowData::setFocused( GtkWidget* widget, bool value )
    {

        bool oldFocus( focused() );
        ChildDataMap::iterator iter( _childrenData.find( widget ) );
        if( iter != _childrenData.end() ) iter->second._focused = value;
        else return;

        // need to schedule repaint of the whole widget
        if( oldFocus != focused() && _target ) gtk_widget_queue_draw( _target );

    }

    //_____________________________________________
    void ScrolledWindowData::registerChild( GtkWidget* widget )
    {
        // make sure widget is not already in map
        if( _childrenData.find( widget ) == _childrenData.end() )
        {

            #if OXYGEN_DEBUG
            std::cerr
                << "Oxygen::ScrolledWindowData::registerChild -"
                << " " << widget << " (" << G_OBJECT_TYPE_NAME( widget ) << ")"
                << std::endl;
            #endif

            // adjust event mask
            gtk_widget_add_events( widget, GDK_ENTER_NOTIFY_MASK|GDK_LEAVE_NOTIFY_MASK|GDK_FOCUS_CHANGE_MASK );

            // allocate new Hover data
            ChildData data;
            data._destroyId.connect( G_OBJECT(widget), "destroy", G_CALLBACK( childDestroyNotifyEvent ), this );
            data._styleChangeId.connect( G_OBJECT(widget), "style-set", G_CALLBACK( childStyleChangeNotifyEvent ), this );
            data._enterId.connect( G_OBJECT(widget), "enter-notify-event", G_CALLBACK( enterNotifyEvent ), this );
            data._leaveId.connect( G_OBJECT(widget), "leave-notify-event", G_CALLBACK( leaveNotifyEvent ), this );
            data._focusInId.connect( G_OBJECT(widget), "focus-in-event", G_CALLBACK( focusInNotifyEvent ), this );
            data._focusOutId.connect( G_OBJECT(widget), "focus-out-event", G_CALLBACK( focusOutNotifyEvent ), this );

            // and insert in map
            _childrenData.insert( std::make_pair( widget, data ) );

            // set initial focus
            setFocused( widget, gtk_widget_has_focus( widget ) );

            // set initial hover
            const bool enabled( gtk_widget_get_state( widget ) != GTK_STATE_INSENSITIVE );

            // on connection, needs to check whether mouse pointer is in widget or not
            // to have the proper initial value of the hover flag
            if( enabled )
            {
                gint xPointer,yPointer;
                gdk_window_get_pointer( gtk_widget_get_window( widget ), &xPointer, &yPointer, 0L );
                const GtkAllocation allocation( Gtk::gtk_widget_get_allocation( widget ) );
                const GdkRectangle rect( Gtk::gdk_rectangle( 0, 0, allocation.width, allocation.height ) );
                setHovered( widget, Gtk::gdk_rectangle_contains( &rect, xPointer, yPointer ) );
            }

        }

    }

    //________________________________________________________________________________
    void ScrolledWindowData::unregisterChild( GtkWidget* widget )
    {

        // loopup in hover map
        ChildDataMap::iterator iter( _childrenData.find( widget ) );
        if( iter == _childrenData.end() ) return;

        #if OXYGEN_DEBUG
        std::cerr
            << "Oxygen::ScrolledWindowData::unregisterChild -"
            << " " << widget << " (" << G_OBJECT_TYPE_NAME( widget ) << ")"
            << std::endl;
        #endif

        iter->second.disconnect( widget );
        _childrenData.erase( iter );

    }

    //________________________________________________________________________________
    #if OXYGEN_DEBUG
    void ScrolledWindowData::ChildData::disconnect( GtkWidget* widget )
    #else
    void ScrolledWindowData::ChildData::disconnect( GtkWidget* )
    #endif
    {

        #if OXYGEN_DEBUG
        std::cerr
            << "Oxygen::ScrolledWindowData::ChildData::disconnect -"
            << " " << widget << " (" << G_OBJECT_TYPE_NAME( widget ) << ")"
            << std::endl;
        #endif

        _destroyId.disconnect();
        _styleChangeId.disconnect();
        _enterId.disconnect();
        _leaveId.disconnect();
        _focusInId.disconnect();
        _focusOutId.disconnect();
        _hovered = false;
        _focused = false;

    }

    //____________________________________________________________________________________________
    gboolean ScrolledWindowData::childDestroyNotifyEvent( GtkWidget* widget, gpointer data )
    {
        #if OXYGEN_DEBUG
        std::cerr
            << "Oxygen::ScrolledWindowData::childDestroyNotifyEvent -"
            << " " << widget << " (" << G_OBJECT_TYPE_NAME( widget ) << ")"
            << std::endl;
        #endif
        static_cast<ScrolledWindowData*>(data)->unregisterChild( widget );
        return FALSE;
    }

    //____________________________________________________________________________________________
    void ScrolledWindowData::childStyleChangeNotifyEvent( GtkWidget* widget, GtkStyle*, gpointer data )
    { static_cast<ScrolledWindowData*>(data)->unregisterChild( widget ); }

    //________________________________________________________________________________
    gboolean ScrolledWindowData::enterNotifyEvent( GtkWidget* widget, GdkEventCrossing* event, gpointer data )
    {

        #if OXYGEN_DEBUG
        std::cerr << "Oxygen::ScrolledWindowData::enterNotifyEvent -"
            << " " << widget << " (" << G_OBJECT_TYPE_NAME( widget ) << ")"
            << std::endl;
        #endif

        if( !(event->state & (GDK_BUTTON1_MASK|GDK_BUTTON2_MASK) ) )
        { static_cast<ScrolledWindowData*>( data )->setHovered( widget, true ); }

        return FALSE;
    }

    //________________________________________________________________________________
    gboolean ScrolledWindowData::leaveNotifyEvent( GtkWidget* widget, GdkEventCrossing* event, gpointer data )
    {

        #if OXYGEN_DEBUG
        std::cerr << "Oxygen::ScrolledWindowData::leaveNotifyEvent -"
            << " " << widget << " (" << G_OBJECT_TYPE_NAME( widget ) << ")"
            << std::endl;
        #endif

        if( !(event->state & (GDK_BUTTON1_MASK|GDK_BUTTON2_MASK) ) )
        { static_cast<ScrolledWindowData*>( data )->setHovered( widget, false ); }

        return FALSE;
    }

    //________________________________________________________________________________
    gboolean ScrolledWindowData::focusInNotifyEvent( GtkWidget* widget, GdkEvent*, gpointer data )
    {

        #if OXYGEN_DEBUG
        std::cerr << "Oxygen::ScrolledWindowData::focusInNotifyEvent -"
            << " " << widget << " (" << G_OBJECT_TYPE_NAME( widget ) << ")"
            << std::endl;
        #endif

        static_cast<ScrolledWindowData*>( data )->setFocused( widget, true );
        return FALSE;
    }

    //________________________________________________________________________________
    gboolean ScrolledWindowData::focusOutNotifyEvent( GtkWidget* widget, GdkEvent*, gpointer data )
    {

        #if OXYGEN_DEBUG
        std::cerr << "Oxygen::ScrolledWindowData::focusOutNotifyEvent -"
            << " " << widget << " (" << G_OBJECT_TYPE_NAME( widget ) << ")"
            << std::endl;
        #endif

        static_cast<ScrolledWindowData*>( data )->setFocused( widget, false );
        return FALSE;
    }

}
<commit_msg>added protection against undefined window when registering ScrolledWindow child to engine.<commit_after>/*
* this file is part of the oxygen gtk engine
* Copyright (c) 2010 Hugo Pereira Da Costa <hugo@oxygen-icons.org>
* Copyright (c) 2010 Ruslan Kabatsayev <b7.10110111@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 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 St, Fifth Floor, Boston,
* MA 02110-1301, USA.
*/

#include "oxygenscrolledwindowdata.h"
#include "../oxygengtkutils.h"
#include "../config.h"

#include <cassert>
#include <iostream>

namespace Oxygen
{

    //_____________________________________________
    void ScrolledWindowData::connect( GtkWidget* widget )
    {
        assert( GTK_IS_SCROLLED_WINDOW( widget ) );
        assert( !_target );

        // store target
        _target = widget;

        // register scrollbars
        GtkScrolledWindow* scrolledWindow( GTK_SCROLLED_WINDOW( widget ) );

        if( GtkWidget* hScrollBar = gtk_scrolled_window_get_hscrollbar( scrolledWindow ) )
        { registerChild( hScrollBar ); }

        if( GtkWidget* vScrollBar = gtk_scrolled_window_get_vscrollbar( scrolledWindow ) )
        { registerChild( vScrollBar ); }

        // check child
        GtkWidget* child( gtk_bin_get_child( GTK_BIN( widget ) ) );
        if( !child ) return;

        #if OXYGEN_DEBUG
        std::cerr
            << "Oxygen::ScrolledWindowData::connect -"
            << " child: " << child << " (" << G_OBJECT_TYPE_NAME( child ) << ")"
            << std::endl;
        #endif

        if( GTK_IS_TREE_VIEW( child ) || GTK_IS_TEXT_VIEW( child ) || GTK_IS_ICON_VIEW( child ) )
        {

            registerChild( child );

        } else {

            // list widget types for which scrolled window needs register
            static const char* widgetTypes[] = { "ExoIconView", "FMIconContainer", 0L };
            for( unsigned int i = 0; widgetTypes[i]; i++ )
            {
                if( Gtk::g_object_is_a( G_OBJECT( child ), widgetTypes[i] ) )
                {
                    registerChild( child );
                    break;
                }
            }

        }

    }

    //_____________________________________________
    void ScrolledWindowData::disconnect( GtkWidget* widget )
    {
        _target = 0;
        for( ChildDataMap::iterator iter = _childrenData.begin(); iter != _childrenData.end(); ++iter )
        { iter->second.disconnect( iter->first ); }

        _childrenData.clear();
    }

    //________________________________________________________________________________
    void ScrolledWindowData::setHovered( GtkWidget* widget, bool value )
    {

        bool oldHover( hovered() );
        ChildDataMap::iterator iter( _childrenData.find( widget ) );
        if( iter != _childrenData.end() ) iter->second._hovered = value;
        else return;

        // need to schedule repaint of the whole widget
        if( oldHover != hovered() && _target ) gtk_widget_queue_draw( _target );

    }

    //________________________________________________________________________________
    void ScrolledWindowData::setFocused( GtkWidget* widget, bool value )
    {

        bool oldFocus( focused() );
        ChildDataMap::iterator iter( _childrenData.find( widget ) );
        if( iter != _childrenData.end() ) iter->second._focused = value;
        else return;

        // need to schedule repaint of the whole widget
        if( oldFocus != focused() && _target ) gtk_widget_queue_draw( _target );

    }

    //_____________________________________________
    void ScrolledWindowData::registerChild( GtkWidget* widget )
    {
        // make sure widget is not already in map
        if( _childrenData.find( widget ) == _childrenData.end() )
        {

            #if OXYGEN_DEBUG
            std::cerr
                << "Oxygen::ScrolledWindowData::registerChild -"
                << " " << widget << " (" << G_OBJECT_TYPE_NAME( widget ) << ")"
                << std::endl;
            #endif

            // adjust event mask
            gtk_widget_add_events( widget, GDK_ENTER_NOTIFY_MASK|GDK_LEAVE_NOTIFY_MASK|GDK_FOCUS_CHANGE_MASK );

            // allocate new Hover data
            ChildData data;
            data._destroyId.connect( G_OBJECT(widget), "destroy", G_CALLBACK( childDestroyNotifyEvent ), this );
            data._styleChangeId.connect( G_OBJECT(widget), "style-set", G_CALLBACK( childStyleChangeNotifyEvent ), this );
            data._enterId.connect( G_OBJECT(widget), "enter-notify-event", G_CALLBACK( enterNotifyEvent ), this );
            data._leaveId.connect( G_OBJECT(widget), "leave-notify-event", G_CALLBACK( leaveNotifyEvent ), this );
            data._focusInId.connect( G_OBJECT(widget), "focus-in-event", G_CALLBACK( focusInNotifyEvent ), this );
            data._focusOutId.connect( G_OBJECT(widget), "focus-out-event", G_CALLBACK( focusOutNotifyEvent ), this );

            // and insert in map
            _childrenData.insert( std::make_pair( widget, data ) );

            // set initial focus
            setFocused( widget, gtk_widget_has_focus( widget ) );

            // set initial hover
            const bool enabled( gtk_widget_get_state( widget ) != GTK_STATE_INSENSITIVE );

            // on connection, needs to check whether mouse pointer is in widget or not
            // to have the proper initial value of the hover flag
            if( enabled && gtk_widget_get_window( widget ) )
            {

                gint xPointer,yPointer;
                gdk_window_get_pointer( gtk_widget_get_window( widget ), &xPointer, &yPointer, 0L );
                const GtkAllocation allocation( Gtk::gtk_widget_get_allocation( widget ) );
                const GdkRectangle rect( Gtk::gdk_rectangle( 0, 0, allocation.width, allocation.height ) );
                setHovered( widget, Gtk::gdk_rectangle_contains( &rect, xPointer, yPointer ) );

            } else setHovered( widget, false );

        }

    }

    //________________________________________________________________________________
    void ScrolledWindowData::unregisterChild( GtkWidget* widget )
    {

        // loopup in hover map
        ChildDataMap::iterator iter( _childrenData.find( widget ) );
        if( iter == _childrenData.end() ) return;

        #if OXYGEN_DEBUG
        std::cerr
            << "Oxygen::ScrolledWindowData::unregisterChild -"
            << " " << widget << " (" << G_OBJECT_TYPE_NAME( widget ) << ")"
            << std::endl;
        #endif

        iter->second.disconnect( widget );
        _childrenData.erase( iter );

    }

    //________________________________________________________________________________
    #if OXYGEN_DEBUG
    void ScrolledWindowData::ChildData::disconnect( GtkWidget* widget )
    #else
    void ScrolledWindowData::ChildData::disconnect( GtkWidget* )
    #endif
    {

        #if OXYGEN_DEBUG
        std::cerr
            << "Oxygen::ScrolledWindowData::ChildData::disconnect -"
            << " " << widget << " (" << G_OBJECT_TYPE_NAME( widget ) << ")"
            << std::endl;
        #endif

        _destroyId.disconnect();
        _styleChangeId.disconnect();
        _enterId.disconnect();
        _leaveId.disconnect();
        _focusInId.disconnect();
        _focusOutId.disconnect();
        _hovered = false;
        _focused = false;

    }

    //____________________________________________________________________________________________
    gboolean ScrolledWindowData::childDestroyNotifyEvent( GtkWidget* widget, gpointer data )
    {
        #if OXYGEN_DEBUG
        std::cerr
            << "Oxygen::ScrolledWindowData::childDestroyNotifyEvent -"
            << " " << widget << " (" << G_OBJECT_TYPE_NAME( widget ) << ")"
            << std::endl;
        #endif
        static_cast<ScrolledWindowData*>(data)->unregisterChild( widget );
        return FALSE;
    }

    //____________________________________________________________________________________________
    void ScrolledWindowData::childStyleChangeNotifyEvent( GtkWidget* widget, GtkStyle*, gpointer data )
    { static_cast<ScrolledWindowData*>(data)->unregisterChild( widget ); }

    //________________________________________________________________________________
    gboolean ScrolledWindowData::enterNotifyEvent( GtkWidget* widget, GdkEventCrossing* event, gpointer data )
    {

        #if OXYGEN_DEBUG
        std::cerr << "Oxygen::ScrolledWindowData::enterNotifyEvent -"
            << " " << widget << " (" << G_OBJECT_TYPE_NAME( widget ) << ")"
            << std::endl;
        #endif

        if( !(event->state & (GDK_BUTTON1_MASK|GDK_BUTTON2_MASK) ) )
        { static_cast<ScrolledWindowData*>( data )->setHovered( widget, true ); }

        return FALSE;
    }

    //________________________________________________________________________________
    gboolean ScrolledWindowData::leaveNotifyEvent( GtkWidget* widget, GdkEventCrossing* event, gpointer data )
    {

        #if OXYGEN_DEBUG
        std::cerr << "Oxygen::ScrolledWindowData::leaveNotifyEvent -"
            << " " << widget << " (" << G_OBJECT_TYPE_NAME( widget ) << ")"
            << std::endl;
        #endif

        if( !(event->state & (GDK_BUTTON1_MASK|GDK_BUTTON2_MASK) ) )
        { static_cast<ScrolledWindowData*>( data )->setHovered( widget, false ); }

        return FALSE;
    }

    //________________________________________________________________________________
    gboolean ScrolledWindowData::focusInNotifyEvent( GtkWidget* widget, GdkEvent*, gpointer data )
    {

        #if OXYGEN_DEBUG
        std::cerr << "Oxygen::ScrolledWindowData::focusInNotifyEvent -"
            << " " << widget << " (" << G_OBJECT_TYPE_NAME( widget ) << ")"
            << std::endl;
        #endif

        static_cast<ScrolledWindowData*>( data )->setFocused( widget, true );
        return FALSE;
    }

    //________________________________________________________________________________
    gboolean ScrolledWindowData::focusOutNotifyEvent( GtkWidget* widget, GdkEvent*, gpointer data )
    {

        #if OXYGEN_DEBUG
        std::cerr << "Oxygen::ScrolledWindowData::focusOutNotifyEvent -"
            << " " << widget << " (" << G_OBJECT_TYPE_NAME( widget ) << ")"
            << std::endl;
        #endif

        static_cast<ScrolledWindowData*>( data )->setFocused( widget, false );
        return FALSE;
    }

}
<|endoftext|>


<commit_before>#ifndef ALEPH_TOPOLOGY_MAXIMAL_CLIQUES_HH__
#define ALEPH_TOPOLOGY_MAXIMAL_CLIQUES_HH__

#include <iterator>
#include <set>
#include <unordered_map>
#include <unordered_set>
#include <vector>

#include <aleph/math/SparseMatrix.hh>

#include <aleph/utilities/UnorderedSetOperations.hh>

#include <aleph/topology/SimplicialComplex.hh>

namespace aleph
{

namespace topology
{

namespace detail
{

/**
  Given a simplicial complex, calculates the vertex set for enumerating
  cliques. This function is able to handle simplicial complexes without
  zero-based indices. The remaining functions ensures that an index can
  be mapped back to the original complex.
*/

template <class SimplicialComplex> auto createInitialVertexSet( const SimplicialComplex& K )
  -> std::unordered_set<typename SimplicialComplex::ValueType::VertexType>
{
  using Simplex    = typename SimplicialComplex::ValueType;
  using VertexType = typename Simplex::VertexType;

  std::unordered_set<VertexType> vertices;
  K.vertices( std::inserter( vertices, vertices.begin() ) );

  std::unordered_set<VertexType> I;
  for( VertexType i = VertexType(); i < VertexType( vertices.size() ); i++ )
    I.insert( i );

  return I;
}

template <class Simplex> auto adjacencyMatrix( const SimplicialComplex<Simplex>& K ) -> math::SparseBinaryMatrix<typename Simplex::VertexType>
{
  using VertexType = typename Simplex::VertexType;
  using Matrix     = math::SparseBinaryMatrix<VertexType>;

  std::set<VertexType> vertices;
  K.vertices( std::inserter( vertices, vertices.begin() ) );

  // This is required for simplicial complexes in which the vertices do
  // not start at zero.
  std::unordered_map<VertexType, VertexType> vertex_to_id;

  {
    VertexType index = VertexType();
    for( auto&& vertex : vertices )
      vertex_to_id[vertex]  = index++;
  }

  Matrix A( VertexType( vertices.size() ) );

  for( auto itPair = K.range(1); itPair.first != itPair.second; ++itPair.first )
  {
    auto s = *itPair.first;

    // Map vertices (which may be arbitrary natural numbers) to the
    // corresponding column/row in the matrix (which are zero-based
    // and do not have gaps).
    auto u = vertex_to_id.at( s[0] );
    auto v = vertex_to_id.at( s[1] );

    A.set(u,v);
    A.set(v,u);
  }

  A.setIndices( vertices.begin(), vertices.end() );
  return A;
}

template <class VertexType>
void enumerateKoch( std::unordered_set<VertexType>& C,
                    std::unordered_set<VertexType>& I,
                    std::unordered_set<VertexType>& X,
                    std::vector< std::set<VertexType> >& cliques,
                    const math::SparseBinaryMatrix<VertexType>& A )
{
  if( I.empty() && X.empty() )
  {
    std::set<VertexType> newClique;
    for( auto&& c : C )
      newClique.insert( A.getIndex(c) );

    cliques.push_back( newClique );
    return;
  }

  // TODO: Is this the correct way of calculating the set? In the
  // algorithm, it appears that X and I are either both non-empty
  // or empty.
  if( I.empty() )
    return;

  // Pivot selection ---------------------------------------------------

  auto pivot     = *I.begin();
  auto maxDegree = VertexType(0);

  for( auto&& v : I )
  {
    auto degree = VertexType( A.numEntries(v) );
    if( degree > maxDegree )
    {
      pivot     = v;
      maxDegree = degree;
    }
  }

  // Bron--Kerbosch traversal ------------------------------------------

  for( auto it = I.begin(); it != I.end(); )
  {
    auto element = *it;

    // If the currently selected element is a neighbour of the pivot vertex,
    // just move on to another element.
    if( A.get(element, pivot) )
    {
      ++it;
      continue;
    }

    it = I.erase( it );

    std::unordered_set<VertexType> newC = C;
    newC.insert( element );

    std::unordered_set<VertexType> neighbours;
    A.get( element, std::inserter( neighbours, neighbours.begin() ) );

    std::unordered_set<VertexType> newI;
    std::unordered_set<VertexType> newX;

    using namespace aleph::utilities;

    set_intersection( I, neighbours, newI );
    set_intersection( X, neighbours, newX );

    enumerateKoch( newC,
                   newI,
                   newX,
                   cliques,
                   A );

    X.insert( element );
  }
}

template <class VertexType>
void enumerateBronKerbosch( std::unordered_set<VertexType>& C,
                            std::unordered_set<VertexType>& I,
                            std::unordered_set<VertexType>& X,
                            std::vector< std::set<VertexType> >& cliques,
                            const math::SparseBinaryMatrix<VertexType>& A )
{
  if( I.empty() && X.empty() )
  {
    std::set<VertexType> newClique;
    for( auto&& c : C )
      newClique.insert( A.getIndex(c) );

    cliques.push_back( newClique );
    return;
  }

  for( auto it = I.begin(); it != I.end(); )
  {
    auto element = *it;
    it = I.erase( it );

    auto newC = C;
    newC.insert( element );

    std::unordered_set<VertexType> neighbours;
    A.get( element, std::inserter( neighbours, neighbours.begin() ) );

    std::unordered_set<VertexType> newI;
    std::unordered_set<VertexType> newX;

    using namespace aleph::utilities;

    set_intersection( I, neighbours, newI );
    set_intersection( X, neighbours, newX );

    enumerateBronKerbosch( newC,
                           newI,
                           newX,
                           cliques,
                           A );

    X.insert( element );
  }
}

} // namespace detail

/**
  Enumerates all maximal cliques in the given simplicial complex by
  using Koch's modification of the Bron--Kerbosch algorithm for the
  enumeration of cliques.

  Cliques are returned in the form a 2-dimensional vector. For each
  clique, it contains the vertex indices.
*/

template <class Simplex> auto maximalCliquesKoch( const SimplicialComplex<Simplex>& K ) -> std::vector< std::set<typename Simplex::VertexType> >
{
  using VertexType = typename Simplex::VertexType;

  std::unordered_set<VertexType> C;
  std::unordered_set<VertexType> I = detail::createInitialVertexSet( K );
  std::unordered_set<VertexType> X;

  std::vector< std::set<VertexType> > cliques;

  detail::enumerateKoch( C, I, X, cliques, detail::adjacencyMatrix(K) );
  return cliques;
}

template <class Simplex> auto maximalCliquesBronKerbosch( const SimplicialComplex<Simplex>& K ) -> std::vector< std::set<typename Simplex::VertexType> >
{
  using VertexType = typename Simplex::VertexType;

  std::unordered_set<VertexType> C;
  std::unordered_set<VertexType> I = detail::createInitialVertexSet( K );
  std::unordered_set<VertexType> X;

  std::vector< std::set<VertexType> > cliques;

  detail::enumerateBronKerbosch( C, I, X, cliques, detail::adjacencyMatrix(K) );
  return cliques;
}

} // namespace topology

} // namespace aleph

#endif
<commit_msg>Fixed maximal clique calculation<commit_after>#ifndef ALEPH_TOPOLOGY_MAXIMAL_CLIQUES_HH__
#define ALEPH_TOPOLOGY_MAXIMAL_CLIQUES_HH__

#include <iterator>
#include <set>
#include <unordered_map>
#include <unordered_set>
#include <vector>

#include <aleph/math/SparseMatrix.hh>

#include <aleph/utilities/UnorderedSetOperations.hh>

#include <aleph/topology/SimplicialComplex.hh>

namespace aleph
{

namespace topology
{

namespace detail
{

/**
  Given a simplicial complex, calculates the vertex set for enumerating
  cliques. This function is able to handle simplicial complexes without
  zero-based indices. The remaining functions ensures that an index can
  be mapped back to the original complex.
*/

template <class SimplicialComplex> auto createInitialVertexSet( const SimplicialComplex& K )
  -> std::unordered_set<typename SimplicialComplex::ValueType::VertexType>
{
  using Simplex    = typename SimplicialComplex::ValueType;
  using VertexType = typename Simplex::VertexType;

  std::unordered_set<VertexType> vertices;
  K.vertices( std::inserter( vertices, vertices.begin() ) );

  std::unordered_set<VertexType> I;
  for( VertexType i = VertexType(); i < VertexType( vertices.size() ); i++ )
    I.insert( i );

  return I;
}

template <class Simplex> auto adjacencyMatrix( const SimplicialComplex<Simplex>& K ) -> math::SparseBinaryMatrix<typename Simplex::VertexType>
{
  using VertexType = typename Simplex::VertexType;
  using Matrix     = math::SparseBinaryMatrix<VertexType>;

  std::set<VertexType> vertices;
  K.vertices( std::inserter( vertices, vertices.begin() ) );

  // This is required for simplicial complexes in which the vertices do
  // not start at zero.
  std::unordered_map<VertexType, VertexType> vertex_to_id;

  {
    VertexType index = VertexType();
    for( auto&& vertex : vertices )
      vertex_to_id[vertex]  = index++;
  }

  Matrix A( VertexType( vertices.size() ) );

  for( auto itPair = K.range(1); itPair.first != itPair.second; ++itPair.first )
  {
    auto s = *itPair.first;

    // Map vertices (which may be arbitrary natural numbers) to the
    // corresponding column/row in the matrix (which are zero-based
    // and do not have gaps).
    auto u = vertex_to_id.at( s[0] );
    auto v = vertex_to_id.at( s[1] );

    A.set(u,v);
    A.set(v,u);
  }

  A.setIndices( vertices.begin(), vertices.end() );
  return A;
}

template <class VertexType>
void enumerateKoch( std::unordered_set<VertexType>& C,
                    std::unordered_set<VertexType>& I,
                    std::unordered_set<VertexType>& X,
                    std::vector< std::set<VertexType> >& cliques,
                    const math::SparseBinaryMatrix<VertexType>& A )
{
  if( I.empty() && X.empty() )
  {
    std::set<VertexType> newClique;
    for( auto&& c : C )
      newClique.insert( A.getIndex(c) );

    cliques.push_back( newClique );
    return;
  }

  if( I.empty() )
    return;

  // Pivot selection ---------------------------------------------------

  auto pivot     = *I.begin();
  auto maxDegree = VertexType(0);

  for( auto&& v : I )
  {
    auto degree = VertexType( A.numEntries(v) );
    if( degree > maxDegree )
    {
      pivot     = v;
      maxDegree = degree;
    }
  }

  // Bron--Kerbosch traversal ------------------------------------------

  for( auto it = I.begin(); it != I.end(); )
  {
    auto element = *it;

    // If the currently selected element is a neighbour of the pivot vertex,
    // just move on to another element.
    if( A.get(element, pivot) )
    {
      ++it;
      continue;
    }

    it = I.erase( it );

    std::unordered_set<VertexType> newC = C;
    newC.insert( element );

    std::unordered_set<VertexType> neighbours;
    A.get( element, std::inserter( neighbours, neighbours.begin() ) );

    std::unordered_set<VertexType> newI;
    std::unordered_set<VertexType> newX;

    using namespace aleph::utilities;

    set_intersection( I, neighbours, newI );
    set_intersection( X, neighbours, newX );

    enumerateKoch( newC,
                   newI,
                   newX,
                   cliques,
                   A );

    X.insert( element );
  }
}

template <class VertexType>
void enumerateBronKerbosch( std::unordered_set<VertexType>& C,
                            std::unordered_set<VertexType>& I,
                            std::unordered_set<VertexType>& X,
                            std::vector< std::set<VertexType> >& cliques,
                            const math::SparseBinaryMatrix<VertexType>& A )
{
  if( I.empty() && X.empty() )
  {
    std::set<VertexType> newClique;
    for( auto&& c : C )
      newClique.insert( A.getIndex(c) );

    cliques.push_back( newClique );
    return;
  }

  for( auto it = I.begin(); it != I.end(); )
  {
    auto element = *it;
    it = I.erase( it );

    auto newC = C;
    newC.insert( element );

    std::unordered_set<VertexType> neighbours;
    A.get( element, std::inserter( neighbours, neighbours.begin() ) );

    std::unordered_set<VertexType> newI;
    std::unordered_set<VertexType> newX;

    using namespace aleph::utilities;

    set_intersection( I, neighbours, newI );
    set_intersection( X, neighbours, newX );

    enumerateBronKerbosch( newC,
                           newI,
                           newX,
                           cliques,
                           A );

    X.insert( element );
  }
}

} // namespace detail

/**
  Enumerates all maximal cliques in the given simplicial complex by
  using Koch's modification of the Bron--Kerbosch algorithm for the
  enumeration of cliques.

  Cliques are returned in the form a 2-dimensional vector. For each
  clique, it contains the vertex indices.
*/

template <class Simplex> auto maximalCliquesKoch( const SimplicialComplex<Simplex>& K ) -> std::vector< std::set<typename Simplex::VertexType> >
{
  using VertexType = typename Simplex::VertexType;

  std::unordered_set<VertexType> C;
  std::unordered_set<VertexType> I = detail::createInitialVertexSet( K );
  std::unordered_set<VertexType> X;

  std::vector< std::set<VertexType> > cliques;

  detail::enumerateKoch( C, I, X, cliques, detail::adjacencyMatrix(K) );
  return cliques;
}

template <class Simplex> auto maximalCliquesBronKerbosch( const SimplicialComplex<Simplex>& K ) -> std::vector< std::set<typename Simplex::VertexType> >
{
  using VertexType = typename Simplex::VertexType;

  std::unordered_set<VertexType> C;
  std::unordered_set<VertexType> I = detail::createInitialVertexSet( K );
  std::unordered_set<VertexType> X;

  std::vector< std::set<VertexType> > cliques;

  detail::enumerateBronKerbosch( C, I, X, cliques, detail::adjacencyMatrix(K) );
  return cliques;
}

} // namespace topology

} // namespace aleph

#endif
<|endoftext|>


<commit_before>#include "Memory.h"

#include <vector>
#include <iostream>
#include <iomanip>
#include <cstdint>
#include <cassert>

#include <llvm/IR/GlobalVariable.h>
#include <llvm/IR/Function.h>
#include <llvm/IR/IntrinsicInst.h>

#include "Type.h"
#include "Runtime.h"
#include "GasMeter.h"
#include "Endianness.h"
#include "RuntimeManager.h"

namespace dev
{
namespace eth
{
namespace jit
{

Memory::Memory(RuntimeManager& _runtimeManager, GasMeter& _gasMeter):
	RuntimeHelper(_runtimeManager),
	m_gasMeter(_gasMeter)
{
	auto module = getModule();
	llvm::Type* argTypes[] = {Type::Word, Type::Word};
	auto dumpTy = llvm::FunctionType::get(m_builder.getVoidTy(), llvm::ArrayRef<llvm::Type*>(argTypes), false);
	m_memDump = llvm::Function::Create(dumpTy, llvm::GlobalValue::LinkageTypes::ExternalLinkage,
									   "evmccrt_memory_dump", module);

	m_data = new llvm::GlobalVariable(*module, Type::BytePtr, false, llvm::GlobalVariable::PrivateLinkage, llvm::UndefValue::get(Type::BytePtr), "mem.data");
	m_data->setUnnamedAddr(true); // Address is not important

	m_size = new llvm::GlobalVariable(*module, Type::Word, false, llvm::GlobalVariable::PrivateLinkage, Constant::get(0), "mem.size");
	m_size->setUnnamedAddr(true); // Address is not important

	llvm::Type* resizeArgs[] = {Type::RuntimePtr, Type::WordPtr};
	m_resize = llvm::Function::Create(llvm::FunctionType::get(Type::BytePtr, resizeArgs, false), llvm::Function::ExternalLinkage, "mem_resize", module);
	llvm::AttrBuilder attrBuilder;
	attrBuilder.addAttribute(llvm::Attribute::NoAlias).addAttribute(llvm::Attribute::NoCapture).addAttribute(llvm::Attribute::NonNull).addAttribute(llvm::Attribute::ReadOnly);
	m_resize->setAttributes(llvm::AttributeSet::get(m_resize->getContext(), 1, attrBuilder));

	m_require = createRequireFunc(_gasMeter, _runtimeManager);
	m_loadWord = createFunc(false, Type::Word, _gasMeter);
	m_storeWord = createFunc(true, Type::Word, _gasMeter);
	m_storeByte = createFunc(true, Type::Byte,  _gasMeter);
}

llvm::Function* Memory::createRequireFunc(GasMeter& _gasMeter, RuntimeManager& _runtimeManager)
{
	llvm::Type* argTypes[] = {Type::Word, Type::Word};
	auto func = llvm::Function::Create(llvm::FunctionType::get(Type::Void, argTypes, false), llvm::Function::PrivateLinkage, "mem.require", getModule());
	auto offset = func->arg_begin();
	offset->setName("offset");
	auto size = offset->getNextNode();
	size->setName("size");

	auto checkBB = llvm::BasicBlock::Create(func->getContext(), "Check", func);
	auto resizeBB = llvm::BasicBlock::Create(func->getContext(), "Resize", func);
	auto returnBB = llvm::BasicBlock::Create(func->getContext(), "Return", func);

	InsertPointGuard guard(m_builder); // Restores insert point at function exit

	// BB "Check"
	m_builder.SetInsertPoint(checkBB);
	auto uaddWO = llvm::Intrinsic::getDeclaration(getModule(), llvm::Intrinsic::uadd_with_overflow, Type::Word);
	auto uaddRes = m_builder.CreateCall2(uaddWO, offset, size, "res");
	auto sizeRequired = m_builder.CreateExtractValue(uaddRes, 0, "sizeReq");
	auto overflow1 = m_builder.CreateExtractValue(uaddRes, 1, "overflow1");
	auto currSize = m_builder.CreateLoad(m_size, "currSize");
	auto tooSmall = m_builder.CreateICmpULE(currSize, sizeRequired, "tooSmall");
	auto resizeNeeded = m_builder.CreateOr(tooSmall, overflow1, "resizeNeeded");
	m_builder.CreateCondBr(resizeNeeded, resizeBB, returnBB); // OPT branch weights?

	// BB "Resize"
	m_builder.SetInsertPoint(resizeBB);
	// Check gas first
	uaddRes = m_builder.CreateCall2(uaddWO, sizeRequired, Constant::get(31), "res");
	auto wordsRequired = m_builder.CreateExtractValue(uaddRes, 0);
	auto overflow2 = m_builder.CreateExtractValue(uaddRes, 1, "overflow2");
	auto overflow = m_builder.CreateOr(overflow1, overflow2, "overflow");
	wordsRequired = m_builder.CreateSelect(overflow, Constant::get(-1), wordsRequired);
	wordsRequired = m_builder.CreateUDiv(wordsRequired, Constant::get(32), "wordsReq");
	sizeRequired = m_builder.CreateMul(wordsRequired, Constant::get(32), "roundedSizeReq");
	auto words = m_builder.CreateUDiv(currSize, Constant::get(32), "words");	// size is always 32*k
	auto newWords = m_builder.CreateSub(wordsRequired, words, "addtionalWords");
	_gasMeter.countMemory(newWords);
	// Resize
	m_builder.CreateStore(sizeRequired, m_size);
	auto newData = m_builder.CreateCall2(m_resize, _runtimeManager.getRuntimePtr(), m_size, "newData");
	m_builder.CreateStore(newData, m_data);
	m_builder.CreateBr(returnBB);

	// BB "Return"
	m_builder.SetInsertPoint(returnBB);
	m_builder.CreateRetVoid();
	return func;
}

llvm::Function* Memory::createFunc(bool _isStore, llvm::Type* _valueType, GasMeter&)
{
	auto isWord = _valueType == Type::Word;

	llvm::Type* storeArgs[] = {Type::Word, _valueType};
	auto name = _isStore ? isWord ? "mstore" : "mstore8" : "mload";
	auto funcType = _isStore ? llvm::FunctionType::get(Type::Void, storeArgs, false) : llvm::FunctionType::get(Type::Word, Type::Word, false);
	auto func = llvm::Function::Create(funcType, llvm::Function::PrivateLinkage, name, getModule());

	InsertPointGuard guard(m_builder); // Restores insert point at function exit

	m_builder.SetInsertPoint(llvm::BasicBlock::Create(func->getContext(), {}, func));
	llvm::Value* index = func->arg_begin();
	index->setName("index");

	auto valueSize = _valueType->getPrimitiveSizeInBits() / 8;
	this->require(index, Constant::get(valueSize));
	auto ptr = getBytePtr(index);
	if (isWord)
		ptr = m_builder.CreateBitCast(ptr, Type::WordPtr, "wordPtr");
	if (_isStore)
	{
		llvm::Value* value = ++func->arg_begin();
		value->setName("value");
		if (isWord)
			value = Endianness::toBE(m_builder, value);
		m_builder.CreateStore(value, ptr);
		m_builder.CreateRetVoid();
	}
	else
	{
		llvm::Value* ret = m_builder.CreateLoad(ptr);
		ret = Endianness::toNative(m_builder, ret);
		m_builder.CreateRet(ret);
	}

	return func;
}

llvm::Value* Memory::loadWord(llvm::Value* _addr)
{
	auto value = m_builder.CreateCall(m_loadWord, _addr);
	return value;
}

void Memory::storeWord(llvm::Value* _addr, llvm::Value* _word)
{
	m_builder.CreateCall2(m_storeWord, _addr, _word);
}

void Memory::storeByte(llvm::Value* _addr, llvm::Value* _word)
{
	auto byte = m_builder.CreateTrunc(_word, Type::Byte, "byte");
	m_builder.CreateCall2(m_storeByte, _addr, byte);
}

llvm::Value* Memory::getData()
{
	return m_builder.CreateLoad(m_data);
}

llvm::Value* Memory::getSize()
{
	return m_builder.CreateLoad(m_size);
}

llvm::Value* Memory::getBytePtr(llvm::Value* _index)
{
	auto data = m_builder.CreateLoad(m_data, "data");
	return m_builder.CreateGEP(data, _index, "ptr");
}

void Memory::require(llvm::Value* _offset, llvm::Value* _size)
{
	m_builder.CreateCall2(m_require, _offset, _size);
}

void Memory::copyBytes(llvm::Value* _srcPtr, llvm::Value* _srcSize, llvm::Value* _srcIdx,
					   llvm::Value* _destMemIdx, llvm::Value* _reqBytes)
{
	auto zero256 = llvm::ConstantInt::get(Type::Word, 0);

	require(_destMemIdx, _reqBytes);

	// Additional copy cost
	// TODO: This round ups to 32 happens in many places
	auto copyWords = m_builder.CreateUDiv(m_builder.CreateAdd(_reqBytes, Constant::get(31)), Constant::get(32));
	m_gasMeter.countCopy(copyWords);

	auto srcPtr = m_builder.CreateGEP(_srcPtr, _srcIdx, "src_idx");

	auto memPtr = getData();
	auto destPtr = m_builder.CreateGEP(memPtr, _destMemIdx, "dest_mem_ptr");

	// remaining source bytes:
	auto remSrcSize = m_builder.CreateSub(_srcSize, _srcIdx);
	auto remSizeNegative = m_builder.CreateICmpSLT(remSrcSize, zero256);
	auto remSrcBytes = m_builder.CreateSelect(remSizeNegative, zero256, remSrcSize, "rem_src_bytes");

	auto tooFewSrcBytes = m_builder.CreateICmpULT(remSrcBytes, _reqBytes);
	auto bytesToCopy = m_builder.CreateSelect(tooFewSrcBytes, remSrcBytes, _reqBytes, "bytes_to_copy");

	m_builder.CreateMemCpy(destPtr, srcPtr, bytesToCopy, 0);
}

}
}
}

extern "C"
{
	using namespace dev::eth::jit;

	EXPORT byte* mem_resize(Runtime* _rt, i256* _size)	// TODO: Use uint64 as size OR use realloc in LLVM IR
	{
		auto size = _size->a; // Trunc to 64-bit
		auto& memory = _rt->getMemory();
		memory.resize(size);
		return memory.data();
	}
}
<commit_msg>Fix checking memory requirements with size 0<commit_after>#include "Memory.h"

#include <vector>
#include <iostream>
#include <iomanip>
#include <cstdint>
#include <cassert>

#include <llvm/IR/GlobalVariable.h>
#include <llvm/IR/Function.h>
#include <llvm/IR/IntrinsicInst.h>

#include "Type.h"
#include "Runtime.h"
#include "GasMeter.h"
#include "Endianness.h"
#include "RuntimeManager.h"

namespace dev
{
namespace eth
{
namespace jit
{

Memory::Memory(RuntimeManager& _runtimeManager, GasMeter& _gasMeter):
	RuntimeHelper(_runtimeManager),
	m_gasMeter(_gasMeter)
{
	auto module = getModule();
	llvm::Type* argTypes[] = {Type::Word, Type::Word};
	auto dumpTy = llvm::FunctionType::get(m_builder.getVoidTy(), llvm::ArrayRef<llvm::Type*>(argTypes), false);
	m_memDump = llvm::Function::Create(dumpTy, llvm::GlobalValue::LinkageTypes::ExternalLinkage,
									   "evmccrt_memory_dump", module);

	m_data = new llvm::GlobalVariable(*module, Type::BytePtr, false, llvm::GlobalVariable::PrivateLinkage, llvm::UndefValue::get(Type::BytePtr), "mem.data");
	m_data->setUnnamedAddr(true); // Address is not important

	m_size = new llvm::GlobalVariable(*module, Type::Word, false, llvm::GlobalVariable::PrivateLinkage, Constant::get(0), "mem.size");
	m_size->setUnnamedAddr(true); // Address is not important

	llvm::Type* resizeArgs[] = {Type::RuntimePtr, Type::WordPtr};
	m_resize = llvm::Function::Create(llvm::FunctionType::get(Type::BytePtr, resizeArgs, false), llvm::Function::ExternalLinkage, "mem_resize", module);
	llvm::AttrBuilder attrBuilder;
	attrBuilder.addAttribute(llvm::Attribute::NoAlias).addAttribute(llvm::Attribute::NoCapture).addAttribute(llvm::Attribute::NonNull).addAttribute(llvm::Attribute::ReadOnly);
	m_resize->setAttributes(llvm::AttributeSet::get(m_resize->getContext(), 1, attrBuilder));

	m_require = createRequireFunc(_gasMeter, _runtimeManager);
	m_loadWord = createFunc(false, Type::Word, _gasMeter);
	m_storeWord = createFunc(true, Type::Word, _gasMeter);
	m_storeByte = createFunc(true, Type::Byte,  _gasMeter);
}

llvm::Function* Memory::createRequireFunc(GasMeter& _gasMeter, RuntimeManager& _runtimeManager)
{
	llvm::Type* argTypes[] = {Type::Word, Type::Word};
	auto func = llvm::Function::Create(llvm::FunctionType::get(Type::Void, argTypes, false), llvm::Function::PrivateLinkage, "mem.require", getModule());
	auto offset = func->arg_begin();
	offset->setName("offset");
	auto size = offset->getNextNode();
	size->setName("size");

	auto preBB = llvm::BasicBlock::Create(func->getContext(), "Pre", func);
	auto checkBB = llvm::BasicBlock::Create(func->getContext(), "Check", func);
	auto resizeBB = llvm::BasicBlock::Create(func->getContext(), "Resize", func);
	auto returnBB = llvm::BasicBlock::Create(func->getContext(), "Return", func);

	InsertPointGuard guard(m_builder); // Restores insert point at function exit

	// BB "Pre": Ignore checks with size 0
	m_builder.SetInsertPoint(preBB);
	auto sizeIsZero = m_builder.CreateICmpEQ(size, Constant::get(0));
	m_builder.CreateCondBr(sizeIsZero, returnBB, checkBB);

	// BB "Check"
	m_builder.SetInsertPoint(checkBB);
	auto uaddWO = llvm::Intrinsic::getDeclaration(getModule(), llvm::Intrinsic::uadd_with_overflow, Type::Word);
	auto uaddRes = m_builder.CreateCall2(uaddWO, offset, size, "res");
	auto sizeRequired = m_builder.CreateExtractValue(uaddRes, 0, "sizeReq");
	auto overflow1 = m_builder.CreateExtractValue(uaddRes, 1, "overflow1");
	auto currSize = m_builder.CreateLoad(m_size, "currSize");
	auto tooSmall = m_builder.CreateICmpULE(currSize, sizeRequired, "tooSmall");
	auto resizeNeeded = m_builder.CreateOr(tooSmall, overflow1, "resizeNeeded");
	m_builder.CreateCondBr(resizeNeeded, resizeBB, returnBB); // OPT branch weights?

	// BB "Resize"
	m_builder.SetInsertPoint(resizeBB);
	// Check gas first
	uaddRes = m_builder.CreateCall2(uaddWO, sizeRequired, Constant::get(31), "res");
	auto wordsRequired = m_builder.CreateExtractValue(uaddRes, 0);
	auto overflow2 = m_builder.CreateExtractValue(uaddRes, 1, "overflow2");
	auto overflow = m_builder.CreateOr(overflow1, overflow2, "overflow");
	wordsRequired = m_builder.CreateSelect(overflow, Constant::get(-1), wordsRequired);
	wordsRequired = m_builder.CreateUDiv(wordsRequired, Constant::get(32), "wordsReq");
	sizeRequired = m_builder.CreateMul(wordsRequired, Constant::get(32), "roundedSizeReq");
	auto words = m_builder.CreateUDiv(currSize, Constant::get(32), "words");	// size is always 32*k
	auto newWords = m_builder.CreateSub(wordsRequired, words, "addtionalWords");
	_gasMeter.countMemory(newWords);
	// Resize
	m_builder.CreateStore(sizeRequired, m_size);
	auto newData = m_builder.CreateCall2(m_resize, _runtimeManager.getRuntimePtr(), m_size, "newData");
	m_builder.CreateStore(newData, m_data);
	m_builder.CreateBr(returnBB);

	// BB "Return"
	m_builder.SetInsertPoint(returnBB);
	m_builder.CreateRetVoid();
	return func;
}

llvm::Function* Memory::createFunc(bool _isStore, llvm::Type* _valueType, GasMeter&)
{
	auto isWord = _valueType == Type::Word;

	llvm::Type* storeArgs[] = {Type::Word, _valueType};
	auto name = _isStore ? isWord ? "mstore" : "mstore8" : "mload";
	auto funcType = _isStore ? llvm::FunctionType::get(Type::Void, storeArgs, false) : llvm::FunctionType::get(Type::Word, Type::Word, false);
	auto func = llvm::Function::Create(funcType, llvm::Function::PrivateLinkage, name, getModule());

	InsertPointGuard guard(m_builder); // Restores insert point at function exit

	m_builder.SetInsertPoint(llvm::BasicBlock::Create(func->getContext(), {}, func));
	llvm::Value* index = func->arg_begin();
	index->setName("index");

	auto valueSize = _valueType->getPrimitiveSizeInBits() / 8;
	this->require(index, Constant::get(valueSize));
	auto ptr = getBytePtr(index);
	if (isWord)
		ptr = m_builder.CreateBitCast(ptr, Type::WordPtr, "wordPtr");
	if (_isStore)
	{
		llvm::Value* value = ++func->arg_begin();
		value->setName("value");
		if (isWord)
			value = Endianness::toBE(m_builder, value);
		m_builder.CreateStore(value, ptr);
		m_builder.CreateRetVoid();
	}
	else
	{
		llvm::Value* ret = m_builder.CreateLoad(ptr);
		ret = Endianness::toNative(m_builder, ret);
		m_builder.CreateRet(ret);
	}

	return func;
}

llvm::Value* Memory::loadWord(llvm::Value* _addr)
{
	auto value = m_builder.CreateCall(m_loadWord, _addr);
	return value;
}

void Memory::storeWord(llvm::Value* _addr, llvm::Value* _word)
{
	m_builder.CreateCall2(m_storeWord, _addr, _word);
}

void Memory::storeByte(llvm::Value* _addr, llvm::Value* _word)
{
	auto byte = m_builder.CreateTrunc(_word, Type::Byte, "byte");
	m_builder.CreateCall2(m_storeByte, _addr, byte);
}

llvm::Value* Memory::getData()
{
	return m_builder.CreateLoad(m_data);
}

llvm::Value* Memory::getSize()
{
	return m_builder.CreateLoad(m_size);
}

llvm::Value* Memory::getBytePtr(llvm::Value* _index)
{
	auto data = m_builder.CreateLoad(m_data, "data");
	return m_builder.CreateGEP(data, _index, "ptr");
}

void Memory::require(llvm::Value* _offset, llvm::Value* _size)
{
	m_builder.CreateCall2(m_require, _offset, _size);
}

void Memory::copyBytes(llvm::Value* _srcPtr, llvm::Value* _srcSize, llvm::Value* _srcIdx,
					   llvm::Value* _destMemIdx, llvm::Value* _reqBytes)
{
	auto zero256 = llvm::ConstantInt::get(Type::Word, 0);

	require(_destMemIdx, _reqBytes);

	// Additional copy cost
	// TODO: This round ups to 32 happens in many places
	auto copyWords = m_builder.CreateUDiv(m_builder.CreateAdd(_reqBytes, Constant::get(31)), Constant::get(32));
	m_gasMeter.countCopy(copyWords);

	auto srcPtr = m_builder.CreateGEP(_srcPtr, _srcIdx, "src_idx");

	auto memPtr = getData();
	auto destPtr = m_builder.CreateGEP(memPtr, _destMemIdx, "dest_mem_ptr");

	// remaining source bytes:
	auto remSrcSize = m_builder.CreateSub(_srcSize, _srcIdx);
	auto remSizeNegative = m_builder.CreateICmpSLT(remSrcSize, zero256);
	auto remSrcBytes = m_builder.CreateSelect(remSizeNegative, zero256, remSrcSize, "rem_src_bytes");

	auto tooFewSrcBytes = m_builder.CreateICmpULT(remSrcBytes, _reqBytes);
	auto bytesToCopy = m_builder.CreateSelect(tooFewSrcBytes, remSrcBytes, _reqBytes, "bytes_to_copy");

	m_builder.CreateMemCpy(destPtr, srcPtr, bytesToCopy, 0);
}

}
}
}

extern "C"
{
	using namespace dev::eth::jit;

	EXPORT byte* mem_resize(Runtime* _rt, i256* _size)	// TODO: Use uint64 as size OR use realloc in LLVM IR
	{
		auto size = _size->a; // Trunc to 64-bit
		auto& memory = _rt->getMemory();
		memory.resize(size);
		return memory.data();
	}
}
<|endoftext|>