<commit_before>/*
    Copyright (c) 2007 Volker Krause <vkrause@kde.org>

    This library is free software; you can redistribute it and/or modify it
    under the terms of the GNU Library General Public License 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 Library General Public
    License for more details.

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

#include "notificationmessage_p.h"

#include "imapparser_p.h"

#include <QtCore/QDebug>
#include <QtCore/QHash>
#include <QtDBus/QDBusMetaType>

using namespace Akonadi;

class NotificationMessage::Private : public QSharedData
{
  public:
    Private()
      : QSharedData(),
        type( NotificationMessage::InvalidType ),
        operation( NotificationMessage::InvalidOp ),
        uid( -1 ),
        parentCollection( -1 ),
        parentDestCollection( -1 )
    {
    }

    Private( const Private &other )
      : QSharedData( other )
    {
      sessionId = other.sessionId;
      type = other.type;
      operation = other.operation;
      uid = other.uid;
      remoteId = other.remoteId;
      resource = other.resource;
      destResource = other.destResource;
      parentCollection = other.parentCollection;
      parentDestCollection = other.parentDestCollection;
      mimeType = other.mimeType;
      parts = other.parts;
    }

    bool compareWithoutOpAndParts( const Private &other ) const
    {
      return uid == other.uid
          && type == other.type
          && sessionId == other.sessionId
          && remoteId == other.remoteId
          && resource == other.resource
          && destResource == other.destResource
          && parentCollection == other.parentCollection
          && parentDestCollection == other.parentDestCollection
          && mimeType == other.mimeType;
    }

    bool operator==( const Private &other ) const
    {
      return operation == other.operation && parts == other.parts && compareWithoutOpAndParts( other );
    }

    QByteArray sessionId;
    NotificationMessage::Type type;
    NotificationMessage::Operation operation;
    Id uid;
    QString remoteId;
    QByteArray resource;
    QByteArray destResource;
    Id parentCollection;
    Id parentDestCollection;
    QString mimeType;
    QSet<QByteArray> parts;
};

NotificationMessage::NotificationMessage()
  : d( new Private )
{
}

NotificationMessage::NotificationMessage( const NotificationMessage &other )
  : d( other.d )
{
}

NotificationMessage::~NotificationMessage()
{
}

NotificationMessage& NotificationMessage::operator=( const NotificationMessage &other )
{
  if ( this != &other )
    d = other.d;

  return *this;
}

bool NotificationMessage::operator==( const NotificationMessage &other ) const
{
  return d == other.d;
}

void NotificationMessage::registerDBusTypes()
{
  qDBusRegisterMetaType<Akonadi::NotificationMessage>();
  qDBusRegisterMetaType<Akonadi::NotificationMessage::List>();
}

QByteArray NotificationMessage::sessionId() const
{
  return d->sessionId;
}

void NotificationMessage::setSessionId( const QByteArray &sessionId )
{
  d->sessionId = sessionId;
}

NotificationMessage::Type NotificationMessage::type() const
{
  return d->type;
}

void NotificationMessage::setType( Type type )
{
  d->type = type;
}

NotificationMessage::Operation NotificationMessage::operation() const
{
  return d->operation;
}

void NotificationMessage::setOperation( Operation operation )
{
  d->operation = operation;
}

NotificationMessage::Id NotificationMessage::uid() const
{
  return d->uid;
}

void NotificationMessage::setUid( Id uid )
{
  d->uid = uid;
}

QString NotificationMessage::remoteId() const
{
  return d->remoteId;
}

void NotificationMessage::setRemoteId( const QString &remoteId )
{
  d->remoteId = remoteId;
}

QByteArray NotificationMessage::resource() const
{
  return d->resource;
}

void NotificationMessage::setResource( const QByteArray &resource )
{
  d->resource = resource;
}

NotificationMessage::Id NotificationMessage::parentCollection() const
{
  return d->parentCollection;
}

NotificationMessage::Id NotificationMessage::parentDestCollection() const
{
  return d->parentDestCollection;
}

void NotificationMessage::setParentCollection( Id parent )
{
  d->parentCollection = parent;
}

void NotificationMessage::setParentDestCollection( Id parent )
{
  d->parentDestCollection = parent;
}

void NotificationMessage::setDestinationResource( const QByteArray &destResource )
{
  d->destResource = destResource;
}

QByteArray NotificationMessage::destinationResource() const
{
  return d->destResource;
}

QString NotificationMessage::mimeType() const
{
  return d->mimeType;
}

void NotificationMessage::setMimeType( const QString &mimeType )
{
  d->mimeType = mimeType;
}

QSet<QByteArray> NotificationMessage::itemParts() const
{
  return d->parts;
}

void NotificationMessage::setItemParts( const QSet<QByteArray> &parts )
{
  d->parts = parts;
}

QString NotificationMessage::toString() const
{
  QString rv;
  switch ( type() ) {
    case Item:
      rv += QLatin1String( "Item " );
      break;
    case Collection:
      rv += QLatin1String( "Collection " );
      break;
    case InvalidType: // TODO: an error?
      break;
  }

  rv += QString::fromLatin1( "(%1, %2) " ).arg( uid() ).arg( remoteId() );
  if ( parentDestCollection() >= 0 )
    rv += QString::fromLatin1( "from " );
  else
    rv += QString::fromLatin1( "in " );

  if ( parentCollection() >= 0 )
    rv += QString::fromLatin1( "collection %1 " ).arg( parentCollection() );

  switch ( operation() ) {
    case Add:
      rv += QLatin1String( "added" );
      break;
    case Modify:
      rv += QLatin1String( "modified parts (" );
      rv += QString::fromLatin1( ImapParser::join( itemParts().toList(), ", " ) );
      rv += QLatin1String( ")" );
      break;
    case Move:
      rv += QLatin1String( "moved" );
      break;
    case Remove:
      rv += QLatin1String( "removed" );
      break;
    case Link:
      rv += QLatin1String( "linked" );
      break;
    case Unlink:
      rv += QLatin1String( "unlinked" );
      break;
    case Subscribe:
      rv += QLatin1String( "subscribed" );
      break;
    case Unsubscribe:
      rv += QLatin1String( "unsubscribed" );
      break;
    case InvalidOp: // TODO: an error?
      break;
  }

  if ( parentDestCollection() >= 0 )
    rv += QString::fromLatin1( "to collection %1" ).arg( parentDestCollection() );

  return rv;
}

void NotificationMessage::appendAndCompress( NotificationMessage::List &list, const NotificationMessage &msg )
{
  bool appended;
  appendAndCompress( list, msg, &appended );
}

void NotificationMessage::appendAndCompress( NotificationMessage::List &list, const NotificationMessage &msg, bool *appended )
{
  // fast-path for stuff that is not considered during O(n) compression below
  if ( msg.operation() != Add && msg.operation() != Link && msg.operation() != Unlink && msg.operation() != Subscribe && msg.operation() != Unsubscribe && msg.operation() != Move ) {
    NotificationMessage::List::Iterator end = list.end();
    for ( NotificationMessage::List::Iterator it = list.begin(); it != end; ) {
      if ( msg.d.constData()->compareWithoutOpAndParts( *((*it).d.constData()) ) ) {
        // same operation: merge changed parts and drop the new one
        if ( msg.operation() == (*it).operation() ) {
          (*it).setItemParts( (*it).itemParts() + msg.itemParts() );
          *appended = false;
          return;
        }
        // new one is a modification, the existing one not, so drop the new one
        else if ( msg.operation() == Modify ) {
          *appended = false;
          return;
        }
        // new on is a deletion, erase the existing modification ones (and keep going, in case there are more)
        else if ( msg.operation() == Remove && (*it).operation() == Modify ) {
          it = list.erase( it );
          end = list.end();
        }
        // keep looking
        else {
          ++it;
        }
      } else {
        ++it;
      }
    }
  }
  *appended = true;
  list.append( msg );
}

QDBusArgument& operator<<( QDBusArgument &arg, const NotificationMessage &msg )
{
  arg.beginStructure();
  arg << msg.sessionId();
  arg << msg.type();
  arg << msg.operation();
  arg << msg.uid();
  arg << msg.remoteId();
  arg << msg.resource();
  arg << msg.parentCollection();
  arg << msg.parentDestCollection();
  arg << msg.mimeType();

  QStringList itemParts;
  if ( msg.operation() == NotificationMessage::Move ) {
    // encode destination resource in parts, as a backward compat hack
    itemParts.push_back( QString::fromLatin1( msg.destinationResource() ) );
  } else {
    Q_FOREACH ( const QByteArray &itemPart, msg.itemParts() )
      itemParts.append( QString::fromLatin1( itemPart ) );
  }

  arg << itemParts;
  arg.endStructure();
  return arg;
}

const QDBusArgument& operator>>( const QDBusArgument &arg, NotificationMessage &msg )
{
  arg.beginStructure();
  QByteArray b;
  arg >> b;
  msg.setSessionId( b );
  int i;
  arg >> i;
  msg.setType( static_cast<NotificationMessage::Type>( i ) );
  arg >> i;
  msg.setOperation( static_cast<NotificationMessage::Operation>( i ) );
  NotificationMessage::Id id;
  arg >> id;
  msg.setUid( id );
  QString s;
  arg >> s;
  msg.setRemoteId( s );
  arg >> b;
  msg.setResource( b );
  arg >> id;
  msg.setParentCollection( id );
  arg >> id;
  msg.setParentDestCollection( id );
  arg >> s;
  msg.setMimeType( s );
  QStringList l;
  arg >> l;

  QSet<QByteArray> itemParts;
  if ( msg.operation() == NotificationMessage::Move && l.size() >= 1 ) {
    // decode destination resource, which is stored in parts as a backward compat hack
    msg.setDestinationResource( l.first().toLatin1() );
  } else {
    Q_FOREACH ( const QString &itemPart, l )
      itemParts.insert( itemPart.toLatin1() );
  }

  msg.setItemParts( itemParts );
  arg.endStructure();
  return arg;
}

uint qHash( const Akonadi::NotificationMessage &msg )
{
  return qHash( msg.uid() + (msg.type() << 31) + (msg.operation() << 28) );
}
<commit_msg>to get a better message, #108582<commit_after>/*
    Copyright (c) 2007 Volker Krause <vkrause@kde.org>

    This library is free software; you can redistribute it and/or modify it
    under the terms of the GNU Library General Public License 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 Library General Public
    License for more details.

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

#include "notificationmessage_p.h"

#include "imapparser_p.h"

#include <QtCore/QDebug>
#include <QtCore/QHash>
#include <QtDBus/QDBusMetaType>

using namespace Akonadi;

class NotificationMessage::Private : public QSharedData
{
  public:
    Private()
      : QSharedData(),
        type( NotificationMessage::InvalidType ),
        operation( NotificationMessage::InvalidOp ),
        uid( -1 ),
        parentCollection( -1 ),
        parentDestCollection( -1 )
    {
    }

    Private( const Private &other )
      : QSharedData( other )
    {
      sessionId = other.sessionId;
      type = other.type;
      operation = other.operation;
      uid = other.uid;
      remoteId = other.remoteId;
      resource = other.resource;
      destResource = other.destResource;
      parentCollection = other.parentCollection;
      parentDestCollection = other.parentDestCollection;
      mimeType = other.mimeType;
      parts = other.parts;
    }

    bool compareWithoutOpAndParts( const Private &other ) const
    {
      return uid == other.uid
          && type == other.type
          && sessionId == other.sessionId
          && remoteId == other.remoteId
          && resource == other.resource
          && destResource == other.destResource
          && parentCollection == other.parentCollection
          && parentDestCollection == other.parentDestCollection
          && mimeType == other.mimeType;
    }

    bool operator==( const Private &other ) const
    {
      return operation == other.operation && parts == other.parts && compareWithoutOpAndParts( other );
    }

    QByteArray sessionId;
    NotificationMessage::Type type;
    NotificationMessage::Operation operation;
    Id uid;
    QString remoteId;
    QByteArray resource;
    QByteArray destResource;
    Id parentCollection;
    Id parentDestCollection;
    QString mimeType;
    QSet<QByteArray> parts;
};

NotificationMessage::NotificationMessage()
  : d( new Private )
{
}

NotificationMessage::NotificationMessage( const NotificationMessage &other )
  : d( other.d )
{
}

NotificationMessage::~NotificationMessage()
{
}

NotificationMessage& NotificationMessage::operator=( const NotificationMessage &other )
{
  if ( this != &other )
    d = other.d;

  return *this;
}

bool NotificationMessage::operator==( const NotificationMessage &other ) const
{
  return d == other.d;
}

void NotificationMessage::registerDBusTypes()
{
  qDBusRegisterMetaType<Akonadi::NotificationMessage>();
  qDBusRegisterMetaType<Akonadi::NotificationMessage::List>();
}

QByteArray NotificationMessage::sessionId() const
{
  return d->sessionId;
}

void NotificationMessage::setSessionId( const QByteArray &sessionId )
{
  d->sessionId = sessionId;
}

NotificationMessage::Type NotificationMessage::type() const
{
  return d->type;
}

void NotificationMessage::setType( Type type )
{
  d->type = type;
}

NotificationMessage::Operation NotificationMessage::operation() const
{
  return d->operation;
}

void NotificationMessage::setOperation( Operation operation )
{
  d->operation = operation;
}

NotificationMessage::Id NotificationMessage::uid() const
{
  return d->uid;
}

void NotificationMessage::setUid( Id uid )
{
  d->uid = uid;
}

QString NotificationMessage::remoteId() const
{
  return d->remoteId;
}

void NotificationMessage::setRemoteId( const QString &remoteId )
{
  d->remoteId = remoteId;
}

QByteArray NotificationMessage::resource() const
{
  return d->resource;
}

void NotificationMessage::setResource( const QByteArray &resource )
{
  d->resource = resource;
}

NotificationMessage::Id NotificationMessage::parentCollection() const
{
  return d->parentCollection;
}

NotificationMessage::Id NotificationMessage::parentDestCollection() const
{
  return d->parentDestCollection;
}

void NotificationMessage::setParentCollection( Id parent )
{
  d->parentCollection = parent;
}

void NotificationMessage::setParentDestCollection( Id parent )
{
  d->parentDestCollection = parent;
}

void NotificationMessage::setDestinationResource( const QByteArray &destResource )
{
  d->destResource = destResource;
}

QByteArray NotificationMessage::destinationResource() const
{
  return d->destResource;
}

QString NotificationMessage::mimeType() const
{
  return d->mimeType;
}

void NotificationMessage::setMimeType( const QString &mimeType )
{
  d->mimeType = mimeType;
}

QSet<QByteArray> NotificationMessage::itemParts() const
{
  return d->parts;
}

void NotificationMessage::setItemParts( const QSet<QByteArray> &parts )
{
  d->parts = parts;
}

QString NotificationMessage::toString() const
{
  QString rv;
  switch ( type() ) {
    case Item:
      rv += QLatin1String( "Item " );
      break;
    case Collection:
      rv += QLatin1String( "Collection " );
      break;
    case InvalidType: // TODO: an error?
      break;
  }

  rv += QString::fromLatin1( "(%1, %2) " ).arg( uid() ).arg( remoteId() );
  if ( parentDestCollection() >= 0 )
    rv += QString::fromLatin1( "from " );
  else
    rv += QString::fromLatin1( "in " );

  if ( parentCollection() >= 0 )
    rv += QString::fromLatin1( "collection %1 " ).arg( parentCollection() );

  switch ( operation() ) {
    case Add:
      rv += QLatin1String( "added" );
      break;
    case Modify:
      rv += QLatin1String( "modified parts (" );
      rv += QString::fromLatin1( ImapParser::join( itemParts().toList(), ", " ) );
      rv += QLatin1String( ")" );
      break;
    case Move:
      rv += QLatin1String( "moved" );
      break;
    case Remove:
      rv += QLatin1String( "removed" );
      break;
    case Link:
      rv += QLatin1String( "linked" );
      break;
    case Unlink:
      rv += QLatin1String( "unlinked" );
      break;
    case Subscribe:
      rv += QLatin1String( "subscribed" );
      break;
    case Unsubscribe:
      rv += QLatin1String( "unsubscribed" );
      break;
    case InvalidOp: // TODO: an error?
      break;
  }

  if ( parentDestCollection() >= 0 )
    rv += QString::fromLatin1( " to collection %1" ).arg( parentDestCollection() );

  return rv;
}

void NotificationMessage::appendAndCompress( NotificationMessage::List &list, const NotificationMessage &msg )
{
  bool appended;
  appendAndCompress( list, msg, &appended );
}

void NotificationMessage::appendAndCompress( NotificationMessage::List &list, const NotificationMessage &msg, bool *appended )
{
  // fast-path for stuff that is not considered during O(n) compression below
  if ( msg.operation() != Add && msg.operation() != Link && msg.operation() != Unlink && msg.operation() != Subscribe && msg.operation() != Unsubscribe && msg.operation() != Move ) {
    NotificationMessage::List::Iterator end = list.end();
    for ( NotificationMessage::List::Iterator it = list.begin(); it != end; ) {
      if ( msg.d.constData()->compareWithoutOpAndParts( *((*it).d.constData()) ) ) {
        // same operation: merge changed parts and drop the new one
        if ( msg.operation() == (*it).operation() ) {
          (*it).setItemParts( (*it).itemParts() + msg.itemParts() );
          *appended = false;
          return;
        }
        // new one is a modification, the existing one not, so drop the new one
        else if ( msg.operation() == Modify ) {
          *appended = false;
          return;
        }
        // new on is a deletion, erase the existing modification ones (and keep going, in case there are more)
        else if ( msg.operation() == Remove && (*it).operation() == Modify ) {
          it = list.erase( it );
          end = list.end();
        }
        // keep looking
        else {
          ++it;
        }
      } else {
        ++it;
      }
    }
  }
  *appended = true;
  list.append( msg );
}

QDBusArgument& operator<<( QDBusArgument &arg, const NotificationMessage &msg )
{
  arg.beginStructure();
  arg << msg.sessionId();
  arg << msg.type();
  arg << msg.operation();
  arg << msg.uid();
  arg << msg.remoteId();
  arg << msg.resource();
  arg << msg.parentCollection();
  arg << msg.parentDestCollection();
  arg << msg.mimeType();

  QStringList itemParts;
  if ( msg.operation() == NotificationMessage::Move ) {
    // encode destination resource in parts, as a backward compat hack
    itemParts.push_back( QString::fromLatin1( msg.destinationResource() ) );
  } else {
    Q_FOREACH ( const QByteArray &itemPart, msg.itemParts() )
      itemParts.append( QString::fromLatin1( itemPart ) );
  }

  arg << itemParts;
  arg.endStructure();
  return arg;
}

const QDBusArgument& operator>>( const QDBusArgument &arg, NotificationMessage &msg )
{
  arg.beginStructure();
  QByteArray b;
  arg >> b;
  msg.setSessionId( b );
  int i;
  arg >> i;
  msg.setType( static_cast<NotificationMessage::Type>( i ) );
  arg >> i;
  msg.setOperation( static_cast<NotificationMessage::Operation>( i ) );
  NotificationMessage::Id id;
  arg >> id;
  msg.setUid( id );
  QString s;
  arg >> s;
  msg.setRemoteId( s );
  arg >> b;
  msg.setResource( b );
  arg >> id;
  msg.setParentCollection( id );
  arg >> id;
  msg.setParentDestCollection( id );
  arg >> s;
  msg.setMimeType( s );
  QStringList l;
  arg >> l;

  QSet<QByteArray> itemParts;
  if ( msg.operation() == NotificationMessage::Move && l.size() >= 1 ) {
    // decode destination resource, which is stored in parts as a backward compat hack
    msg.setDestinationResource( l.first().toLatin1() );
  } else {
    Q_FOREACH ( const QString &itemPart, l )
      itemParts.insert( itemPart.toLatin1() );
  }

  msg.setItemParts( itemParts );
  arg.endStructure();
  return arg;
}

uint qHash( const Akonadi::NotificationMessage &msg )
{
  return qHash( msg.uid() + (msg.type() << 31) + (msg.operation() << 28) );
}
<|endoftext|>


<commit_before>#include "crashhandler.hpp"

#if (defined(WIN32) || defined(_WIN32) || defined(__WIN32__) && !defined(__GNUC__))
#error "crashhandler_unix.cpp is used on a non-UNIX platform"
#endif

#include <csignal>
#include <cstring>
#include <unistd.h>
#include <execinfo.h>
#include <cxxabi.h>
#include <cstdlib>
#include <sstream>
#include <iostream>
#include <thread>
#include <atomic>
#include <map>
#include <mutex>
#include <fmt/format.h>

 // Linux/Clang, OSX/Clang, OSX/gcc
#if (defined(__clang__) || defined(__APPLE__))
#include <sys/ucontext.h>
#else
#include <ucontext.h>
#endif

#include "CLogger.hpp"

namespace
{
	const std::map<crashhandler::Signal, std::string> Signals = {
	   {SIGABRT, "SIGABRT"},
	   {SIGFPE, "SIGFPE"},
	   {SIGILL, "SIGILL"},
	   {SIGSEGV, "SIGSEGV"},
	   {SIGTERM, "SIGTERM"},
	};

	std::map<crashhandler::Signal, struct sigaction> OldSignalActions;

	bool IsFirstSignal()
	{
		static std::atomic<int> first_exit{ 0 };
		int const count = first_exit.fetch_add(1, std::memory_order_relaxed);
		return (count == 0);
	}

	void RestoreSignalHandler(int signal_number)
	{
		//try restoring old action
		auto it = OldSignalActions.find(signal_number);
		if (it != OldSignalActions.end())
		{
			sigaction(signal_number, &(it->second), nullptr);
		}
		else //fallback to default action
		{
			struct sigaction action;
			memset(&action, 0, sizeof(action));
			sigemptyset(&action.sa_mask);
			action.sa_handler = SIG_DFL;
			sigaction(signal_number, &action, nullptr);
		}
	}

	void ExitWithDefaultSignalHandler(crashhandler::Signal fatal_signal_id, pid_t process_id)
	{
		const int signal_number = static_cast<int>(fatal_signal_id);
		RestoreSignalHandler(signal_number);
		std::cerr << "\n\n" << __FUNCTION__ << ":" << __LINE__ << ". Signal ID: " << signal_number << "   \n\n" << std::flush;

		kill(process_id, signal_number);
		exit(signal_number);
	}

	void SignalHandler(int signal_number, siginfo_t* info, void* unused_context)
	{
		//only one signal will be allowed past this point
		if (!IsFirstSignal())
		{
			while (true)
				std::this_thread::sleep_for(std::chrono::seconds(1));
		}

		const std::string err_msg = fmt::format(
			"signal {:d} ({:s}) catched; shutting log-core down (errno: {}, signal code: {}, exit status: {})",
			signal_number, Signals.at(signal_number), info->si_errno, info->si_code, info->si_status);

		CLogManager::Get()->QueueLogMessage(std::unique_ptr<CMessage>(new CMessage(
			"log-core", LogLevel::ERROR,
			err_msg, 0, "", "")));
		CLogManager::Get()->Destroy();

		ExitWithDefaultSignalHandler(signal_number, info->si_pid);
	}
}

namespace crashhandler
{
	void Install()
	{
		struct sigaction action, old_action;
		memset(&action, 0, sizeof(action));
		memset(&old_action, 0, sizeof(old_action));
		sigemptyset(&action.sa_mask);
		action.sa_sigaction = &SignalHandler;
		action.sa_flags = SA_SIGINFO;

		for (const auto &signal : Signals)
		{
			if (sigaction(signal.first, &action, &old_action) < 0)
			{
				const std::string error = "sigaction - " + signal.second;
				perror(error.c_str());
			}
			else
			{
				if (old_action.sa_handler != nullptr || old_action.sa_sigaction != nullptr)
					OldSignalActions.emplace(signal.first, old_action);
			}
		}
	}
}

<commit_msg>improve UNIX crash handler<commit_after>#include "crashhandler.hpp"

#if (defined(WIN32) || defined(_WIN32) || defined(__WIN32__) && !defined(__GNUC__))
#error "crashhandler_unix.cpp is used on a non-UNIX platform"
#endif

#include <csignal>
#include <cstring>
#include <unistd.h>
#include <execinfo.h>
#include <cxxabi.h>
#include <cstdlib>
#include <sstream>
#include <iostream>
#include <thread>
#include <atomic>
#include <map>
#include <mutex>
#include <fmt/format.h>

 // Linux/Clang, OSX/Clang, OSX/gcc
#if (defined(__clang__) || defined(__APPLE__))
#include <sys/ucontext.h>
#else
#include <ucontext.h>
#endif

#include "CLogger.hpp"

namespace
{
	const std::map<crashhandler::Signal, std::string> Signals = {
	   {SIGABRT, "SIGABRT"},
	   {SIGFPE, "SIGFPE"},
	   {SIGILL, "SIGILL"},
	   {SIGSEGV, "SIGSEGV"},
	   {SIGTERM, "SIGTERM"},
	};

	std::map<crashhandler::Signal, struct sigaction> OldSignalActions;

	bool IsFirstSignal()
	{
		static std::atomic<int> first_exit{ 0 };
		int const count = first_exit.fetch_add(1, std::memory_order_relaxed);
		return (count == 0);
	}

	void RestoreSignalHandler(int signal_number)
	{
		//try restoring old action
		auto it = OldSignalActions.find(signal_number);
		if (it != OldSignalActions.end())
			sigaction(signal_number, &(it->second), nullptr);
	}

	void ExitWithDefaultSignalHandler(crashhandler::Signal fatal_signal_id)
	{
		const int signal_number = static_cast<int>(fatal_signal_id);
		RestoreSignalHandler(signal_number);
		std::cerr << "\n\n" << "[log-core] fatal signal '" << signal_number
			<< "' (" << Signals.at(fatal_signal_id) << ") catched   \n\n" << std::flush;

		raise(signal_number);
	}

	void SignalHandler(int signal_number, siginfo_t* info, void* unused_context)
	{
		//only one signal will be allowed past this point
		if (!IsFirstSignal())
		{
			while (true)
				std::this_thread::sleep_for(std::chrono::seconds(1));
		}

		const std::string err_msg = fmt::format(
			"signal {:d} ({:s}) catched; shutting log-core down (errno: {}, signal code: {}, exit status: {})",
			signal_number, Signals.at(signal_number), info->si_errno, info->si_code, info->si_status);

		CLogManager::Get()->QueueLogMessage(std::unique_ptr<CMessage>(new CMessage(
			"log-core", LogLevel::ERROR, err_msg, 0, "", "")));
		CLogManager::Get()->Destroy();

		ExitWithDefaultSignalHandler(signal_number);
	}
}

namespace crashhandler
{
	void Install()
	{
		struct sigaction action, old_action;
		memset(&action, 0, sizeof(action));
		memset(&old_action, 0, sizeof(old_action));
		sigemptyset(&action.sa_mask);
		action.sa_sigaction = &SignalHandler;
		action.sa_flags = SA_SIGINFO;

		for (const auto &signal : Signals)
		{
			if (sigaction(signal.first, &action, &old_action) < 0)
			{
				const std::string error = "sigaction - " + signal.second;
				perror(error.c_str());
			}
			else
			{
				OldSignalActions.emplace(signal.first, old_action);
			}
		}
	}
}

<|endoftext|>


<commit_before>#include "ofSoundStream.h"
#include "RtAudio.h"

//----------------------------------- static variables:
static ofBaseApp 	* 		OFSAptr = NULL;
RtAudio				*		audio = NULL;
int 						nInputChannels;
int 						nOutputChannels;
ofAudioEventArgs 			audioEventArgs;

int receiveAudioBufferAndCallSimpleApp(void *outputBuffer, void *inputBuffer, unsigned int bufferSize,
           double streamTime, RtAudioStreamStatus status, void *data);

//------------------------------------------------------------------------------
int receiveAudioBufferAndCallSimpleApp(void *outputBuffer, void *inputBuffer, unsigned int bufferSize,
           double streamTime, RtAudioStreamStatus status, void *data){

	if ( status ) std::cout << "Stream over/underflow detected." << std::endl;

	// 	rtAudio uses a system by which the audio
	// 	can be of different formats
	// 	char, float, etc.
	// 	we choose float
	float * fPtrOut = (float *)outputBuffer;
	float * fPtrIn = (float *)inputBuffer;
	// [zach] memset output to zero before output call
	// this is because of how rtAudio works: duplex w/ one callback
	// you need to cut in the middle. if the simpleApp
	// doesn't produce audio, we pass silence instead of duplex...

	if (nInputChannels > 0){
		OFSAptr->audioReceived(fPtrIn, bufferSize, nInputChannels);
		#ifdef OF_USING_POCO
			audioEventArgs.buffer = fPtrIn;
			audioEventArgs.bufferSize = bufferSize;
			audioEventArgs.nChannels = nInputChannels;
			ofNotifyEvent( ofEvents.audioReceived, audioEventArgs );
		#endif
		memset(fPtrIn, 0, bufferSize * nInputChannels * sizeof(float));
	}

	if (nOutputChannels > 0) {
		OFSAptr->audioRequested(fPtrOut, bufferSize, nOutputChannels);
		#ifdef OF_USING_POCO
			audioEventArgs.buffer = fPtrOut;
			audioEventArgs.bufferSize = bufferSize;
			audioEventArgs.nChannels = nOutputChannels;
			ofNotifyEvent( ofEvents.audioRequested, audioEventArgs );
		#endif
	}

	return 0;
}
//---------------------------------------------------------
void ofSoundStreamSetup(int nOutputs, int nInputs, ofBaseApp * OFSA){
	ofSoundStreamSetup(nOutputs, nInputs, OFSA, 44100, 256, 4);
}

//---------------------------------------------------------
void ofSoundStreamSetup(int nOutputs, int nInputs, int sampleRate, int bufferSize, int nBuffers){
	ofSoundStreamSetup(nOutputs, nInputs, NULL, sampleRate, bufferSize, nBuffers);
}

//---------------------------------------------------------
void ofSoundStreamSetup(int nOutputs, int nInputs, ofBaseApp * OFSA, int sampleRate, int bufferSize, int nBuffers){

	nInputChannels 		=  nInputs;
	nOutputChannels 	=  nOutputs;
	OFSAptr 			=  OFSA;
	bufferSize = ofNextPow2(bufferSize);	// must be pow2

	try {
		audio = new RtAudio();
	}	catch (RtError &error) {
		error.printMessage();
		//std::exit(EXIT_FAILURE); // need case here
	}

	RtAudio::StreamParameters * outputParameters=NULL;
	if(nOutputChannels >0){
		outputParameters = new RtAudio::StreamParameters();
		outputParameters->deviceId = audio->getDefaultOutputDevice();
		outputParameters->nChannels = nOutputChannels;
	}

	RtAudio::StreamParameters * inputParameters = NULL;
	if(nInputChannels>0){
		inputParameters = new RtAudio::StreamParameters;
		inputParameters->deviceId = audio->getDefaultInputDevice();
		inputParameters->nChannels = nInputChannels;
	}

	unsigned int bufferFrames = (unsigned int)bufferSize; // 256 sample frames

	RtAudio::StreamOptions options;
	options.flags = RTAUDIO_SCHEDULE_REALTIME;
	options.numberOfBuffers = nBuffers;
	options.priority = 1;

	try {

		audio ->openStream( outputParameters, inputParameters, RTAUDIO_FLOAT32,
							sampleRate, &bufferFrames, &receiveAudioBufferAndCallSimpleApp, &options);
		audio->startStream();
	} catch (RtError &error) {
		error.printMessage();
	}

}

//---------------------------------------------------------
void ofSoundStreamStop(){
	try {
    	audio->stopStream();
  	} catch (RtError &error) {
   		error.printMessage();
 	}
}

//---------------------------------------------------------
void ofSoundStreamStart(){
	try{
		audio->startStream();
	} catch (RtError &error) {
		error.printMessage();
	}
}

//---------------------------------------------------------
void ofSoundStreamClose(){
	if(!audio) return;
	try {
    	audio->stopStream();
    	audio->closeStream();
  	} catch (RtError &error) {
   		error.printMessage();
 	}
	delete audio;
}

//---------------------------------------------------------
void ofSoundStreamListDevices(){
	RtAudio *audioTemp = 0;
	try {
		audioTemp = new RtAudio();
	} catch (RtError &error) {
		error.printMessage();
	}
 	int devices = audioTemp->getDeviceCount();
	RtAudio::DeviceInfo info;
	for (int i=0; i< devices; i++) {
		try {
			info = audioTemp->getDeviceInfo(i);
		} catch (RtError &error) {
			error.printMessage();
			break;
		}
		std::cout << "device = " << i << " (" << info.name << ")\n";
		if (info.isDefaultInput) std::cout << "----* default ----* \n";
		std::cout << "maximum output channels = " << info.outputChannels << "\n";
		std::cout << "maximum input channels = " << info.inputChannels << "\n";
		std::cout << "-----------------------------------------\n";

	}
	delete audioTemp;
}
<commit_msg>ofSoundStream: check if app is set in callback. Closes #183<commit_after>#include "ofSoundStream.h"
#include "RtAudio.h"

//----------------------------------- static variables:
static ofBaseApp 	* 		OFSAptr = NULL;
RtAudio				*		audio = NULL;
int 						nInputChannels;
int 						nOutputChannels;
ofAudioEventArgs 			audioEventArgs;

int receiveAudioBufferAndCallSimpleApp(void *outputBuffer, void *inputBuffer, unsigned int bufferSize,
           double streamTime, RtAudioStreamStatus status, void *data);

//------------------------------------------------------------------------------
int receiveAudioBufferAndCallSimpleApp(void *outputBuffer, void *inputBuffer, unsigned int bufferSize,
           double streamTime, RtAudioStreamStatus status, void *data){

	if ( status ) std::cout << "Stream over/underflow detected." << std::endl;

	// 	rtAudio uses a system by which the audio
	// 	can be of different formats
	// 	char, float, etc.
	// 	we choose float
	float * fPtrOut = (float *)outputBuffer;
	float * fPtrIn = (float *)inputBuffer;
	// [zach] memset output to zero before output call
	// this is because of how rtAudio works: duplex w/ one callback
	// you need to cut in the middle. if the simpleApp
	// doesn't produce audio, we pass silence instead of duplex...

	if (nInputChannels > 0){
		if(OFSAptr) OFSAptr->audioReceived(fPtrIn, bufferSize, nInputChannels);
		#ifdef OF_USING_POCO
			audioEventArgs.buffer = fPtrIn;
			audioEventArgs.bufferSize = bufferSize;
			audioEventArgs.nChannels = nInputChannels;
			ofNotifyEvent( ofEvents.audioReceived, audioEventArgs );
		#endif
		memset(fPtrIn, 0, bufferSize * nInputChannels * sizeof(float));
	}

	if (nOutputChannels > 0) {
		if(OFSAptr) OFSAptr->audioRequested(fPtrOut, bufferSize, nOutputChannels);
		#ifdef OF_USING_POCO
			audioEventArgs.buffer = fPtrOut;
			audioEventArgs.bufferSize = bufferSize;
			audioEventArgs.nChannels = nOutputChannels;
			ofNotifyEvent( ofEvents.audioRequested, audioEventArgs );
		#endif
	}

	return 0;
}
//---------------------------------------------------------
void ofSoundStreamSetup(int nOutputs, int nInputs, ofBaseApp * OFSA){
	ofSoundStreamSetup(nOutputs, nInputs, OFSA, 44100, 256, 4);
}

//---------------------------------------------------------
void ofSoundStreamSetup(int nOutputs, int nInputs, int sampleRate, int bufferSize, int nBuffers){
	ofSoundStreamSetup(nOutputs, nInputs, NULL, sampleRate, bufferSize, nBuffers);
}

//---------------------------------------------------------
void ofSoundStreamSetup(int nOutputs, int nInputs, ofBaseApp * OFSA, int sampleRate, int bufferSize, int nBuffers){

	nInputChannels 		=  nInputs;
	nOutputChannels 	=  nOutputs;
	OFSAptr 			=  OFSA;
	bufferSize = ofNextPow2(bufferSize);	// must be pow2

	try {
		audio = new RtAudio();
	}	catch (RtError &error) {
		error.printMessage();
		//std::exit(EXIT_FAILURE); // need case here
	}

	RtAudio::StreamParameters * outputParameters=NULL;
	if(nOutputChannels >0){
		outputParameters = new RtAudio::StreamParameters();
		outputParameters->deviceId = audio->getDefaultOutputDevice();
		outputParameters->nChannels = nOutputChannels;
	}

	RtAudio::StreamParameters * inputParameters = NULL;
	if(nInputChannels>0){
		inputParameters = new RtAudio::StreamParameters;
		inputParameters->deviceId = audio->getDefaultInputDevice();
		inputParameters->nChannels = nInputChannels;
	}

	unsigned int bufferFrames = (unsigned int)bufferSize; // 256 sample frames

	RtAudio::StreamOptions options;
	options.flags = RTAUDIO_SCHEDULE_REALTIME;
	options.numberOfBuffers = nBuffers;
	options.priority = 1;

	try {

		audio ->openStream( outputParameters, inputParameters, RTAUDIO_FLOAT32,
							sampleRate, &bufferFrames, &receiveAudioBufferAndCallSimpleApp, &options);
		audio->startStream();
	} catch (RtError &error) {
		error.printMessage();
	}

}

//---------------------------------------------------------
void ofSoundStreamStop(){
	try {
    	audio->stopStream();
  	} catch (RtError &error) {
   		error.printMessage();
 	}
}

//---------------------------------------------------------
void ofSoundStreamStart(){
	try{
		audio->startStream();
	} catch (RtError &error) {
		error.printMessage();
	}
}

//---------------------------------------------------------
void ofSoundStreamClose(){
	if(!audio) return;
	try {
    	audio->stopStream();
    	audio->closeStream();
  	} catch (RtError &error) {
   		error.printMessage();
 	}
	delete audio;
}

//---------------------------------------------------------
void ofSoundStreamListDevices(){
	RtAudio *audioTemp = 0;
	try {
		audioTemp = new RtAudio();
	} catch (RtError &error) {
		error.printMessage();
	}
 	int devices = audioTemp->getDeviceCount();
	RtAudio::DeviceInfo info;
	for (int i=0; i< devices; i++) {
		try {
			info = audioTemp->getDeviceInfo(i);
		} catch (RtError &error) {
			error.printMessage();
			break;
		}
		std::cout << "device = " << i << " (" << info.name << ")\n";
		if (info.isDefaultInput) std::cout << "----* default ----* \n";
		std::cout << "maximum output channels = " << info.outputChannels << "\n";
		std::cout << "maximum input channels = " << info.inputChannels << "\n";
		std::cout << "-----------------------------------------\n";

	}
	delete audioTemp;
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2014 Pavel Kirienko <pavel.kirienko@gmail.com>
 */

#pragma once

#include <queue>
#include <vector>
#include <gtest/gtest.h>
#include <uavcan/internal/transport/can_io.hpp>
#include "../../common.hpp"

class CanIfaceMock : public uavcan::ICanIface
{
public:
    struct FrameWithTime
    {
        uavcan::CanFrame frame;
        uint64_t time;

        FrameWithTime(const uavcan::CanFrame& frame, uint64_t time)
        : frame(frame)
        , time(time)
        { }
    };

    std::queue<FrameWithTime> tx;       ///< Queue of outgoing frames (bus <-- library)
    std::queue<FrameWithTime> rx;       ///< Queue of incoming frames (bus --> library)
    bool writeable;
    bool tx_failure;
    bool rx_failure;
    uint64_t num_errors;
    SystemClockMock& clockmock;

    CanIfaceMock(SystemClockMock& clockmock)
    : writeable(true)
    , tx_failure(false)
    , rx_failure(false)
    , num_errors(0)
    , clockmock(clockmock)
    { }

    void pushRx(uavcan::CanFrame frame)
    {
        rx.push(FrameWithTime(frame, clockmock.utc));
    }

    bool matchAndPopTx(const uavcan::CanFrame& frame, uint64_t tx_deadline)
    {
        if (tx.empty())
        {
            std::cout << "Tx buffer is empty" << std::endl;
            return false;
        }
        const FrameWithTime frame_time = tx.front();
        tx.pop();
        return (frame_time.frame == frame) && (frame_time.time == tx_deadline);
    }

    int send(const uavcan::CanFrame& frame, uint64_t tx_timeout_usec)
    {
        assert(this);
        EXPECT_TRUE(writeable);        // Shall never be called when not writeable
        if (tx_failure)
            return -1;
        if (!writeable)
            return 0;
        const uint64_t monotonic_deadline = tx_timeout_usec + clockmock.monotonic;
        tx.push(FrameWithTime(frame, monotonic_deadline));
        return 1;
    }

    int receive(uavcan::CanFrame& out_frame, uint64_t& out_ts_monotonic_usec, uint64_t& out_ts_utc_usec)
    {
        assert(this);
        EXPECT_TRUE(rx.size());        // Shall never be called when not readable
        if (rx_failure)
            return -1;
        if (rx.empty())
            return 0;
        const FrameWithTime frame = rx.front();
        rx.pop();
        out_frame = frame.frame;
        out_ts_monotonic_usec = frame.time;
        out_ts_utc_usec = 0;
        return 1;
    }

    // cppcheck-suppress unusedFunction
    // cppcheck-suppress functionConst
    int configureFilters(const uavcan::CanFilterConfig* filter_configs, int num_configs) { return -1; }
    // cppcheck-suppress unusedFunction
    int getNumFilters() const { return 0; }
    uint64_t getNumErrors() const { return num_errors; }
};

class CanDriverMock : public uavcan::ICanDriver
{
public:
    std::vector<CanIfaceMock> ifaces;
    SystemClockMock& clockmock;
    bool select_failure;

    CanDriverMock(int num_ifaces, SystemClockMock& clockmock)
    : ifaces(num_ifaces, CanIfaceMock(clockmock))
    , clockmock(clockmock)
    , select_failure(false)
    { }

    int select(int& inout_write_iface_mask, int& inout_read_iface_mask, uint64_t timeout_usec)
    {
        assert(this);
        std::cout << "Write/read masks: " << inout_write_iface_mask << "/" << inout_read_iface_mask << std::endl;

        if (select_failure)
            return -1;

        const int valid_iface_mask = (1 << getNumIfaces()) - 1;
        EXPECT_FALSE(inout_write_iface_mask & ~valid_iface_mask);
        EXPECT_FALSE(inout_read_iface_mask & ~valid_iface_mask);

        int out_write_mask = 0;
        int out_read_mask = 0;
        for (int i = 0; i < getNumIfaces(); i++)
        {
            const int mask = 1 << i;
            if ((inout_write_iface_mask & mask) && ifaces.at(i).writeable)
                out_write_mask |= mask;
            if ((inout_read_iface_mask & mask) && ifaces.at(i).rx.size())
                out_read_mask |= mask;
        }
        inout_write_iface_mask = out_write_mask;
        inout_read_iface_mask = out_read_mask;
        if ((out_write_mask | out_read_mask) == 0)
        {
            clockmock.advance(timeout_usec);   // Emulating timeout
            return 0;
        }
        return 1;  // This value is not being checked anyway, it just has to be greater than zero
    }

    uavcan::ICanIface* getIface(int iface_index) { return &ifaces.at(iface_index); }
    int getNumIfaces() const { return ifaces.size(); }
};
<commit_msg>CAN iface mock uses monotonic timestamping instead of UTC<commit_after>/*
 * Copyright (C) 2014 Pavel Kirienko <pavel.kirienko@gmail.com>
 */

#pragma once

#include <queue>
#include <vector>
#include <gtest/gtest.h>
#include <uavcan/internal/transport/can_io.hpp>
#include "../../common.hpp"

class CanIfaceMock : public uavcan::ICanIface
{
public:
    struct FrameWithTime
    {
        uavcan::CanFrame frame;
        uint64_t time;

        FrameWithTime(const uavcan::CanFrame& frame, uint64_t time)
        : frame(frame)
        , time(time)
        { }
    };

    std::queue<FrameWithTime> tx;       ///< Queue of outgoing frames (bus <-- library)
    std::queue<FrameWithTime> rx;       ///< Queue of incoming frames (bus --> library)
    bool writeable;
    bool tx_failure;
    bool rx_failure;
    uint64_t num_errors;
    SystemClockMock& clockmock;

    CanIfaceMock(SystemClockMock& clockmock)
    : writeable(true)
    , tx_failure(false)
    , rx_failure(false)
    , num_errors(0)
    , clockmock(clockmock)
    { }

    void pushRx(uavcan::CanFrame frame)
    {
        rx.push(FrameWithTime(frame, clockmock.monotonic));
    }

    bool matchAndPopTx(const uavcan::CanFrame& frame, uint64_t tx_deadline)
    {
        if (tx.empty())
        {
            std::cout << "Tx buffer is empty" << std::endl;
            return false;
        }
        const FrameWithTime frame_time = tx.front();
        tx.pop();
        return (frame_time.frame == frame) && (frame_time.time == tx_deadline);
    }

    int send(const uavcan::CanFrame& frame, uint64_t tx_timeout_usec)
    {
        assert(this);
        EXPECT_TRUE(writeable);        // Shall never be called when not writeable
        if (tx_failure)
            return -1;
        if (!writeable)
            return 0;
        const uint64_t monotonic_deadline = tx_timeout_usec + clockmock.monotonic;
        tx.push(FrameWithTime(frame, monotonic_deadline));
        return 1;
    }

    int receive(uavcan::CanFrame& out_frame, uint64_t& out_ts_monotonic_usec, uint64_t& out_ts_utc_usec)
    {
        assert(this);
        EXPECT_TRUE(rx.size());        // Shall never be called when not readable
        if (rx_failure)
            return -1;
        if (rx.empty())
            return 0;
        const FrameWithTime frame = rx.front();
        rx.pop();
        out_frame = frame.frame;
        out_ts_monotonic_usec = frame.time;
        out_ts_utc_usec = 0;
        return 1;
    }

    // cppcheck-suppress unusedFunction
    // cppcheck-suppress functionConst
    int configureFilters(const uavcan::CanFilterConfig* filter_configs, int num_configs) { return -1; }
    // cppcheck-suppress unusedFunction
    int getNumFilters() const { return 0; }
    uint64_t getNumErrors() const { return num_errors; }
};

class CanDriverMock : public uavcan::ICanDriver
{
public:
    std::vector<CanIfaceMock> ifaces;
    SystemClockMock& clockmock;
    bool select_failure;

    CanDriverMock(int num_ifaces, SystemClockMock& clockmock)
    : ifaces(num_ifaces, CanIfaceMock(clockmock))
    , clockmock(clockmock)
    , select_failure(false)
    { }

    int select(int& inout_write_iface_mask, int& inout_read_iface_mask, uint64_t timeout_usec)
    {
        assert(this);
        std::cout << "Write/read masks: " << inout_write_iface_mask << "/" << inout_read_iface_mask << std::endl;

        if (select_failure)
            return -1;

        const int valid_iface_mask = (1 << getNumIfaces()) - 1;
        EXPECT_FALSE(inout_write_iface_mask & ~valid_iface_mask);
        EXPECT_FALSE(inout_read_iface_mask & ~valid_iface_mask);

        int out_write_mask = 0;
        int out_read_mask = 0;
        for (int i = 0; i < getNumIfaces(); i++)
        {
            const int mask = 1 << i;
            if ((inout_write_iface_mask & mask) && ifaces.at(i).writeable)
                out_write_mask |= mask;
            if ((inout_read_iface_mask & mask) && ifaces.at(i).rx.size())
                out_read_mask |= mask;
        }
        inout_write_iface_mask = out_write_mask;
        inout_read_iface_mask = out_read_mask;
        if ((out_write_mask | out_read_mask) == 0)
        {
            clockmock.advance(timeout_usec);   // Emulating timeout
            return 0;
        }
        return 1;  // This value is not being checked anyway, it just has to be greater than zero
    }

    uavcan::ICanIface* getIface(int iface_index) { return &ifaces.at(iface_index); }
    int getNumIfaces() const { return ifaces.size(); }
};
<|endoftext|>


<commit_before>#include "SimulationEvent.hpp"

auto operator<<(std::ostream& os, const SimulationEventType& ty) -> std::ostream& {
    switch (ty) {
        case SimulationEventType::Attack:
            os << "Attack";
            break;
        case SimulationEventType::Collision:
            os << "Collision";
            break;
        case SimulationEventType::Desertion:
            os << "Desertion";
            break;
    }
    return os;
}

auto test_aabb_circle(
    int rect_x, int rect_y, int rect_w, int rect_h,
    const hlt::Location& circ_center, double radius) -> bool {
    // https://stackoverflow.com/a/21096179

    // Find axis-aligned distances between circle and rectangle center
    const auto x_half_rect = rect_w / 2.0;
    const auto y_half_rect = rect_h / 2.0;
    const auto x_dist = std::abs(circ_center.pos_x - rect_x - x_half_rect);
    const auto y_dist = std::abs(circ_center.pos_y - rect_y - y_half_rect);

    if (x_dist > x_half_rect + radius) return false;
    if (y_dist > y_half_rect + radius) return false;

    if (x_dist <= x_half_rect) return true;
    if (y_dist <= y_half_rect) return true;

    // Distance from rectangle side to circle center
    const auto dx = x_dist - x_half_rect;
    const auto dy = y_dist - y_half_rect;

    return std::pow(dx, 2) + std::pow(dy, 2) <= std::pow(radius, 2);
}

CollisionMap::CollisionMap(const hlt::Map& game_map,
                           const std::function<double(const hlt::Ship&)> radius_func) {
    width = static_cast<int>(std::ceil(static_cast<double>(game_map.map_width) / CELL_SIZE));
    height = static_cast<int>(std::ceil(static_cast<double>(game_map.map_height) / CELL_SIZE));

    std::vector<std::vector<hlt::EntityId>> row(height, std::vector<hlt::EntityId>());
    cells.resize(width, row);

    rebuild(game_map, radius_func);
}

auto CollisionMap::rebuild(const hlt::Map& game_map,
                           const std::function<double(const hlt::Ship&)> radius_func) -> void {
    hlt::PlayerId player = 0;
    for (const auto& player_ships : game_map.ships) {
        for (const auto& ship_pair : player_ships) {
            const auto& location = ship_pair.second.location;
            const auto id = hlt::EntityId::for_ship(player, ship_pair.first);

            add(location, radius_func(ship_pair.second), id);
        }

        player++;
    }
}

auto CollisionMap::add(const hlt::Location& location, double radius,
                       hlt::EntityId id) -> void {
    // Add the entity ID to all grid cells that the entity overlaps
    for (auto cell_x = 0; cell_x < width; cell_x++) {
        for (auto cell_y = 0; cell_y < height; cell_y++) {
            if (test_aabb_circle(cell_x * CELL_SIZE, cell_y * CELL_SIZE,
                                 CELL_SIZE, CELL_SIZE,
                                 location, radius)) {
                cells.at(cell_x).at(cell_y).push_back(id);
            }
        }
    }
}

auto CollisionMap::test(const hlt::Location& location, double radius,
                        std::vector<hlt::EntityId>& potential_collisions) -> void {
    // Add all IDs of any cell that overlaps the circle
    for (auto cell_x = 0; cell_x < width; cell_x++) {
        for (auto cell_y = 0; cell_y < height; cell_y++) {
            if (test_aabb_circle(cell_x * CELL_SIZE, cell_y * CELL_SIZE,
                                 CELL_SIZE, CELL_SIZE,
                                 location, radius)) {
                const auto& cell = cells.at(cell_x).at(cell_y);
                potential_collisions.insert(
                    potential_collisions.end(),
                    cell.begin(), cell.end()
                );
            }
        }
    }
}

auto collision_time(
    double r,
    const hlt::Location& loc1, const hlt::Location& loc2,
    const hlt::Velocity& vel1, const hlt::Velocity& vel2
) -> std::pair<bool, double> {
    // With credit to Ben Spector
    // Simplified derivation:
    // 1. Set up the distance between the two entities in terms of time,
    //    the difference between their velocities and the difference between
    //    their positions
    // 2. Equate the distance equal to the event radius (max possible distance
    //    they could be)
    // 3. Solve the resulting quadratic

    const auto dx = loc1.pos_x - loc2.pos_x;
    const auto dy = loc1.pos_y - loc2.pos_y;
    const auto dvx = vel1.vel_x - vel2.vel_x;
    const auto dvy = vel1.vel_y - vel2.vel_y;

    // Quadratic formula
    const auto a = std::pow(dvx, 2) + std::pow(dvy, 2);
    const auto b = 2 * (dx * dvx + dy * dvy);
    const auto c = std::pow(dx, 2) + std::pow(dy, 2) - std::pow(r, 2);

    const auto disc = std::pow(b, 2) - 4 * a * c;

    if (a == 0.0) {
        if (b == 0.0) {
            if (c <= 0.0) {
                // Implies r^2 >= dx^2 + dy^2 and the two are already colliding
                return { true, 0.0 };
            }
            return { false, 0.0 };
        }
        const auto t = -c / b;
        if (t >= 0.0) {
            return { true, t };
        }
        return { false, 0.0 };
    }
    else if (disc == 0.0) {
        // One solution
        const auto t = -b / (2 * a);
        return { true, t };
    }
    else if (disc > 0) {
        const auto t1 = -b + std::sqrt(disc);
        const auto t2 = -b - std::sqrt(disc);

        if (t1 >= 0.0 && t2 >= 0.0) {
            return { true, std::min(t1, t2) / (2 * a) };
        }
        else {
            return { true, std::max(t1, t2) / (2 * a) };
        }
    }
    else {
        return { false, 0.0 };
    }
}

auto collision_time(double r, const hlt::Ship& ship1, const hlt::Ship& ship2) -> std::pair<bool, double> {
    return collision_time(r,
                          ship1.location, ship2.location,
                          ship1.velocity, ship2.velocity);
}

auto collision_time(double r, const hlt::Ship& ship1, const hlt::Planet& planet) -> std::pair<bool, double> {
    return collision_time(r,
                          ship1.location, planet.location,
                          ship1.velocity, { 0, 0 });
}

auto might_attack(double distance, const hlt::Ship& ship1, const hlt::Ship& ship2) -> bool {
    return distance <= ship1.velocity.magnitude() + ship2.velocity.magnitude()
        + hlt::GameConstants::get().WEAPON_RADIUS;
}

auto might_collide(double distance, const hlt::Ship& ship1, const hlt::Ship& ship2) -> bool {
    return distance <= ship1.velocity.magnitude() + ship2.velocity.magnitude() +
        ship1.radius + ship2.radius;
}

auto round_event_time(double t) -> double {
    return std::round(t * EVENT_TIME_PRECISION) / EVENT_TIME_PRECISION;
}

auto find_events(
    std::unordered_set<SimulationEvent>& unsorted_events,
    const hlt::EntityId id1, const hlt::EntityId& id2,
    const hlt::Ship& ship1, const hlt::Ship& ship2) -> void {
    const auto distance = ship1.location.distance(ship2.location);
    const auto player1 = id1.player_id();
    const auto player2 = id2.player_id();

    if (player1 != player2 && might_attack(distance, ship1, ship2)) {
        // Combat event
        const auto attack_radius = ship1.radius +
            ship2.radius + hlt::GameConstants::get().WEAPON_RADIUS;
        const auto t = collision_time(attack_radius, ship1, ship2);
        if (t.first && t.second >= 0 && t.second <= 1) {
            unsorted_events.insert(SimulationEvent{
                SimulationEventType::Attack,
                id1, id2, round_event_time(t.second),
            });
        }
        else if (distance < attack_radius) {
            unsorted_events.insert(SimulationEvent{
                SimulationEventType::Attack,
                id1, id2, 0
            });
        }
    }

    if (id1 != id2 && might_collide(distance, ship1, ship2)) {
        // Collision event
        const auto collision_radius = ship1.radius + ship2.radius;
        const auto t = collision_time(collision_radius, ship1, ship2);
        if (t.first) {
            if (t.second >= 0 && t.second <= 1) {
                unsorted_events.insert(SimulationEvent{
                    SimulationEventType::Collision,
                    id1, id2, round_event_time(t.second),
                });
            }
        }
        else if (distance < collision_radius) {
            // This should never happen - the ships should already be dead
            assert(false);
        }
    }
}
<commit_msg>Fixes the collision time calculation<commit_after>#include "SimulationEvent.hpp"

auto operator<<(std::ostream& os, const SimulationEventType& ty) -> std::ostream& {
    switch (ty) {
        case SimulationEventType::Attack:
            os << "Attack";
            break;
        case SimulationEventType::Collision:
            os << "Collision";
            break;
        case SimulationEventType::Desertion:
            os << "Desertion";
            break;
    }
    return os;
}

auto test_aabb_circle(
    int rect_x, int rect_y, int rect_w, int rect_h,
    const hlt::Location& circ_center, double radius) -> bool {
    // https://stackoverflow.com/a/21096179

    // Find axis-aligned distances between circle and rectangle center
    const auto x_half_rect = rect_w / 2.0;
    const auto y_half_rect = rect_h / 2.0;
    const auto x_dist = std::abs(circ_center.pos_x - rect_x - x_half_rect);
    const auto y_dist = std::abs(circ_center.pos_y - rect_y - y_half_rect);

    if (x_dist > x_half_rect + radius) return false;
    if (y_dist > y_half_rect + radius) return false;

    if (x_dist <= x_half_rect) return true;
    if (y_dist <= y_half_rect) return true;

    // Distance from rectangle side to circle center
    const auto dx = x_dist - x_half_rect;
    const auto dy = y_dist - y_half_rect;

    return std::pow(dx, 2) + std::pow(dy, 2) <= std::pow(radius, 2);
}

CollisionMap::CollisionMap(const hlt::Map& game_map,
                           const std::function<double(const hlt::Ship&)> radius_func) {
    width = static_cast<int>(std::ceil(static_cast<double>(game_map.map_width) / CELL_SIZE));
    height = static_cast<int>(std::ceil(static_cast<double>(game_map.map_height) / CELL_SIZE));

    std::vector<std::vector<hlt::EntityId>> row(height, std::vector<hlt::EntityId>());
    cells.resize(width, row);

    rebuild(game_map, radius_func);
}

auto CollisionMap::rebuild(const hlt::Map& game_map,
                           const std::function<double(const hlt::Ship&)> radius_func) -> void {
    hlt::PlayerId player = 0;
    for (const auto& player_ships : game_map.ships) {
        for (const auto& ship_pair : player_ships) {
            const auto& location = ship_pair.second.location;
            const auto id = hlt::EntityId::for_ship(player, ship_pair.first);

            add(location, radius_func(ship_pair.second), id);
        }

        player++;
    }
}

auto CollisionMap::add(const hlt::Location& location, double radius,
                       hlt::EntityId id) -> void {
    // Add the entity ID to all grid cells that the entity overlaps
    for (auto cell_x = 0; cell_x < width; cell_x++) {
        for (auto cell_y = 0; cell_y < height; cell_y++) {
            if (test_aabb_circle(cell_x * CELL_SIZE, cell_y * CELL_SIZE,
                                 CELL_SIZE, CELL_SIZE,
                                 location, radius)) {
                cells.at(cell_x).at(cell_y).push_back(id);
            }
        }
    }
}

auto CollisionMap::test(const hlt::Location& location, double radius,
                        std::vector<hlt::EntityId>& potential_collisions) -> void {
    // Add all IDs of any cell that overlaps the circle
    for (auto cell_x = 0; cell_x < width; cell_x++) {
        for (auto cell_y = 0; cell_y < height; cell_y++) {
            if (test_aabb_circle(cell_x * CELL_SIZE, cell_y * CELL_SIZE,
                                 CELL_SIZE, CELL_SIZE,
                                 location, radius)) {
                const auto& cell = cells.at(cell_x).at(cell_y);
                potential_collisions.insert(
                    potential_collisions.end(),
                    cell.begin(), cell.end()
                );
            }
        }
    }
}

auto collision_time(
    double r,
    const hlt::Location& loc1, const hlt::Location& loc2,
    const hlt::Velocity& vel1, const hlt::Velocity& vel2
) -> std::pair<bool, double> {
    // With credit to Ben Spector
    // Simplified derivation:
    // 1. Set up the distance between the two entities in terms of time,
    //    the difference between their velocities and the difference between
    //    their positions
    // 2. Equate the distance equal to the event radius (max possible distance
    //    they could be)
    // 3. Solve the resulting quadratic

    const auto dx = loc1.pos_x - loc2.pos_x;
    const auto dy = loc1.pos_y - loc2.pos_y;
    const auto dvx = vel1.vel_x - vel2.vel_x;
    const auto dvy = vel1.vel_y - vel2.vel_y;

    // Quadratic formula
    const auto a = std::pow(dvx, 2) + std::pow(dvy, 2);
    const auto b = 2 * (dx * dvx + dy * dvy);
    const auto c = std::pow(dx, 2) + std::pow(dy, 2) - std::pow(r, 2);

    const auto disc = std::pow(b, 2) - 4 * a * c;

    if (a == 0.0) {
        if (b == 0.0) {
            if (c <= 0.0) {
                // Implies r^2 >= dx^2 + dy^2 and the two are already colliding
                return { true, 0.0 };
            }
            return { false, 0.0 };
        }
        const auto t = -c / b;
        if (t >= 0.0) {
            return { true, t };
        }
        return { false, 0.0 };
    }
    else if (disc == 0.0) {
        // One solution
        const auto t = -b / (2 * a);
        return { true, t };
    }
    else if (disc > 0) {
        const auto t1 = (-b + std::sqrt(disc)) / (2 * a);
        const auto t2 = (-b - std::sqrt(disc)) / (2 * a);

        if(t1 >= 0.0 && t1 <= 1.0) {
            /// t1 is valid to pick, because it is in between 0 and 1
            return { true, t1 };
        } else if (t1 < 0.0 && t2 >= 0.0) {
            /// t1 is before 0 and t2 is after, but that means at t = 0.0 we are colliding
            return { true, 0.0 };
        } else {
            /// The range [0, 1] does not intersect with [t1, t2]
            return { false, 0.0 };
        }
    }
    else {
        return { false, 0.0 };
    }
}

auto collision_time(double r, const hlt::Ship& ship1, const hlt::Ship& ship2) -> std::pair<bool, double> {
    return collision_time(r,
                          ship1.location, ship2.location,
                          ship1.velocity, ship2.velocity);
}

auto collision_time(double r, const hlt::Ship& ship1, const hlt::Planet& planet) -> std::pair<bool, double> {
    return collision_time(r,
                          ship1.location, planet.location,
                          ship1.velocity, { 0, 0 });
}

auto might_attack(double distance, const hlt::Ship& ship1, const hlt::Ship& ship2) -> bool {
    return distance <= ship1.velocity.magnitude() + ship2.velocity.magnitude()
        + hlt::GameConstants::get().WEAPON_RADIUS;
}

auto might_collide(double distance, const hlt::Ship& ship1, const hlt::Ship& ship2) -> bool {
    return distance <= ship1.velocity.magnitude() + ship2.velocity.magnitude() +
        ship1.radius + ship2.radius;
}

auto round_event_time(double t) -> double {
    return std::round(t * EVENT_TIME_PRECISION) / EVENT_TIME_PRECISION;
}

auto find_events(
    std::unordered_set<SimulationEvent>& unsorted_events,
    const hlt::EntityId id1, const hlt::EntityId& id2,
    const hlt::Ship& ship1, const hlt::Ship& ship2) -> void {
    const auto distance = ship1.location.distance(ship2.location);
    const auto player1 = id1.player_id();
    const auto player2 = id2.player_id();

    if (player1 != player2 && might_attack(distance, ship1, ship2)) {
        // Combat event
        const auto attack_radius = ship1.radius +
            ship2.radius + hlt::GameConstants::get().WEAPON_RADIUS;
        const auto t = collision_time(attack_radius, ship1, ship2);
        if (t.first && t.second >= 0 && t.second <= 1) {
            unsorted_events.insert(SimulationEvent{
                SimulationEventType::Attack,
                id1, id2, round_event_time(t.second),
            });
        }
        else if (distance < attack_radius) {
            unsorted_events.insert(SimulationEvent{
                SimulationEventType::Attack,
                id1, id2, 0
            });
        }
    }

    if (id1 != id2 && might_collide(distance, ship1, ship2)) {
        // Collision event
        const auto collision_radius = ship1.radius + ship2.radius;
        const auto t = collision_time(collision_radius, ship1, ship2);
        if (t.first) {
            if (t.second >= 0 && t.second <= 1) {
                unsorted_events.insert(SimulationEvent{
                    SimulationEventType::Collision,
                    id1, id2, round_event_time(t.second),
                });
            }
        }
        else if (distance < collision_radius) {
            // This should never happen - the ships should already be dead
            assert(false);
        }
    }
}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: lngopt.hxx,v $
 *
 *  $Revision: 1.14 $
 *
 *  last change: $Author: rt $ $Date: 2007-01-29 15:46:04 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    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., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef _LINGUISTIC_LNGOPT_HHX_
#define _LINGUISTIC_LNGOPT_HHX_

#include <functional>

#include <uno/lbnames.h>            // CPPU_CURRENT_LANGUAGE_BINDING_NAME macro, which specify the environment type
#include <cppuhelper/implbase5.hxx> // helper for implementations

#ifndef _CPPUHELPER_INTERFACECONTAINER_HXX_
#include <cppuhelper/interfacecontainer.hxx>
#endif

#ifndef _COM_SUN_STAR_BEANS_XPROPERTYSET_HPP_
#include <com/sun/star/beans/XPropertySet.hpp>
#endif
#ifndef _COM_SUN_STAR_BEANS_XFASTPROPERTYSET_HPP_
#include <com/sun/star/beans/XFastPropertySet.hpp>
#endif
#ifndef _COM_SUN_STAR_LANG_XSERVICEINFO_HPP_
#include <com/sun/star/lang/XServiceInfo.hpp>
#endif
#ifndef _COM_SUN_STAR_BEANS_XPROPERTYACCESS_HPP_
#include <com/sun/star/beans/XPropertyAccess.hpp>
#endif
#ifndef _COM_SUN_STAR_LANG_XCOMPONENT_HPP_
#include <com/sun/star/lang/XComponent.hpp>
#endif

#ifndef _SVTOOLS_LINGUCFG_HXX_
#include <svtools/lingucfg.hxx>
#endif
#ifndef _SFX_ITEMPROP_HXX
#include <svtools/itemprop.hxx>
#endif
#ifndef _UTL_CONFIGITEM_HXX_
#include <unotools/configitem.hxx>
#endif

#ifndef _COM_SUN_STAR_UNO_ANY_H_
#include <com/sun/star/uno/Any.h>
#endif

#ifndef _SOLAR_H //autogen wg. INT16
#include <tools/solar.h>
#endif

#include <vcl/timer.hxx>
#include <svtools/itemprop.hxx>

#ifndef _LINGUISTIC_MISC_HXX_
#include "misc.hxx"
#endif
#ifndef _LINGUISTIC_DEFS_HXX_
#include "defs.hxx"
#endif

namespace com { namespace sun { namespace star {
    namespace beans {
        struct PropertyChangeEvent;
    }
    namespace registry {
        class XRegistryKey;
    }
}}};

///////////////////////////////////////////////////////////////////////////
// LinguOptions
// This class represents all Linguistik relevant options.
//

class LinguOptions
{
    static SvtLinguOptions     *pData;
    static vos::ORefCount       aRefCount;  // number of objects of this class

    //! uses default assignment-operator

    BOOL SetLocale_Impl( INT16 &rLanguage,
            ::com::sun::star::uno::Any &rOld,
            const ::com::sun::star::uno::Any &rVal);

public:
    LinguOptions();
    LinguOptions(const LinguOptions &rOpt);
    ~LinguOptions();

    BOOL            SetValue( ::com::sun::star::uno::Any &rOld,
                            const ::com::sun::star::uno::Any &rVal, INT32 nWID );
    void            GetValue( ::com::sun::star::uno::Any &rVal, INT32 nWID ) const;
    ::rtl::OUString GetName( INT32 nWID ) const;

    BOOL    IsSpellInAllLanguages() const   { return pData->bIsSpellInAllLanguages; }

    const ::com::sun::star::uno::Sequence< rtl::OUString >
            GetActiveDics() const   { return pData->aActiveDics; }

    const ::com::sun::star::uno::Sequence< rtl::OUString >
            GetActiveConvDics() const   { return pData->aActiveConvDics; }
};

///////////////////////////////////////////////////////////////////////////

// uses templates from <cppuhelper/interfacecontainer.h>

// helper function call class
struct PropHashType_Impl
{
    size_t operator()(const INT32 &s) const { return s; }
};

typedef cppu::OMultiTypeInterfaceContainerHelperVar
    <
        INT32,
        PropHashType_Impl,
        std::equal_to< INT32 >
    > OPropertyListenerContainerHelper;

///////////////////////////////////////////////////////////////////////////

class LinguProps :
    public cppu::WeakImplHelper5
    <
        com::sun::star::beans::XPropertySet,
        com::sun::star::beans::XFastPropertySet,
        com::sun::star::beans::XPropertyAccess,
        com::sun::star::lang::XComponent,
        com::sun::star::lang::XServiceInfo
    >
{
    ::cppu::OInterfaceContainerHelper           aEvtListeners;
    OPropertyListenerContainerHelper            aPropListeners;

    SfxItemPropertyMap                         *pMap;
    LinguOptions                                aOpt;

    BOOL                                        bDisposing;

    // disallow copy-constructor and assignment-operator for now
    LinguProps(const LinguProps &);
    LinguProps & operator = (const LinguProps &);

    void    launchEvent( const ::com::sun::star::beans::PropertyChangeEvent &rEvt ) const;

public:
    LinguProps();

    // XPropertySet
    virtual ::com::sun::star::uno::Reference<
            ::com::sun::star::beans::XPropertySetInfo > SAL_CALL
        getPropertySetInfo()
            throw(::com::sun::star::uno::RuntimeException);
    virtual void SAL_CALL
        setPropertyValue( const ::rtl::OUString& aPropertyName,
                const ::com::sun::star::uno::Any& aValue )
            throw(::com::sun::star::beans::UnknownPropertyException,
                  ::com::sun::star::beans::PropertyVetoException,
                  ::com::sun::star::lang::IllegalArgumentException,
                  ::com::sun::star::lang::WrappedTargetException,
                  ::com::sun::star::uno::RuntimeException);
    virtual ::com::sun::star::uno::Any SAL_CALL
        getPropertyValue( const ::rtl::OUString& PropertyName )
            throw(::com::sun::star::beans::UnknownPropertyException,
                  ::com::sun::star::lang::WrappedTargetException,
                  ::com::sun::star::uno::RuntimeException);
    virtual void SAL_CALL
        addPropertyChangeListener( const ::rtl::OUString& aPropertyName,
                const ::com::sun::star::uno::Reference<
                    ::com::sun::star::beans::XPropertyChangeListener >& rxListener )
            throw(::com::sun::star::beans::UnknownPropertyException,
                  ::com::sun::star::lang::WrappedTargetException,
                  ::com::sun::star::uno::RuntimeException);
    virtual void SAL_CALL
        removePropertyChangeListener( const ::rtl::OUString& aPropertyName,
                const ::com::sun::star::uno::Reference<
                    ::com::sun::star::beans::XPropertyChangeListener >& rxListener )
            throw(::com::sun::star::beans::UnknownPropertyException,
                  ::com::sun::star::lang::WrappedTargetException,
                  ::com::sun::star::uno::RuntimeException);
    virtual void SAL_CALL
        addVetoableChangeListener( const ::rtl::OUString& PropertyName,
                const ::com::sun::star::uno::Reference<
                    ::com::sun::star::beans::XVetoableChangeListener >& rxListener )
            throw(::com::sun::star::beans::UnknownPropertyException,
                  ::com::sun::star::lang::WrappedTargetException,
                  ::com::sun::star::uno::RuntimeException);
    virtual void SAL_CALL
        removeVetoableChangeListener( const ::rtl::OUString& PropertyName,
                const ::com::sun::star::uno::Reference<
                    ::com::sun::star::beans::XVetoableChangeListener >& rxListener )
            throw(::com::sun::star::beans::UnknownPropertyException,
                  ::com::sun::star::lang::WrappedTargetException,
                  ::com::sun::star::uno::RuntimeException);

    // XFastPropertySet
    virtual void SAL_CALL
        setFastPropertyValue( sal_Int32 nHandle, const ::com::sun::star::uno::Any& aValue )
            throw(::com::sun::star::beans::UnknownPropertyException,
                  ::com::sun::star::beans::PropertyVetoException,
                  ::com::sun::star::lang::IllegalArgumentException,
                  ::com::sun::star::lang::WrappedTargetException,
                  ::com::sun::star::uno::RuntimeException);
    virtual ::com::sun::star::uno::Any SAL_CALL
        getFastPropertyValue( sal_Int32 nHandle )
            throw(::com::sun::star::beans::UnknownPropertyException,
                  ::com::sun::star::lang::WrappedTargetException,
                  ::com::sun::star::uno::RuntimeException);

    // XPropertyAccess
    virtual ::com::sun::star::uno::Sequence<
            ::com::sun::star::beans::PropertyValue > SAL_CALL
        getPropertyValues()
            throw(::com::sun::star::uno::RuntimeException);
    virtual void SAL_CALL
        setPropertyValues( const ::com::sun::star::uno::Sequence<
                ::com::sun::star::beans::PropertyValue >& aProps )
            throw(::com::sun::star::beans::UnknownPropertyException,
                  ::com::sun::star::beans::PropertyVetoException,
                  ::com::sun::star::lang::IllegalArgumentException,
                  ::com::sun::star::lang::WrappedTargetException,
                  ::com::sun::star::uno::RuntimeException);

    // XComponent
    virtual void SAL_CALL
        dispose()
            throw(::com::sun::star::uno::RuntimeException);
    virtual void SAL_CALL
        addEventListener( const ::com::sun::star::uno::Reference<
                ::com::sun::star::lang::XEventListener >& rxListener )
            throw(::com::sun::star::uno::RuntimeException);
    virtual void SAL_CALL
        removeEventListener( const ::com::sun::star::uno::Reference<
                ::com::sun::star::lang::XEventListener >& rxListener )
            throw(::com::sun::star::uno::RuntimeException);

    ////////////////////////////////////////////////////////////
    // Service specific part
    //

    // XServiceInfo
    virtual ::rtl::OUString SAL_CALL
        getImplementationName()
            throw(::com::sun::star::uno::RuntimeException);
    virtual sal_Bool SAL_CALL
        supportsService( const ::rtl::OUString& ServiceName )
            throw(::com::sun::star::uno::RuntimeException);
    virtual ::com::sun::star::uno::Sequence< ::rtl::OUString > SAL_CALL
        getSupportedServiceNames()
            throw(::com::sun::star::uno::RuntimeException);

    static inline ::rtl::OUString
        getImplementationName_Static() throw();
    static com::sun::star::uno::Sequence< ::rtl::OUString >
        getSupportedServiceNames_Static() throw();
};

inline ::rtl::OUString LinguProps::getImplementationName_Static() throw()
{
    return A2OU( "com.sun.star.lingu2.LinguProps" );
}

///////////////////////////////////////////////////////////////////////////

#endif

<commit_msg>INTEGRATION: CWS tl32 (1.13.44); FILE MERGED 2007/04/11 10:25:50 tl 1.13.44.2: RESYNC: (1.13-1.14); FILE MERGED 2006/11/02 15:42:37 tl 1.13.44.1: #140479# warning-free code for unxsols4(.pro)<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: lngopt.hxx,v $
 *
 *  $Revision: 1.15 $
 *
 *  last change: $Author: vg $ $Date: 2007-05-25 12:23:46 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    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., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef _LINGUISTIC_LNGOPT_HHX_
#define _LINGUISTIC_LNGOPT_HHX_

#include <functional>

#include <uno/lbnames.h>            // CPPU_CURRENT_LANGUAGE_BINDING_NAME macro, which specify the environment type
#include <cppuhelper/implbase5.hxx> // helper for implementations

#ifndef _CPPUHELPER_INTERFACECONTAINER_HXX_
#include <cppuhelper/interfacecontainer.hxx>
#endif

#ifndef _COM_SUN_STAR_BEANS_XPROPERTYSET_HPP_
#include <com/sun/star/beans/XPropertySet.hpp>
#endif
#ifndef _COM_SUN_STAR_BEANS_XFASTPROPERTYSET_HPP_
#include <com/sun/star/beans/XFastPropertySet.hpp>
#endif
#ifndef _COM_SUN_STAR_LANG_XSERVICEINFO_HPP_
#include <com/sun/star/lang/XServiceInfo.hpp>
#endif
#ifndef _COM_SUN_STAR_BEANS_XPROPERTYACCESS_HPP_
#include <com/sun/star/beans/XPropertyAccess.hpp>
#endif
#ifndef _COM_SUN_STAR_LANG_XCOMPONENT_HPP_
#include <com/sun/star/lang/XComponent.hpp>
#endif

#ifndef _SVTOOLS_LINGUCFG_HXX_
#include <svtools/lingucfg.hxx>
#endif
#ifndef _SFX_ITEMPROP_HXX
#include <svtools/itemprop.hxx>
#endif
#ifndef _UTL_CONFIGITEM_HXX_
#include <unotools/configitem.hxx>
#endif

#ifndef _COM_SUN_STAR_UNO_ANY_H_
#include <com/sun/star/uno/Any.h>
#endif

#ifndef _SOLAR_H //autogen wg. INT16
#include <tools/solar.h>
#endif

#include <vcl/timer.hxx>
#include <svtools/itemprop.hxx>

#ifndef _LINGUISTIC_MISC_HXX_
#include "misc.hxx"
#endif
#ifndef _LINGUISTIC_DEFS_HXX_
#include "defs.hxx"
#endif

namespace com { namespace sun { namespace star {
    namespace beans {
        struct PropertyChangeEvent;
    }
    namespace registry {
        class XRegistryKey;
    }
}}}

///////////////////////////////////////////////////////////////////////////
// LinguOptions
// This class represents all Linguistik relevant options.
//

class LinguOptions
{
    static SvtLinguOptions     *pData;
    static vos::ORefCount       aRefCount;  // number of objects of this class

    //! uses default assignment-operator

    BOOL SetLocale_Impl( INT16 &rLanguage,
            ::com::sun::star::uno::Any &rOld,
            const ::com::sun::star::uno::Any &rVal);

public:
    LinguOptions();
    LinguOptions(const LinguOptions &rOpt);
    ~LinguOptions();

    BOOL            SetValue( ::com::sun::star::uno::Any &rOld,
                            const ::com::sun::star::uno::Any &rVal, INT32 nWID );
    void            GetValue( ::com::sun::star::uno::Any &rVal, INT32 nWID ) const;
    ::rtl::OUString GetName( INT32 nWID ) const;

    BOOL    IsSpellInAllLanguages() const   { return pData->bIsSpellInAllLanguages; }

    const ::com::sun::star::uno::Sequence< rtl::OUString >
            GetActiveDics() const   { return pData->aActiveDics; }

    const ::com::sun::star::uno::Sequence< rtl::OUString >
            GetActiveConvDics() const   { return pData->aActiveConvDics; }
};

///////////////////////////////////////////////////////////////////////////

// uses templates from <cppuhelper/interfacecontainer.h>

// helper function call class
struct PropHashType_Impl
{
    size_t operator()(const INT32 &s) const { return s; }
};

typedef cppu::OMultiTypeInterfaceContainerHelperVar
    <
        INT32,
        PropHashType_Impl,
        std::equal_to< INT32 >
    > OPropertyListenerContainerHelper;

///////////////////////////////////////////////////////////////////////////

class LinguProps :
    public cppu::WeakImplHelper5
    <
        com::sun::star::beans::XPropertySet,
        com::sun::star::beans::XFastPropertySet,
        com::sun::star::beans::XPropertyAccess,
        com::sun::star::lang::XComponent,
        com::sun::star::lang::XServiceInfo
    >
{
    ::cppu::OInterfaceContainerHelper           aEvtListeners;
    OPropertyListenerContainerHelper            aPropListeners;

    SfxItemPropertyMap                         *pMap;
    LinguOptions                                aOpt;

    BOOL                                        bDisposing;

    // disallow copy-constructor and assignment-operator for now
    LinguProps(const LinguProps &);
    LinguProps & operator = (const LinguProps &);

    void    launchEvent( const ::com::sun::star::beans::PropertyChangeEvent &rEvt ) const;

public:
    LinguProps();

    // XPropertySet
    virtual ::com::sun::star::uno::Reference<
            ::com::sun::star::beans::XPropertySetInfo > SAL_CALL
        getPropertySetInfo()
            throw(::com::sun::star::uno::RuntimeException);
    virtual void SAL_CALL
        setPropertyValue( const ::rtl::OUString& aPropertyName,
                const ::com::sun::star::uno::Any& aValue )
            throw(::com::sun::star::beans::UnknownPropertyException,
                  ::com::sun::star::beans::PropertyVetoException,
                  ::com::sun::star::lang::IllegalArgumentException,
                  ::com::sun::star::lang::WrappedTargetException,
                  ::com::sun::star::uno::RuntimeException);
    virtual ::com::sun::star::uno::Any SAL_CALL
        getPropertyValue( const ::rtl::OUString& PropertyName )
            throw(::com::sun::star::beans::UnknownPropertyException,
                  ::com::sun::star::lang::WrappedTargetException,
                  ::com::sun::star::uno::RuntimeException);
    virtual void SAL_CALL
        addPropertyChangeListener( const ::rtl::OUString& aPropertyName,
                const ::com::sun::star::uno::Reference<
                    ::com::sun::star::beans::XPropertyChangeListener >& rxListener )
            throw(::com::sun::star::beans::UnknownPropertyException,
                  ::com::sun::star::lang::WrappedTargetException,
                  ::com::sun::star::uno::RuntimeException);
    virtual void SAL_CALL
        removePropertyChangeListener( const ::rtl::OUString& aPropertyName,
                const ::com::sun::star::uno::Reference<
                    ::com::sun::star::beans::XPropertyChangeListener >& rxListener )
            throw(::com::sun::star::beans::UnknownPropertyException,
                  ::com::sun::star::lang::WrappedTargetException,
                  ::com::sun::star::uno::RuntimeException);
    virtual void SAL_CALL
        addVetoableChangeListener( const ::rtl::OUString& PropertyName,
                const ::com::sun::star::uno::Reference<
                    ::com::sun::star::beans::XVetoableChangeListener >& rxListener )
            throw(::com::sun::star::beans::UnknownPropertyException,
                  ::com::sun::star::lang::WrappedTargetException,
                  ::com::sun::star::uno::RuntimeException);
    virtual void SAL_CALL
        removeVetoableChangeListener( const ::rtl::OUString& PropertyName,
                const ::com::sun::star::uno::Reference<
                    ::com::sun::star::beans::XVetoableChangeListener >& rxListener )
            throw(::com::sun::star::beans::UnknownPropertyException,
                  ::com::sun::star::lang::WrappedTargetException,
                  ::com::sun::star::uno::RuntimeException);

    // XFastPropertySet
    virtual void SAL_CALL
        setFastPropertyValue( sal_Int32 nHandle, const ::com::sun::star::uno::Any& aValue )
            throw(::com::sun::star::beans::UnknownPropertyException,
                  ::com::sun::star::beans::PropertyVetoException,
                  ::com::sun::star::lang::IllegalArgumentException,
                  ::com::sun::star::lang::WrappedTargetException,
                  ::com::sun::star::uno::RuntimeException);
    virtual ::com::sun::star::uno::Any SAL_CALL
        getFastPropertyValue( sal_Int32 nHandle )
            throw(::com::sun::star::beans::UnknownPropertyException,
                  ::com::sun::star::lang::WrappedTargetException,
                  ::com::sun::star::uno::RuntimeException);

    // XPropertyAccess
    virtual ::com::sun::star::uno::Sequence<
            ::com::sun::star::beans::PropertyValue > SAL_CALL
        getPropertyValues()
            throw(::com::sun::star::uno::RuntimeException);
    virtual void SAL_CALL
        setPropertyValues( const ::com::sun::star::uno::Sequence<
                ::com::sun::star::beans::PropertyValue >& aProps )
            throw(::com::sun::star::beans::UnknownPropertyException,
                  ::com::sun::star::beans::PropertyVetoException,
                  ::com::sun::star::lang::IllegalArgumentException,
                  ::com::sun::star::lang::WrappedTargetException,
                  ::com::sun::star::uno::RuntimeException);

    // XComponent
    virtual void SAL_CALL
        dispose()
            throw(::com::sun::star::uno::RuntimeException);
    virtual void SAL_CALL
        addEventListener( const ::com::sun::star::uno::Reference<
                ::com::sun::star::lang::XEventListener >& rxListener )
            throw(::com::sun::star::uno::RuntimeException);
    virtual void SAL_CALL
        removeEventListener( const ::com::sun::star::uno::Reference<
                ::com::sun::star::lang::XEventListener >& rxListener )
            throw(::com::sun::star::uno::RuntimeException);

    ////////////////////////////////////////////////////////////
    // Service specific part
    //

    // XServiceInfo
    virtual ::rtl::OUString SAL_CALL
        getImplementationName()
            throw(::com::sun::star::uno::RuntimeException);
    virtual sal_Bool SAL_CALL
        supportsService( const ::rtl::OUString& ServiceName )
            throw(::com::sun::star::uno::RuntimeException);
    virtual ::com::sun::star::uno::Sequence< ::rtl::OUString > SAL_CALL
        getSupportedServiceNames()
            throw(::com::sun::star::uno::RuntimeException);

    static inline ::rtl::OUString
        getImplementationName_Static() throw();
    static com::sun::star::uno::Sequence< ::rtl::OUString >
        getSupportedServiceNames_Static() throw();
};

inline ::rtl::OUString LinguProps::getImplementationName_Static() throw()
{
    return A2OU( "com.sun.star.lingu2.LinguProps" );
}

///////////////////////////////////////////////////////////////////////////

#endif

<|endoftext|>