<commit_before>/*
    Copyright (c) 2007 Till Adam <adam@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 "maildirresource.h"
#include "settings.h"
#include "settingsadaptor.h"
#include "configdialog.h"

#include <QtCore/QDir>
#include <QtDBus/QDBusConnection>

#include <akonadi/kmime/messageparts.h>
#include <akonadi/changerecorder.h>
#include <akonadi/itemfetchscope.h>
#include <kdebug.h>
#include <kurl.h>
#include <kfiledialog.h>
#include <klocale.h>

#include <KWindowSystem>

#include "libmaildir/maildir.h"

#include <kmime/kmime_message.h>

#include <boost/shared_ptr.hpp>
typedef boost::shared_ptr<KMime::Message> MessagePtr;

using namespace Akonadi;
using KPIM::Maildir;

static QString maildirPath( const QString &remoteId )
{
  const int pos = remoteId.lastIndexOf( QDir::separator() );
  if ( pos >= 0 )
    return remoteId.left( pos );
  return QString();
}

static QString maildirId( const QString &remoteId )
{
  const int pos = remoteId.lastIndexOf( QDir::separator() );
  if ( pos >= 0 )
    return remoteId.mid( pos + 1 );
  return QString();
}

static QString maildirSubdirPath( const QString &parentPath, const QString &subName )
{
  QString basePath = maildirPath( parentPath );
  if ( !basePath.endsWith( QDir::separator() ) )
    basePath += QDir::separator();
  const QString name = maildirId( parentPath );
  return basePath + '.' + name + ".directory" + QDir::separator() + subName;
}

MaildirResource::MaildirResource( const QString &id )
    :ResourceBase( id )
{
  new SettingsAdaptor( Settings::self() );
  QDBusConnection::sessionBus().registerObject( QLatin1String( "/Settings" ),
                              Settings::self(), QDBusConnection::ExportAdaptors );
  connect( this, SIGNAL(reloadConfiguration()), SLOT(ensureDirExists()) );

  // We need to enable this here, otherwise we neither get the remote ID of the
  // parent collection when a collection changes, nor the full item when an item
  // is added.
  changeRecorder()->fetchCollection( true );
  changeRecorder()->itemFetchScope().fetchFullPayload( true );
}

MaildirResource::~ MaildirResource()
{
}

bool MaildirResource::retrieveItem( const Akonadi::Item &item, const QSet<QByteArray> &parts )
{
  Q_UNUSED( parts );

  const QString dir = maildirPath( item.remoteId() );
  const QString entry = maildirId( item.remoteId() );

  Maildir md( dir );
  if ( !md.isValid() ) {
    cancelTask( i18n( "Unable to fetch item: The maildir folder \"%1\" is not valid.",
                      md.path() ) );
    return false;
  }

  const QByteArray data = md.readEntry( entry );
  KMime::Message *mail = new KMime::Message();
  mail->setContent( KMime::CRLFtoLF( data ) );
  mail->parse();

  Item i( item );
  i.setPayload( MessagePtr( mail ) );
  itemRetrieved( i );
  return true;
}

void MaildirResource::aboutToQuit()
{
  // The settings may not have been saved if e.g. they have been modified via
  // DBus instead of the config dialog.
  Settings::self()->writeConfig();
  kDebug( 5254 ) << "Implement me!" ;
}

void MaildirResource::configure( WId windowId )
{
  ConfigDialog dlg;
  if ( windowId )
    KWindowSystem::setMainWindow( &dlg, windowId );
  dlg.exec();

  ensureDirExists();
  synchronizeCollectionTree();
}

void MaildirResource::itemAdded( const Akonadi::Item & item, const Akonadi::Collection& collection )
{
    Maildir dir( collection.remoteId() );
    QString errMsg;
    if ( Settings::readOnly() || !dir.isValid( errMsg ) ) {
      cancelTask( errMsg );
      return;
    }
    // we can only deal with mail
    if ( item.mimeType() != "message/rfc822" ) {
      cancelTask( i18n("Only email messages can be added to the Maildir resource.") );
      return;
    }
    const MessagePtr mail = item.payload<MessagePtr>();
    const QString rid = collection.remoteId() + QDir::separator() + dir.addEntry( mail->encodedContent() );
    Item i( item );
    i.setRemoteId( rid );
    changeCommitted( i );
}

void MaildirResource::itemChanged( const Akonadi::Item& item, const QSet<QByteArray>& parts )
{
    if ( Settings::self()->readOnly() || !parts.contains( MessagePart::Body ) ) {
      changeProcessed();
      return;
    }

    const QString path = maildirPath( item.remoteId() );
    const QString entry = maildirId( item.remoteId() );

    Maildir dir( path );
    QString errMsg;
    if ( !dir.isValid( errMsg ) ) {
        cancelTask( errMsg );
        return;
    }
    // we can only deal with mail
    if ( item.mimeType() != "message/rfc822" ) {
        cancelTask( i18n("Only email messages can be added to the Maildir resource.") );
        return;
    }
    const MessagePtr mail = item.payload<MessagePtr>();
    dir.writeEntry( entry, mail->encodedContent() );
    changeCommitted( item );
}

void MaildirResource::itemRemoved(const Akonadi::Item & item)
{
  if ( !Settings::self()->readOnly() ) {
    const QString path = maildirPath( item.remoteId() );
    const QString entry = maildirId( item.remoteId() );

    Maildir dir( path );
    QString errMsg;
    if ( !dir.isValid( errMsg ) ) {
      cancelTask( errMsg );
      return;
    }
    if ( !dir.removeEntry( entry ) ) {
      emit error( i18n("Failed to delete item: %1", item.remoteId()) );
    }
  }
  changeProcessed();
}

Collection::List listRecursive( const Collection &root, const Maildir &dir )
{
  Collection::List list;
  const QStringList mimeTypes = QStringList() << "message/rfc822" << Collection::mimeType();
  foreach ( const QString &sub, dir.subFolderList() ) {
    const QString path = maildirSubdirPath( root.remoteId(), sub );
    Maildir md( path );
    if ( !md.isValid() )
      continue;
    Collection c;
    c.setName( sub );
    c.setRemoteId( path );
    c.setParent( root );
    c.setContentMimeTypes( mimeTypes );
    list << c;
    list += listRecursive( c, md );
  }
  return list;
}

void MaildirResource::retrieveCollections()
{
  Maildir dir( Settings::self()->path() );
  QString errMsg;
  if ( !dir.isValid( errMsg ) ) {
    emit error( errMsg );
    collectionsRetrieved( Collection::List() );
  }

  Collection root;
  root.setParent( Collection::root() );
  root.setRemoteId( Settings::self()->path() );
  root.setName( name() );
  QStringList mimeTypes;
  mimeTypes << "message/rfc822" << Collection::mimeType();
  root.setContentMimeTypes( mimeTypes );

  Collection::List list;
  list << root;
  list += listRecursive( root, dir );
  collectionsRetrieved( list );
}

void MaildirResource::retrieveItems( const Akonadi::Collection & col )
{
  Maildir md( col.remoteId() );
  if ( !md.isValid() ) {
    emit error( i18n("Invalid maildir: %1", col.remoteId() ) );
    itemsRetrieved( Item::List() );
    return;
  }
  QStringList entryList = md.entryList();

  Item::List items;
  foreach ( const QString &entry, entryList ) {
    const QString rid = col.remoteId() + QDir::separator() + entry;
    Item item;
    item.setRemoteId( rid );
    item.setMimeType( "message/rfc822" );
    item.setSize( md.size( entry ) );
    KMime::Message *msg = new KMime::Message;
    msg->setHead( KMime::CRLFtoLF( md.readEntryHeaders( entry ) ) );
    msg->parse();
    item.setPayload( MessagePtr( msg ) );
    items << item;
  }
  itemsRetrieved( items );
}

void MaildirResource::collectionAdded(const Collection & collection, const Collection &parent)
{
  Maildir md( parent.remoteId() );
  kDebug( 5254 ) << md.subFolderList() << md.entryList();
  if ( Settings::self()->readOnly() || !md.isValid() ) {
    changeProcessed();
    return;
  }
  else {

    QString newFolderPath = md.addSubFolder( collection.name() );
    if ( newFolderPath.isEmpty() ) {
      changeProcessed();
      return;
    }

    kDebug( 5254 ) << md.subFolderList() << md.entryList();

    Collection col = collection;
    col.setRemoteId( newFolderPath );
    changeCommitted( col );
  }

}

void MaildirResource::collectionChanged(const Collection & collection)
{
  kDebug( 5254 ) << "Implement me!";
  AgentBase::Observer::collectionChanged( collection );
}

void MaildirResource::collectionRemoved( const Akonadi::Collection &collection )
{
  kDebug( 5254 ) << "Implement me!";
  AgentBase::Observer::collectionRemoved( collection );
}

void MaildirResource::ensureDirExists()
{
  Maildir root( Settings::self()->path() );
  if ( !root.isValid() ) {
    if ( !root.create() )
      emit status( Broken, i18n( "Unable to create maildir '%1'.", Settings::self()->path() ) );
  }
}

AKONADI_RESOURCE_MAIN( MaildirResource )

#include "maildirresource.moc"
<commit_msg>Honor the top-level container setting, fix possible assert on error.<commit_after>/*
    Copyright (c) 2007 Till Adam <adam@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 "maildirresource.h"
#include "settings.h"
#include "settingsadaptor.h"
#include "configdialog.h"

#include <QtCore/QDir>
#include <QtDBus/QDBusConnection>

#include <akonadi/kmime/messageparts.h>
#include <akonadi/changerecorder.h>
#include <akonadi/itemfetchscope.h>
#include <kdebug.h>
#include <kurl.h>
#include <kfiledialog.h>
#include <klocale.h>

#include <KWindowSystem>

#include "libmaildir/maildir.h"

#include <kmime/kmime_message.h>

#include <boost/shared_ptr.hpp>
typedef boost::shared_ptr<KMime::Message> MessagePtr;

using namespace Akonadi;
using KPIM::Maildir;

static QString maildirPath( const QString &remoteId )
{
  const int pos = remoteId.lastIndexOf( QDir::separator() );
  if ( pos >= 0 )
    return remoteId.left( pos );
  return QString();
}

static QString maildirId( const QString &remoteId )
{
  const int pos = remoteId.lastIndexOf( QDir::separator() );
  if ( pos >= 0 )
    return remoteId.mid( pos + 1 );
  return QString();
}

static QString maildirSubdirPath( const QString &parentPath, const QString &subName )
{
  QString basePath = maildirPath( parentPath );
  if ( !basePath.endsWith( QDir::separator() ) )
    basePath += QDir::separator();
  const QString name = maildirId( parentPath );
  return basePath + '.' + name + ".directory" + QDir::separator() + subName;
}

MaildirResource::MaildirResource( const QString &id )
    :ResourceBase( id )
{
  new SettingsAdaptor( Settings::self() );
  QDBusConnection::sessionBus().registerObject( QLatin1String( "/Settings" ),
                              Settings::self(), QDBusConnection::ExportAdaptors );
  connect( this, SIGNAL(reloadConfiguration()), SLOT(ensureDirExists()) );

  // We need to enable this here, otherwise we neither get the remote ID of the
  // parent collection when a collection changes, nor the full item when an item
  // is added.
  changeRecorder()->fetchCollection( true );
  changeRecorder()->itemFetchScope().fetchFullPayload( true );
}

MaildirResource::~ MaildirResource()
{
}

bool MaildirResource::retrieveItem( const Akonadi::Item &item, const QSet<QByteArray> &parts )
{
  Q_UNUSED( parts );

  const QString dir = maildirPath( item.remoteId() );
  const QString entry = maildirId( item.remoteId() );

  Maildir md( dir );
  if ( !md.isValid() ) {
    cancelTask( i18n( "Unable to fetch item: The maildir folder \"%1\" is not valid.",
                      md.path() ) );
    return false;
  }

  const QByteArray data = md.readEntry( entry );
  KMime::Message *mail = new KMime::Message();
  mail->setContent( KMime::CRLFtoLF( data ) );
  mail->parse();

  Item i( item );
  i.setPayload( MessagePtr( mail ) );
  itemRetrieved( i );
  return true;
}

void MaildirResource::aboutToQuit()
{
  // The settings may not have been saved if e.g. they have been modified via
  // DBus instead of the config dialog.
  Settings::self()->writeConfig();
  kDebug( 5254 ) << "Implement me!" ;
}

void MaildirResource::configure( WId windowId )
{
  ConfigDialog dlg;
  if ( windowId )
    KWindowSystem::setMainWindow( &dlg, windowId );
  dlg.exec();

  ensureDirExists();
  synchronizeCollectionTree();
}

void MaildirResource::itemAdded( const Akonadi::Item & item, const Akonadi::Collection& collection )
{
    Maildir dir( collection.remoteId() );
    QString errMsg;
    if ( Settings::readOnly() || !dir.isValid( errMsg ) ) {
      cancelTask( errMsg );
      return;
    }
    // we can only deal with mail
    if ( item.mimeType() != "message/rfc822" ) {
      cancelTask( i18n("Only email messages can be added to the Maildir resource.") );
      return;
    }
    const MessagePtr mail = item.payload<MessagePtr>();
    const QString rid = collection.remoteId() + QDir::separator() + dir.addEntry( mail->encodedContent() );
    Item i( item );
    i.setRemoteId( rid );
    changeCommitted( i );
}

void MaildirResource::itemChanged( const Akonadi::Item& item, const QSet<QByteArray>& parts )
{
    if ( Settings::self()->readOnly() || !parts.contains( MessagePart::Body ) ) {
      changeProcessed();
      return;
    }

    const QString path = maildirPath( item.remoteId() );
    const QString entry = maildirId( item.remoteId() );

    Maildir dir( path );
    QString errMsg;
    if ( !dir.isValid( errMsg ) ) {
        cancelTask( errMsg );
        return;
    }
    // we can only deal with mail
    if ( item.mimeType() != "message/rfc822" ) {
        cancelTask( i18n("Only email messages can be added to the Maildir resource.") );
        return;
    }
    const MessagePtr mail = item.payload<MessagePtr>();
    dir.writeEntry( entry, mail->encodedContent() );
    changeCommitted( item );
}

void MaildirResource::itemRemoved(const Akonadi::Item & item)
{
  if ( !Settings::self()->readOnly() ) {
    const QString path = maildirPath( item.remoteId() );
    const QString entry = maildirId( item.remoteId() );

    Maildir dir( path );
    QString errMsg;
    if ( !dir.isValid( errMsg ) ) {
      cancelTask( errMsg );
      return;
    }
    if ( !dir.removeEntry( entry ) ) {
      emit error( i18n("Failed to delete item: %1", item.remoteId()) );
    }
  }
  changeProcessed();
}

Collection::List listRecursive( const Collection &root, const Maildir &dir )
{
  Collection::List list;
  const QStringList mimeTypes = QStringList() << "message/rfc822" << Collection::mimeType();
  foreach ( const QString &sub, dir.subFolderList() ) {
    const QString path = maildirSubdirPath( root.remoteId(), sub );
    Maildir md( path );
    if ( !md.isValid() )
      continue;
    Collection c;
    c.setName( sub );
    c.setRemoteId( path );
    c.setParent( root );
    c.setContentMimeTypes( mimeTypes );
    list << c;
    list += listRecursive( c, md );
  }
  return list;
}

void MaildirResource::retrieveCollections()
{
  Maildir dir( Settings::self()->path(), Settings::self()->topLevelIsContainer() );
  QString errMsg;
  if ( !dir.isValid( errMsg ) ) {
    emit error( errMsg );
    collectionsRetrieved( Collection::List() );
    return;
  }

  Collection root;
  root.setParentCollection( Collection::root() );
  root.setRemoteId( Settings::self()->path() );
  root.setName( name() );
  QStringList mimeTypes;
  mimeTypes << Collection::mimeType();
  if ( !Settings::self()->topLevelIsContainer() )
    mimeTypes << "message/rfc822";
  root.setContentMimeTypes( mimeTypes );

  Collection::List list;
  list << root;
  list += listRecursive( root, dir );
  collectionsRetrieved( list );
}

void MaildirResource::retrieveItems( const Akonadi::Collection & col )
{
  Maildir md( col.remoteId() );
  if ( !md.isValid() ) {
    emit error( i18n("Invalid maildir: %1", col.remoteId() ) );
    itemsRetrieved( Item::List() );
    return;
  }
  QStringList entryList = md.entryList();

  Item::List items;
  foreach ( const QString &entry, entryList ) {
    const QString rid = col.remoteId() + QDir::separator() + entry;
    Item item;
    item.setRemoteId( rid );
    item.setMimeType( "message/rfc822" );
    item.setSize( md.size( entry ) );
    KMime::Message *msg = new KMime::Message;
    msg->setHead( KMime::CRLFtoLF( md.readEntryHeaders( entry ) ) );
    msg->parse();
    item.setPayload( MessagePtr( msg ) );
    items << item;
  }
  itemsRetrieved( items );
}

void MaildirResource::collectionAdded(const Collection & collection, const Collection &parent)
{
  Maildir md( parent.remoteId() );
  kDebug( 5254 ) << md.subFolderList() << md.entryList();
  if ( Settings::self()->readOnly() || !md.isValid() ) {
    changeProcessed();
    return;
  }
  else {

    QString newFolderPath = md.addSubFolder( collection.name() );
    if ( newFolderPath.isEmpty() ) {
      changeProcessed();
      return;
    }

    kDebug( 5254 ) << md.subFolderList() << md.entryList();

    Collection col = collection;
    col.setRemoteId( newFolderPath );
    changeCommitted( col );
  }

}

void MaildirResource::collectionChanged(const Collection & collection)
{
  kDebug( 5254 ) << "Implement me!";
  AgentBase::Observer::collectionChanged( collection );
}

void MaildirResource::collectionRemoved( const Akonadi::Collection &collection )
{
  kDebug( 5254 ) << "Implement me!";
  AgentBase::Observer::collectionRemoved( collection );
}

void MaildirResource::ensureDirExists()
{
  Maildir root( Settings::self()->path() );
  if ( !root.isValid() ) {
    if ( !root.create() )
      emit status( Broken, i18n( "Unable to create maildir '%1'.", Settings::self()->path() ) );
  }
}

AKONADI_RESOURCE_MAIN( MaildirResource )

#include "maildirresource.moc"
<|endoftext|>


<commit_before>/*
* Copyright 2016 Nu-book Inc.
* Copyright 2016 ZXing authors
*/
// SPDX-License-Identifier: Apache-2.0

#include "Result.h"

#include "DecoderResult.h"
#include "TextDecoder.h"

#include <cmath>
#include <list>
#include <map>
#include <utility>

namespace ZXing {

Result::Result(const std::string& text, int y, int xStart, int xStop, BarcodeFormat format,
			   SymbologyIdentifier si, ByteArray&& rawBytes, const bool readerInit)
	:
	  _format(format),
	  _content({ByteArray(text)}, si),
	  _position(Line(y, xStart, xStop)),
	  _rawBytes(std::move(rawBytes)),
	  _numBits(Size(_rawBytes) * 8),
	  _readerInit(readerInit),
	  _lineCount(0)
{}

Result::Result(DecoderResult&& decodeResult, Position&& position, BarcodeFormat format)
	: _status(decodeResult.errorCode()),
	  _format(format),
	  _content(std::move(decodeResult).content()),
	  _position(std::move(position)),
	  _rawBytes(std::move(decodeResult).rawBytes()),
	  _numBits(decodeResult.numBits()),
	  _ecLevel(TextDecoder::FromLatin1(decodeResult.ecLevel())),
	  _sai(decodeResult.structuredAppend()),
	  _isMirrored(decodeResult.isMirrored()),
	  _readerInit(decodeResult.readerInit()),
	  _lineCount(decodeResult.lineCount())
{
	// TODO: add type opaque and code specific 'extra data'? (see DecoderResult::extra())
}

std::wstring Result::text() const
{
	return _content.text();
}

const ByteArray& Result::bytes() const
{
	return _content.bytes;
}

ByteArray Result::bytesECI() const
{
	return _content.bytesECI();
}

std::string Result::utf8Protocol() const
{
	return _content.utf8Protocol();
}

ContentType Result::contentType() const
{
	return _content.type();
}

bool Result::hasECI() const
{
	return _content.hasECI;
}

int Result::orientation() const
{
	constexpr auto std_numbers_pi_v = 3.14159265358979323846; // TODO: c++20 <numbers>
	return std::lround(_position.orientation() * 180 / std_numbers_pi_v);
}

std::string Result::symbologyIdentifier() const
{
	return _content.symbology.toString();
}

int Result::sequenceSize() const
{
	return _sai.count;
}

int Result::sequenceIndex() const
{
	return _sai.index;
}

std::string Result::sequenceId() const
{
	return _sai.id;
}

bool Result::operator==(const Result& o) const
{
	if (format() != o.format() || text() != o.text())
		return false;

	if (BarcodeFormats(BarcodeFormat::TwoDCodes).testFlag(format()))
		return IsInside(Center(o.position()), position());

	// if one line is less than half the length of the other away from the
	// latter, we consider it to belong to the same symbol
	auto dTop = maxAbsComponent(o.position().topLeft() - position().topLeft());
	auto dBot = maxAbsComponent(o.position().bottomLeft() - position().topLeft());
	auto length = maxAbsComponent(position().topLeft() - position().bottomRight());

	return std::min(dTop, dBot) < length / 2;
}

Result MergeStructuredAppendSequence(const Results& results)
{
	if (results.empty())
		return Result(DecodeStatus::NotFound);

	std::list<Result> allResults(results.begin(), results.end());
	allResults.sort([](const Result& r1, const Result& r2) { return r1.sequenceIndex() < r2.sequenceIndex(); });

	if (allResults.back().sequenceSize() != Size(allResults) ||
		!std::all_of(allResults.begin(), allResults.end(),
					 [&](Result& it) { return it.sequenceId() == allResults.front().sequenceId(); }))
		return Result(DecodeStatus::FormatError);

	Result res = allResults.front();
	for (auto i = std::next(allResults.begin()); i != allResults.end(); ++i)
		res._content.append(i->_content);

	res._position = {};
	res._sai.index = -1;

	return res;
}

Results MergeStructuredAppendSequences(const Results& results)
{
	std::map<std::string, Results> sas;
	for (auto& res : results) {
		if (res.isPartOfSequence())
			sas[res.sequenceId()].push_back(res);
	}

	Results saiResults;
	for (auto& [id, seq] : sas) {
		auto res = MergeStructuredAppendSequence(seq);
		if (res.isValid())
			saiResults.push_back(std::move(res));
	}

	return saiResults;
}

} // ZXing
<commit_msg>Result: compare bytes instead of text in opoerator== (performance)<commit_after>/*
* Copyright 2016 Nu-book Inc.
* Copyright 2016 ZXing authors
*/
// SPDX-License-Identifier: Apache-2.0

#include "Result.h"

#include "DecoderResult.h"
#include "TextDecoder.h"

#include <cmath>
#include <list>
#include <map>
#include <utility>

namespace ZXing {

Result::Result(const std::string& text, int y, int xStart, int xStop, BarcodeFormat format,
			   SymbologyIdentifier si, ByteArray&& rawBytes, const bool readerInit)
	:
	  _format(format),
	  _content({ByteArray(text)}, si),
	  _position(Line(y, xStart, xStop)),
	  _rawBytes(std::move(rawBytes)),
	  _numBits(Size(_rawBytes) * 8),
	  _readerInit(readerInit),
	  _lineCount(0)
{}

Result::Result(DecoderResult&& decodeResult, Position&& position, BarcodeFormat format)
	: _status(decodeResult.errorCode()),
	  _format(format),
	  _content(std::move(decodeResult).content()),
	  _position(std::move(position)),
	  _rawBytes(std::move(decodeResult).rawBytes()),
	  _numBits(decodeResult.numBits()),
	  _ecLevel(TextDecoder::FromLatin1(decodeResult.ecLevel())),
	  _sai(decodeResult.structuredAppend()),
	  _isMirrored(decodeResult.isMirrored()),
	  _readerInit(decodeResult.readerInit()),
	  _lineCount(decodeResult.lineCount())
{
	// TODO: add type opaque and code specific 'extra data'? (see DecoderResult::extra())
}

std::wstring Result::text() const
{
	return _content.text();
}

const ByteArray& Result::bytes() const
{
	return _content.bytes;
}

ByteArray Result::bytesECI() const
{
	return _content.bytesECI();
}

std::string Result::utf8Protocol() const
{
	return _content.utf8Protocol();
}

ContentType Result::contentType() const
{
	return _content.type();
}

bool Result::hasECI() const
{
	return _content.hasECI;
}

int Result::orientation() const
{
	constexpr auto std_numbers_pi_v = 3.14159265358979323846; // TODO: c++20 <numbers>
	return std::lround(_position.orientation() * 180 / std_numbers_pi_v);
}

std::string Result::symbologyIdentifier() const
{
	return _content.symbology.toString();
}

int Result::sequenceSize() const
{
	return _sai.count;
}

int Result::sequenceIndex() const
{
	return _sai.index;
}

std::string Result::sequenceId() const
{
	return _sai.id;
}

bool Result::operator==(const Result& o) const
{
	if (format() != o.format() || bytes() != o.bytes())
		return false;

	if (BarcodeFormats(BarcodeFormat::TwoDCodes).testFlag(format()))
		return IsInside(Center(o.position()), position());

	// if one line is less than half the length of the other away from the
	// latter, we consider it to belong to the same symbol
	auto dTop = maxAbsComponent(o.position().topLeft() - position().topLeft());
	auto dBot = maxAbsComponent(o.position().bottomLeft() - position().topLeft());
	auto length = maxAbsComponent(position().topLeft() - position().bottomRight());

	return std::min(dTop, dBot) < length / 2;
}

Result MergeStructuredAppendSequence(const Results& results)
{
	if (results.empty())
		return Result(DecodeStatus::NotFound);

	std::list<Result> allResults(results.begin(), results.end());
	allResults.sort([](const Result& r1, const Result& r2) { return r1.sequenceIndex() < r2.sequenceIndex(); });

	if (allResults.back().sequenceSize() != Size(allResults) ||
		!std::all_of(allResults.begin(), allResults.end(),
					 [&](Result& it) { return it.sequenceId() == allResults.front().sequenceId(); }))
		return Result(DecodeStatus::FormatError);

	Result res = allResults.front();
	for (auto i = std::next(allResults.begin()); i != allResults.end(); ++i)
		res._content.append(i->_content);

	res._position = {};
	res._sai.index = -1;

	return res;
}

Results MergeStructuredAppendSequences(const Results& results)
{
	std::map<std::string, Results> sas;
	for (auto& res : results) {
		if (res.isPartOfSequence())
			sas[res.sequenceId()].push_back(res);
	}

	Results saiResults;
	for (auto& [id, seq] : sas) {
		auto res = MergeStructuredAppendSequence(seq);
		if (res.isValid())
			saiResults.push_back(std::move(res));
	}

	return saiResults;
}

} // ZXing
<|endoftext|>


<commit_before>// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "android_webview/native/aw_dev_tools_server.h"

#include "android_webview/native/aw_contents.h"
#include "base/bind.h"
#include "base/files/file_path.h"
#include "base/json/json_writer.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/values.h"
#include "content/public/browser/android/devtools_auth.h"
#include "content/public/browser/devtools_agent_host.h"
#include "content/public/browser/devtools_http_handler.h"
#include "content/public/browser/devtools_http_handler_delegate.h"
#include "content/public/browser/devtools_target.h"
#include "content/public/browser/web_contents.h"
#include "content/public/common/user_agent.h"
#include "jni/AwDevToolsServer_jni.h"
#include "net/socket/unix_domain_server_socket_posix.h"

using content::DevToolsAgentHost;
using content::RenderViewHost;
using content::WebContents;

namespace {

const char kFrontEndURL[] =
    "http://chrome-devtools-frontend.appspot.com/serve_rev/%s/devtools.html";
const char kSocketNameFormat[] = "webview_devtools_remote_%d";

// Delegate implementation for the devtools http handler for WebView. A new
// instance of this gets created each time web debugging is enabled.
class AwDevToolsServerDelegate : public content::DevToolsHttpHandlerDelegate {
 public:
  AwDevToolsServerDelegate() {}
  virtual ~AwDevToolsServerDelegate() {}

  // DevToolsHttpProtocolHandler::Delegate overrides.
  std::string GetDiscoveryPageHTML() override;

  bool BundlesFrontendResources() override {
    return false;
  }

  base::FilePath GetDebugFrontendDir() override {
    return base::FilePath();
  }

  scoped_ptr<net::ServerSocket>
  CreateSocketForTethering(std::string* name) override {
    return scoped_ptr<net::ServerSocket>();
  }

 private:
  DISALLOW_COPY_AND_ASSIGN(AwDevToolsServerDelegate);
};

std::string AwDevToolsServerDelegate::GetDiscoveryPageHTML() {
  const char html[] =
      ""
      "<title>WebView remote debugging</title>"
      "Please use chrome://inspect"
      ""
      "";
  return html;
}

// Factory for UnixDomainServerSocket.
class UnixDomainServerSocketFactory
    : public content::DevToolsHttpHandler::ServerSocketFactory {
 public:
  explicit UnixDomainServerSocketFactory(const std::string& socket_name)
      : content::DevToolsHttpHandler::ServerSocketFactory(socket_name, 0, 1) {}

 private:
  // content::DevToolsHttpHandler::ServerSocketFactory.
  virtual scoped_ptr<net::ServerSocket> Create() const override {
    return scoped_ptr<net::ServerSocket>(
        new net::UnixDomainServerSocket(
            base::Bind(&content::CanUserConnectToDevTools),
            true /* use_abstract_namespace */));
  }

  DISALLOW_COPY_AND_ASSIGN(UnixDomainServerSocketFactory);
};

}  // namespace

namespace android_webview {

AwDevToolsServer::AwDevToolsServer()
    : protocol_handler_(NULL) {
}

AwDevToolsServer::~AwDevToolsServer() {
  Stop();
}

void AwDevToolsServer::Start() {
  if (protocol_handler_)
    return;

  scoped_ptr<content::DevToolsHttpHandler::ServerSocketFactory> factory(
      new UnixDomainServerSocketFactory(
          base::StringPrintf(kSocketNameFormat, getpid())));
  protocol_handler_ = content::DevToolsHttpHandler::Start(
      factory.Pass(),
      base::StringPrintf(kFrontEndURL, content::GetWebKitRevision().c_str()),
      new AwDevToolsServerDelegate(),
      base::FilePath());
}

void AwDevToolsServer::Stop() {
  if (!protocol_handler_)
    return;
  // Note that the call to Stop() below takes care of |protocol_handler_|
  // deletion.
  protocol_handler_->Stop();
  protocol_handler_ = NULL;
}

bool AwDevToolsServer::IsStarted() const {
  return protocol_handler_;
}

bool RegisterAwDevToolsServer(JNIEnv* env) {
  return RegisterNativesImpl(env);
}

static jlong InitRemoteDebugging(JNIEnv* env,
                                jobject obj) {
  AwDevToolsServer* server = new AwDevToolsServer();
  return reinterpret_cast<intptr_t>(server);
}

static void DestroyRemoteDebugging(JNIEnv* env, jobject obj, jlong server) {
  delete reinterpret_cast<AwDevToolsServer*>(server);
}

static void SetRemoteDebuggingEnabled(JNIEnv* env,
                                      jobject obj,
                                      jlong server,
                                      jboolean enabled) {
  AwDevToolsServer* devtools_server =
      reinterpret_cast<AwDevToolsServer*>(server);
  if (enabled) {
    devtools_server->Start();
  } else {
    devtools_server->Stop();
  }
}

}  // namespace android_webview
<commit_msg>DevTools: Tethering in Android Webview<commit_after>// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "android_webview/native/aw_dev_tools_server.h"

#include "android_webview/native/aw_contents.h"
#include "base/bind.h"
#include "base/files/file_path.h"
#include "base/json/json_writer.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/values.h"
#include "content/public/browser/android/devtools_auth.h"
#include "content/public/browser/devtools_agent_host.h"
#include "content/public/browser/devtools_http_handler.h"
#include "content/public/browser/devtools_http_handler_delegate.h"
#include "content/public/browser/devtools_target.h"
#include "content/public/browser/web_contents.h"
#include "content/public/common/user_agent.h"
#include "jni/AwDevToolsServer_jni.h"
#include "net/base/net_errors.h"
#include "net/socket/unix_domain_server_socket_posix.h"

using content::DevToolsAgentHost;
using content::RenderViewHost;
using content::WebContents;

namespace {

const char kFrontEndURL[] =
    "http://chrome-devtools-frontend.appspot.com/serve_rev/%s/devtools.html";
const char kSocketNameFormat[] = "webview_devtools_remote_%d";
const char kTetheringSocketName[] = "webview_devtools_tethering_%d_%d";

const int kBackLog = 10;

// Delegate implementation for the devtools http handler for WebView. A new
// instance of this gets created each time web debugging is enabled.
class AwDevToolsServerDelegate : public content::DevToolsHttpHandlerDelegate {
 public:
  AwDevToolsServerDelegate() : last_tethering_socket_(0) {
  }

  virtual ~AwDevToolsServerDelegate() {}

  // DevToolsHttpProtocolHandler::Delegate overrides.
  std::string GetDiscoveryPageHTML() override;

  bool BundlesFrontendResources() override {
    return false;
  }

  base::FilePath GetDebugFrontendDir() override {
    return base::FilePath();
  }

  scoped_ptr<net::ServerSocket>
  CreateSocketForTethering(std::string* name) override {
    *name = base::StringPrintf(
        kTetheringSocketName, getpid(), ++last_tethering_socket_);
    scoped_ptr<net::UnixDomainServerSocket> socket(
        new net::UnixDomainServerSocket(
            base::Bind(&content::CanUserConnectToDevTools), true));
    if (socket->ListenWithAddressAndPort(*name, 0, kBackLog) != net::OK)
      return scoped_ptr<net::ServerSocket>();

    return socket.Pass();
  }

 private:
  int last_tethering_socket_;

  DISALLOW_COPY_AND_ASSIGN(AwDevToolsServerDelegate);
};

std::string AwDevToolsServerDelegate::GetDiscoveryPageHTML() {
  const char html[] =
      ""
      "<title>WebView remote debugging</title>"
      "Please use chrome://inspect"
      ""
      "";
  return html;
}

// Factory for UnixDomainServerSocket.
class UnixDomainServerSocketFactory
    : public content::DevToolsHttpHandler::ServerSocketFactory {
 public:
  explicit UnixDomainServerSocketFactory(const std::string& socket_name)
      : content::DevToolsHttpHandler::ServerSocketFactory(socket_name, 0, 1) {}

 private:
  // content::DevToolsHttpHandler::ServerSocketFactory.
  virtual scoped_ptr<net::ServerSocket> Create() const override {
    return scoped_ptr<net::ServerSocket>(
        new net::UnixDomainServerSocket(
            base::Bind(&content::CanUserConnectToDevTools),
            true /* use_abstract_namespace */));
  }

  DISALLOW_COPY_AND_ASSIGN(UnixDomainServerSocketFactory);
};

}  // namespace

namespace android_webview {

AwDevToolsServer::AwDevToolsServer()
    : protocol_handler_(NULL) {
}

AwDevToolsServer::~AwDevToolsServer() {
  Stop();
}

void AwDevToolsServer::Start() {
  if (protocol_handler_)
    return;

  scoped_ptr<content::DevToolsHttpHandler::ServerSocketFactory> factory(
      new UnixDomainServerSocketFactory(
          base::StringPrintf(kSocketNameFormat, getpid())));
  protocol_handler_ = content::DevToolsHttpHandler::Start(
      factory.Pass(),
      base::StringPrintf(kFrontEndURL, content::GetWebKitRevision().c_str()),
      new AwDevToolsServerDelegate(),
      base::FilePath());
}

void AwDevToolsServer::Stop() {
  if (!protocol_handler_)
    return;
  // Note that the call to Stop() below takes care of |protocol_handler_|
  // deletion.
  protocol_handler_->Stop();
  protocol_handler_ = NULL;
}

bool AwDevToolsServer::IsStarted() const {
  return protocol_handler_;
}

bool RegisterAwDevToolsServer(JNIEnv* env) {
  return RegisterNativesImpl(env);
}

static jlong InitRemoteDebugging(JNIEnv* env,
                                jobject obj) {
  AwDevToolsServer* server = new AwDevToolsServer();
  return reinterpret_cast<intptr_t>(server);
}

static void DestroyRemoteDebugging(JNIEnv* env, jobject obj, jlong server) {
  delete reinterpret_cast<AwDevToolsServer*>(server);
}

static void SetRemoteDebuggingEnabled(JNIEnv* env,
                                      jobject obj,
                                      jlong server,
                                      jboolean enabled) {
  AwDevToolsServer* devtools_server =
      reinterpret_cast<AwDevToolsServer*>(server);
  if (enabled) {
    devtools_server->Start();
  } else {
    devtools_server->Stop();
  }
}

}  // namespace android_webview
<|endoftext|>


<commit_before>#include "catch.hpp"
#include <functional>
#include <numeric>
#include <string>
#include <unordered_map>
#include <vector>

namespace {
  const auto nums = std::vector<int> { 1, 2, 3, 4, 5, 6 };
  const auto evens = std::vector<int> { 2, 4, 6 };
  const auto odds = std::vector<int> { 1, 3, 5 };
  const auto isOdd = [](const int num) { return num%2 != 0; };
  const auto manyOddNums = std::vector<int>{1, 3, 5, 7, 9, 11, 13, 15};
}

TEST_CASE("accumulate test", "[algos]") {
  SECTION("string concatenation") {
    auto sv = std::vector<std::string>{ "aa", "bb", "cc" };
    auto result = std::accumulate(sv.begin(), sv.end(), std::string(""));
    REQUIRE("aabbcc" == result);
  }

  SECTION("vector sum") {
    auto res = std::accumulate(nums.begin(), nums.end(), 0,
      [](int acc, int val) { return acc + 2 * val; });
    REQUIRE(res == 42);
  }
}

TEST_CASE("adjacent find test", "[algos]") {
  const auto vec1 = std::vector<int> { 1, 2, 3, 5, 7 };
  const auto vec2 = std::vector<int> { 1, 2, 3, 4, 5 };
  const auto comp = [](const int v1, const int v2)->bool {
    return v2 - v1 == 2;
  };

  SECTION("verifying iterators") {
    auto it1 = std::adjacent_find(vec1.begin(), vec1.end(), comp);
    auto it2 = std::next(vec1.begin(), 2);
    REQUIRE(it1 == it2);
  }

  SECTION("verifying value") {
    auto it1 = std::adjacent_find(vec1.begin(), vec1.end(), comp);
    REQUIRE(*it1 == 3);
  }

  SECTION("verifying failed find") {
    auto it2 = std::adjacent_find(vec2.begin(), vec2.end(), comp);
    REQUIRE(it2 == vec2.end());
  }
}

TEST_CASE("advance test", "[algos]") {
  auto it = nums.begin();
  std::advance(it, 3);
  REQUIRE(*it == 4);
}

TEST_CASE("backward find_if test", "[algos]") {
  SECTION("successful search case") {
    const auto it = std::find_if(nums.rbegin(), nums.rend(), [](int n) { return n%2 == 0; });
    REQUIRE(it == nums.rbegin());
  }

  SECTION("failed search case") {
    const auto it = std::find_if(nums.rbegin(), nums.rend(), [](int n) { return n%2 < 0; });
    REQUIRE(it == nums.rend());
  }
}

TEST_CASE("copy_if test", "[algos]") {
  auto numsCopy = std::vector<int> { 1, 2, 3, 4, 5, 6 };
  auto res = std::vector<int>{};
  std::copy_if(numsCopy.begin(), numsCopy.end(), std::back_inserter(res), isOdd);
  REQUIRE(res == odds);
}

TEST_CASE("distance test", "[algos]") {
  auto it = std::find(nums.begin(), nums.end(), 3);

  SECTION("comparing iterator distances") {
    REQUIRE(std::distance(nums.begin(), it) == (it - nums.begin()));
  }

  SECTION("verifying absolute distance") {
    REQUIRE(it - nums.begin() == 2);
  }

  SECTION("verifying value at distance") {
    REQUIRE(nums[it - nums.begin()] == 3);
  }
}

TEST_CASE("erase test", "[algos]") {
  auto numsCopy = std::vector<int>{ nums };
  numsCopy.erase(numsCopy.begin() + 1, numsCopy.end());
  REQUIRE(numsCopy == std::vector<int>{1});
}

TEST_CASE("insert test", "[algos]") {
  const auto src1 = std::vector<int>{1, 2};
  const auto src2 = std::vector<int>{3, 4, 5};

  SECTION("comparing begin and end of empty vector") {
    auto dst = std::vector<int>{};
    REQUIRE(dst.begin() == dst.end());
  }

  SECTION("successful insertion into empty vector") {
    auto dst = std::vector<int>{};
    dst.insert(dst.end(), src1.begin(), src1.end());
    REQUIRE(*std::prev(dst.end()) == 2);
  }

  SECTION("successful insertion into non-empty vector") {
    auto dst = std::vector<int>{};
    dst.insert(dst.end(), src1.begin(), src1.end());
    dst.insert(dst.end(), src2.begin(), src2.end());
    auto it1 = std::next(dst.begin(), src1.size());
    REQUIRE(*it1 == 3);
  }
}

TEST_CASE("lower bound test", "[algos]") {
  auto it1 = std::lower_bound(manyOddNums.begin(), manyOddNums.end(), 9,
    [](int val, int num) { return val <= num; });

  auto it2 = std::lower_bound(manyOddNums.begin(), manyOddNums.end(), 10,
    [](int val, int num) { return val <= num; });

  SECTION("iterator comparison") {
    REQUIRE(it1 == it2);
  }

  SECTION("correct value found") {
    REQUIRE(*it1 == 11);
  }
}

TEST_CASE("max of range test", "[algos]") {
  const auto val = std::max({1, 2, 3, 4, 5});
  REQUIRE(val == 5);
}

TEST_CASE("move to empty vector test", "[algos]") {
  auto copy1 = std::vector<int>{ nums };
  auto copy2 = std::vector<int>{};
  copy2 = std::move(copy1);
  REQUIRE(copy2 == nums);
}

TEST_CASE("move to non-empty vector test", "[algos]") {
  auto copy1 = std::vector<int>{ nums };
  auto copy2 = std::vector<int>{ 0, 0 };
  auto res = std::vector<int>{ 0, 0, 1, 2, 3, 4, 5, 6 };
  std::move(copy1.begin(), copy1.end(), std::back_inserter(copy2));
  REQUIRE(copy2 == res);
}

TEST_CASE("prev test", "[algos]") {
  auto vec = std::vector<int>{1};

  SECTION("prev works correctly") {
    REQUIRE(vec.begin() == std::prev(vec.end()));
  }

  SECTION("next works correctly") {
    REQUIRE(std::next(vec.begin()) == vec.end());
  }
}

TEST_CASE("remove copy if test", "[algos]") {
  std::vector<int> dst;
  auto res = std::vector<int>{2, 4, 6};
  std::remove_copy_if(nums.begin(), nums.end(), std::back_inserter(dst),
    isOdd);

  REQUIRE(dst == res);
}

TEST_CASE("remove_if test", "[algos]") {
  auto numsCopy = std::vector<int>{ nums };
  numsCopy.erase(std::remove_if(numsCopy.begin(), numsCopy.end(), isOdd),
    numsCopy.end());
  REQUIRE(numsCopy == evens);
}

TEST_CASE("set copy_if test", "[algos]") {
  auto set1 = std::set<int>{ 1, 2, 4, 6 };
  auto res = std::set<int>(nums.begin(), nums.end());
  std::copy_if(nums.begin(), nums.end(), std::inserter(set1, set1.begin()), isOdd);
  REQUIRE(set1 == res);
}

TEST_CASE("set difference test", "[algos]") {
  auto set1 = std::set<int>{ 3, 2, 1 };
  auto set2 = std::set<int>{ 2, 4, 5, 3 };
  auto setDiff = std::vector<int>(set1.size() + set2.size());
  auto it = set_difference(set2.begin(), set2.end(), set1.begin(), set1.end(), setDiff.begin());
  setDiff.resize(it - setDiff.begin());
  auto res = std::vector<int>{ 4, 5 };
  REQUIRE(setDiff == res);
}

TEST_CASE("set insertion test", "[algos]") {
  auto set1 = std::set<int>{ 1, 2, 4 };
  auto res = std::set<int>{ nums.begin(), nums.end() };
  set1.insert(nums.begin(), nums.end());
  REQUIRE(set1 == res);
}

TEST_CASE("set intersection test", "[algos]") {
  auto set1 = std::set<int>{ 3, 2, 1 };
  auto set2 = std::set<int>{ 2, 4, 5, 3 };
  auto inter = std::vector<int>(set1.size() + set2.size());
  auto it = set_intersection(set1.begin(), set1.end(), set2.begin(), set2.end(), inter.begin());
  inter.resize(it - inter.begin());
  std::vector<int> res = { 2, 3 };
  REQUIRE(inter == res);
}

TEST_CASE("sort test", "[algos]") {
  auto numsCopy = std::vector<int>{nums};
  auto orderedRes = std::vector<int>{ 1, 3, 5, 2, 4, 6 };
  auto comparator = [](int i, int j) {
    const bool iOdd = i%2 != 0;
    const bool jOdd = j%2 != 0;

    if(iOdd) {
      if(jOdd)
        return false;
      return true;
    }

    return false;
  };
  std::sort(numsCopy.begin(), numsCopy.end(), comparator);
  REQUIRE(numsCopy == orderedRes);
}

TEST_CASE("stable partition test", "[algos]") {
  auto numsCopy = std::vector<int>{nums};
  auto oddNums = std::vector<int>{};
  auto res = std::vector<int>{ 1, 3, 5, 2, 4, 6 };
  auto it = std::stable_partition(numsCopy.begin(), numsCopy.end(), isOdd);
  oddNums.insert(oddNums.end(), numsCopy.begin(), it);
  REQUIRE(numsCopy == res);
  REQUIRE(oddNums == odds);
}

TEST_CASE("transform test", "[algos]") {
  auto twiceNums = std::vector<int>(nums.size());
  auto res = std::vector<int>{ 2, 4, 6, 8, 10, 12 };
  std::transform(nums.begin(), nums.end(), twiceNums.begin(), [](int a) { return a*2; });
  REQUIRE(twiceNums == res);
}

TEST_CASE("unordered map test", "[algos]") {
  auto someMap = std::unordered_map<int, std::vector<char>>{};

  someMap[1].push_back('a');
  REQUIRE(someMap.count(1) == 1);

  someMap[1].push_back('b');
  REQUIRE(someMap[1].size() == 2);

  someMap[2].push_back('c');
  REQUIRE(someMap.count(2) == 1);
  REQUIRE(someMap[2].size() == 1);
  REQUIRE(someMap.size() == 2);
}
<commit_msg>added test to understand upper bound<commit_after>#include "catch.hpp"
#include <functional>
#include <numeric>
#include <string>
#include <unordered_map>
#include <vector>

namespace {
    const auto nums = std::vector<int> { 1, 2, 3, 4, 5, 6 };
    const auto evens = std::vector<int> { 2, 4, 6 };
    const auto odds = std::vector<int> { 1, 3, 5 };
    const auto isOdd = [](const int num) { return num%2 != 0; };
}

TEST_CASE("accumulate test", "[algos]") {
    SECTION("string concatenation") {
        auto sv = std::vector<std::string>{ "aa", "bb", "cc" };
        auto result = std::accumulate(sv.begin(), sv.end(), std::string(""));
        REQUIRE("aabbcc" == result);
    }

    SECTION("vector sum") {
        auto res = std::accumulate(nums.begin(), nums.end(), 0,
                [](int acc, int val) { return acc + 2 * val; });
        REQUIRE(res == 42);
    }
}

TEST_CASE("adjacent find test", "[algos]") {
    const auto vec1 = std::vector<int> { 1, 2, 3, 5, 7 };
    const auto vec2 = std::vector<int> { 1, 2, 3, 4, 5 };
    const auto comp = [](const int v1, const int v2)->bool {
        return v2 - v1 == 2;
    };

    SECTION("verifying iterators") {
        auto it1 = std::adjacent_find(vec1.begin(), vec1.end(), comp);
        auto it2 = std::next(vec1.begin(), 2);
        REQUIRE(it1 == it2);
    }

    SECTION("verifying value") {
        auto it1 = std::adjacent_find(vec1.begin(), vec1.end(), comp);
        REQUIRE(*it1 == 3);
    }

    SECTION("verifying failed find") {
        auto it2 = std::adjacent_find(vec2.begin(), vec2.end(), comp);
        REQUIRE(it2 == vec2.end());
    }
}

TEST_CASE("advance test", "[algos]") {
    auto it = nums.begin();
    std::advance(it, 3);
    REQUIRE(*it == 4);
}

TEST_CASE("backward find_if test", "[algos]") {
    SECTION("successful search case") {
        const auto it = std::find_if(nums.rbegin(), nums.rend(), [](int n) { return n%2 == 0; });
        REQUIRE(it == nums.rbegin());
    }

    SECTION("failed search case") {
        const auto it = std::find_if(nums.rbegin(), nums.rend(), [](int n) { return n%2 < 0; });
        REQUIRE(it == nums.rend());
    }
}

TEST_CASE("copy_if test", "[algos]") {
    auto numsCopy = std::vector<int> { 1, 2, 3, 4, 5, 6 };
    auto res = std::vector<int>{};
    std::copy_if(numsCopy.begin(), numsCopy.end(), std::back_inserter(res), isOdd);
    REQUIRE(res == odds);
}

TEST_CASE("distance test", "[algos]") {
    auto it = std::find(nums.begin(), nums.end(), 3);

    SECTION("comparing iterator distances") {
        REQUIRE(std::distance(nums.begin(), it) == (it - nums.begin()));
    }

    SECTION("verifying absolute distance") {
        REQUIRE(it - nums.begin() == 2);
    }

    SECTION("verifying value at distance") {
        REQUIRE(nums[it - nums.begin()] == 3);
    }
}

TEST_CASE("erase test", "[algos]") {
    auto numsCopy = std::vector<int>{ nums };
    numsCopy.erase(numsCopy.begin() + 1, numsCopy.end());
    REQUIRE(numsCopy == std::vector<int>{1});
}

TEST_CASE("insert test", "[algos]") {
    const auto src1 = std::vector<int>{1, 2};
    const auto src2 = std::vector<int>{3, 4, 5};

    SECTION("comparing begin and end of empty vector") {
        auto dst = std::vector<int>{};
        REQUIRE(dst.begin() == dst.end());
    }

    SECTION("successful insertion into empty vector") {
        auto dst = std::vector<int>{};
        dst.insert(dst.end(), src1.begin(), src1.end());
        REQUIRE(*std::prev(dst.end()) == 2);
    }

    SECTION("successful insertion into non-empty vector") {
        auto dst = std::vector<int>{};
        dst.insert(dst.end(), src1.begin(), src1.end());
        dst.insert(dst.end(), src2.begin(), src2.end());
        auto it1 = std::next(dst.begin(), src1.size());
        REQUIRE(*it1 == 3);
    }
}

TEST_CASE("lower bound test", "[algos]") {
    const auto manyOddNums = std::vector<int>{1, 3, 5, 7, 9, 11, 13, 15};

    SECTION("iterator comparison") {
        auto it = std::lower_bound(manyOddNums.begin(), manyOddNums.end(), 9,
            std::less_equal<int>());
        REQUIRE(*it == 11);
    }

    SECTION("correct value found") {
        auto it = std::lower_bound(manyOddNums.begin(), manyOddNums.end(), 10,
            std::less_equal<int>());
        REQUIRE(*it == 11);
    }

    SECTION("successful reverse search") {
        auto it = std::upper_bound(manyOddNums.rbegin(), manyOddNums.rend(), 9,
            std::greater<int>());
        REQUIRE(*it == 7);
    }
}

TEST_CASE("upper bound test", "[algos]") {
    const auto manyOddNums = std::vector<int>{1, 3, 5, 7, 9, 11, 13, 15};

    SECTION("reverse upper bound search") {
        auto it = std::upper_bound(manyOddNums.rbegin(), manyOddNums.rend(), 9,
            std::greater<int>());
        REQUIRE(*it == 7);
    }
}

TEST_CASE("max of range test", "[algos]") {
    const auto val = std::max({1, 2, 3, 4, 5});
    REQUIRE(val == 5);
}

TEST_CASE("move to empty vector test", "[algos]") {
    auto copy1 = std::vector<int>{ nums };
    auto copy2 = std::vector<int>{};
    copy2 = std::move(copy1);
    REQUIRE(copy2 == nums);
}

TEST_CASE("move to non-empty vector test", "[algos]") {
    auto copy1 = std::vector<int>{ nums };
    auto copy2 = std::vector<int>{ 0, 0 };
    auto res = std::vector<int>{ 0, 0, 1, 2, 3, 4, 5, 6 };
    std::move(copy1.begin(), copy1.end(), std::back_inserter(copy2));
    REQUIRE(copy2 == res);
}

TEST_CASE("prev test", "[algos]") {
    auto vec = std::vector<int>{1};

    SECTION("prev works correctly") {
        REQUIRE(vec.begin() == std::prev(vec.end()));
    }

    SECTION("next works correctly") {
        REQUIRE(std::next(vec.begin()) == vec.end());
    }
}

TEST_CASE("remove copy if test", "[algos]") {
    std::vector<int> dst;
    auto res = std::vector<int>{2, 4, 6};
    std::remove_copy_if(nums.begin(), nums.end(), std::back_inserter(dst),
            isOdd);

    REQUIRE(dst == res);
}

TEST_CASE("remove_if test", "[algos]") {
    auto numsCopy = std::vector<int>{ nums };
    numsCopy.erase(std::remove_if(numsCopy.begin(), numsCopy.end(), isOdd),
            numsCopy.end());
    REQUIRE(numsCopy == evens);
}

TEST_CASE("set copy_if test", "[algos]") {
    auto set1 = std::set<int>{ 1, 2, 4, 6 };
    auto res = std::set<int>(nums.begin(), nums.end());
    std::copy_if(nums.begin(), nums.end(), std::inserter(set1, set1.begin()), isOdd);
    REQUIRE(set1 == res);
}

TEST_CASE("set difference test", "[algos]") {
    auto set1 = std::set<int>{ 3, 2, 1 };
    auto set2 = std::set<int>{ 2, 4, 5, 3 };
    auto setDiff = std::vector<int>(set1.size() + set2.size());
    auto it = set_difference(set2.begin(), set2.end(), set1.begin(), set1.end(), setDiff.begin());
    setDiff.resize(it - setDiff.begin());
    auto res = std::vector<int>{ 4, 5 };
    REQUIRE(setDiff == res);
}

TEST_CASE("set insertion test", "[algos]") {
    auto set1 = std::set<int>{ 1, 2, 4 };
    auto res = std::set<int>{ nums.begin(), nums.end() };
    set1.insert(nums.begin(), nums.end());
    REQUIRE(set1 == res);
}

TEST_CASE("set intersection test", "[algos]") {
    auto set1 = std::set<int>{ 3, 2, 1 };
    auto set2 = std::set<int>{ 2, 4, 5, 3 };
    auto inter = std::vector<int>(set1.size() + set2.size());
    auto it = set_intersection(set1.begin(), set1.end(), set2.begin(), set2.end(), inter.begin());
    inter.resize(it - inter.begin());
    std::vector<int> res = { 2, 3 };
    REQUIRE(inter == res);
}

TEST_CASE("sort test", "[algos]") {
    auto numsCopy = std::vector<int>{nums};
    auto orderedRes = std::vector<int>{ 1, 3, 5, 2, 4, 6 };
    auto comparator = [](int i, int j) {
        const bool iOdd = i%2 != 0;
        const bool jOdd = j%2 != 0;

        if(iOdd) {
            if(jOdd)
                return false;
            return true;
        }

        return false;
    };
    std::sort(numsCopy.begin(), numsCopy.end(), comparator);
    REQUIRE(numsCopy == orderedRes);
}

TEST_CASE("stable partition test", "[algos]") {
    auto numsCopy = std::vector<int>{nums};
    auto oddNums = std::vector<int>{};
    auto res = std::vector<int>{ 1, 3, 5, 2, 4, 6 };
    auto it = std::stable_partition(numsCopy.begin(), numsCopy.end(), isOdd);
    oddNums.insert(oddNums.end(), numsCopy.begin(), it);
    REQUIRE(numsCopy == res);
    REQUIRE(oddNums == odds);
}

TEST_CASE("transform test", "[algos]") {
    auto twiceNums = std::vector<int>(nums.size());
    auto res = std::vector<int>{ 2, 4, 6, 8, 10, 12 };
    std::transform(nums.begin(), nums.end(), twiceNums.begin(), [](int a) { return a*2; });
    REQUIRE(twiceNums == res);
}

TEST_CASE("unordered map test", "[algos]") {
    auto someMap = std::unordered_map<int, std::vector<char>>{};

    someMap[1].push_back('a');
    REQUIRE(someMap.count(1) == 1);

    someMap[1].push_back('b');
    REQUIRE(someMap[1].size() == 2);

    someMap[2].push_back('c');
    REQUIRE(someMap.count(2) == 1);
    REQUIRE(someMap[2].size() == 1);
    REQUIRE(someMap.size() == 2);
}
<|endoftext|>


<commit_before>/** \file   Main.cc
 *  \brief  Default main entry point.
 *  \author Dr. Johannes Ruscheinski (johannes.ruscheinski@uni-tuebingen.de)
 *
 *  \copyright 2018 Universitätsbibliothek Tübingen.  All rights reserved.
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Affero General Public License as
 *  published by the Free Software Foundation, either version 3 of the
 *  License, or (at your option) any later version.
 *
 *  This program 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 Affero General Public License for more details.
 *
 *  You should have received a copy of the GNU Affero General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
#include <stdexcept>
#include <string>
#include <cstdlib>
#include "StringUtil.h"
#include "util.h"

int Main(int argc, char *argv[]);

int main(int argc, char *argv[]) __attribute__((weak));

int main(int argc, char *argv[]) {
    ::progname = argv[0];

    Logger::LogLevel log_level(Logger::LL_WARNING);
    if (argc > 1 and StringUtil::StartsWith(argv[1], "--verbosity=")) {
        const std::string level(argv[1] + __builtin_strlen("--verbosity="));
        if (level == "ERROR")
            log_level = Logger::LL_ERROR;
        else if (level == "WARNING")
            log_level = Logger::LL_WARNING;
        else if (level == "INFO")
            log_level = Logger::LL_INFO;
        else if (level == "DEBUG")
            log_level = Logger::LL_DEBUG;
        else
            LOG_ERROR("unknown log level \"" + level + "\"!");
        --argc, ++argv;
    }
    logger->setMinimumLogLevel(log_level);

    try {
        return Main(argc, argv);
    } catch (const std::exception &x) {
        LOG_ERROR("caught exception: " + std::string(x.what()));
    }
}

<commit_msg>Changed the log level speicification flag from --verbosity to --min-log-level.<commit_after>/** \file   Main.cc
 *  \brief  Default main entry point.
 *  \author Dr. Johannes Ruscheinski (johannes.ruscheinski@uni-tuebingen.de)
 *
 *  \copyright 2018 Universitätsbibliothek Tübingen.  All rights reserved.
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Affero General Public License as
 *  published by the Free Software Foundation, either version 3 of the
 *  License, or (at your option) any later version.
 *
 *  This program 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 Affero General Public License for more details.
 *
 *  You should have received a copy of the GNU Affero General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
#include <stdexcept>
#include <string>
#include <cstdlib>
#include "StringUtil.h"
#include "util.h"

int Main(int argc, char *argv[]);

int main(int argc, char *argv[]) __attribute__((weak));

int main(int argc, char *argv[]) {
    ::progname = argv[0];

    Logger::LogLevel log_level(Logger::LL_WARNING);
    if (argc > 1 and StringUtil::StartsWith(argv[1], "--min-log-level=")) {
        const std::string level(argv[1] + __builtin_strlen("--min-log-level="));
        if (level == "ERROR")
            log_level = Logger::LL_ERROR;
        else if (level == "WARNING")
            log_level = Logger::LL_WARNING;
        else if (level == "INFO")
            log_level = Logger::LL_INFO;
        else if (level == "DEBUG")
            log_level = Logger::LL_DEBUG;
        else
            LOG_ERROR("unknown log level \"" + level + "\"!");
        --argc, ++argv;
    }
    logger->setMinimumLogLevel(log_level);

    try {
        return Main(argc, argv);
    } catch (const std::exception &x) {
        LOG_ERROR("caught exception: " + std::string(x.what()));
    }
}

<|endoftext|>


<commit_before>/** \file    util.cc
 *  \brief   Implementation of various utility functions.
 *  \author  Dr. Johannes Ruscheinski
 */

/*
    Copyright (C) 2015,2017,2018 Library of the University of Tübingen

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as
    published by the Free Software Foundation, either version 3 of the
    License, or (at your option) any later version.

    This program 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 Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
#include "util.h"
#include <iostream>
#include <iterator>
#include <stdexcept>
#include <cctype>
#include <cstdlib>
#include <execinfo.h>
#include <signal.h>
#include "Compiler.h"
#include "MiscUtil.h"
#include "TimeUtil.h"

// Macro to determine the number of entries in a one-dimensional array:
#define DIM(array) (sizeof(array) / sizeof(array[0]))

char *progname; // Must be set in main() with "progname = argv[0];";

Logger::Logger()
    : fd_(STDERR_FILENO), log_process_pids_(false), log_no_decorations_(false), log_strip_call_site_(false),
      min_log_level_(LL_INFO)
{
    const char * const min_log_level(::getenv("MIN_LOG_LEVEL"));
    if (min_log_level != nullptr)
        min_log_level_ = Logger::StringToLogLevel(min_log_level);
    const char * const logger_format(::getenv("LOGGER_FORMAT"));
    if (logger_format != nullptr) {
        if (std::strstr(logger_format, "process_pids") != nullptr)
            log_process_pids_ = true;
        if (std::strstr(logger_format, "no_decorations") != nullptr)
            log_no_decorations_ = true;
        if (std::strstr(logger_format, "strip_call_site") != nullptr)
            log_strip_call_site_ = true;
    }
}

void Logger::error(const std::string &msg) {
    std::lock_guard<std::mutex> mutex_locker(mutex_);

    std::string error_message_string;
    if (errno != 0)
        error_message_string = " (" + std::string(std::strerror(errno)) + ")";

    writeString("SEVERE", msg + error_message_string);
    if (::getenv("BACKTRACE") != nullptr) {
        const bool saved_log_no_decorations(log_no_decorations_);
        log_no_decorations_ = true;
        writeString("", "Backtrace:");
        for (const auto &stack_entry : MiscUtil::GetCallStack())
            writeString("", "  " + stack_entry);
        log_no_decorations_ = saved_log_no_decorations;
    }

    std::exit(EXIT_FAILURE);
}

void Logger::warning(const std::string &msg) {
    if (min_log_level_ < LL_WARNING)
        return;

    std::lock_guard<std::mutex> mutex_locker(mutex_);
    writeString("WARN", msg);
}

void Logger::info(const std::string &msg) {
    if (min_log_level_ < LL_INFO)
        return;

    std::lock_guard<std::mutex> mutex_locker(mutex_);
    writeString("INFO", msg);
}

void Logger::debug(const std::string &msg) {
    if ((min_log_level_ < LL_DEBUG) and (MiscUtil::SafeGetEnv("UTIL_LOG_DEBUG") != "true"))
        return;

    std::lock_guard<std::mutex> mutex_locker(mutex_);
    writeString("DEBUG", msg);
}

inline Logger *LoggerInstantiator() {
    return new Logger();
}

Logger *logger(LoggerInstantiator());

Logger::LogLevel Logger::StringToLogLevel(const std::string &level_candidate) {
    if (level_candidate == "ERROR")
        return Logger::LL_ERROR;
    if (level_candidate == "WARNING")
        return Logger::LL_WARNING;
    if (level_candidate == "INFO")
        return Logger::LL_INFO;
    if (level_candidate == "DEBUG")
        return Logger::LL_DEBUG;
    LOG_ERROR("not a valid minimum log level: \"" + level_candidate + "\"! (Use ERROR, WARNING, INFO or DEBUG)");
}

std::string Logger::LogLevelToString(const LogLevel log_level) {
    if (log_level == Logger::LL_ERROR)
        return "ERROR";
    if (log_level == Logger::LL_WARNING)
        return "WARNING";
    if (log_level == Logger::LL_INFO)
        return "INFO";
    if (log_level == Logger::LL_DEBUG)
        return "DEBUG";
    LOG_ERROR("unsupported log level, we should *never* get here!");
}

void Logger::writeString(const std::string &level, std::string msg) {
    if (unlikely(::progname == nullptr))
        msg = "You must set \"progname\" in main() with \"::progname = argv[0];\" in oder to use the Logger API!";
    else if (not log_no_decorations_) {
        msg = TimeUtil::GetCurrentDateAndTime(TimeUtil::ISO_8601_FORMAT) + " " + level + " " + std::string(::progname) + ": "
              + msg;
        if (log_process_pids_)
            msg += " (PID: " + std::to_string(::getpid()) + ")";
    }

    if (log_strip_call_site_) {
        const auto END_OF_CALL_SITE_PREFIX(msg.find("): "));
        if (END_OF_CALL_SITE_PREFIX != std::string::npos)
            msg = msg.substr(END_OF_CALL_SITE_PREFIX + 3);
    }

    msg += '\n';

    if (unlikely(::write(fd_, reinterpret_cast<const void *>(msg.data()), msg.size()) == -1)) {
        const std::string error_message("in Logger::writeString(util.cc): write to file descriptor " + std::to_string(fd_)
                                        + " failed! (errno = " + std::to_string(errno) + ")");
        #pragma GCC diagnostic ignored "-Wunused-result"
        ::write(STDERR_FILENO, error_message.data(), error_message.size());
        #pragma GCC diagnostic warning "-Wunused-result"
        _exit(EXIT_FAILURE);
    }

    if (unlikely(::progname == nullptr))
        _exit(EXIT_FAILURE);
}

DSVReader::DSVReader(const std::string &filename, const char field_separator, const char field_delimiter)
    : field_separator_(field_separator), field_delimiter_(field_delimiter), line_no_(0), filename_(filename)
{
    input_ = std::fopen(filename.c_str(), "rm");
    if (input_ == nullptr)
        throw std::runtime_error("in DSVReader::DSVReader: can't open \"" + filename + "\" for reading!");
}

DSVReader::~DSVReader() {
    if (input_ != nullptr)
        std::fclose(input_);
}

namespace {

void SkipFieldPadding(FILE * const input) {
    int ch = std::fgetc(input);
    while (isblank(ch))
        ch = std::fgetc(input);
    std::ungetc(ch, input);
}

/** \brief Remove trailing spaces and tabs from "s". */
std::string TrimBlanks(std::string * s) {
    std::string::const_reverse_iterator it(s->crbegin());
    for (/* Empty! */; it != s->crend() and std::isblank(*it); ++it)
        /* Intentionally Empty! */;
    if (it != s->crbegin())
        *s = s->substr(0, std::distance(it, s->crend()));

    return *s;
}

std::string ReadQuotedValue(FILE * const input, const char field_delimiter, const char field_separator) {
    std::string value;
    bool delimiter_seen(false);
    for (;;) {
        const int ch(std::fgetc(input));
        if (ch == EOF)
            throw std::runtime_error("unexpected EOF while reading a quoted DSV value!");
        if (ch == field_delimiter) {
            if (delimiter_seen) {
                // ignore if it's not the outermost delimiter
                const int next(std::fgetc(input));
                std::ungetc(next, input);

                if (next == field_separator or next == '\n' or next == EOF)
                    return value;
            } else
                delimiter_seen = true;
        } else {
            if (ch == '\n' or ch == EOF) {
                std::ungetc(ch, input);
                return TrimBlanks(&value);
            }
            value += static_cast<char>(ch);
        }
    }
}

std::string ReadNonQuotedValue(FILE * const input, const char field_separator) {
    std::string value;
    for (;;) {
        const int ch(std::fgetc(input));
        if (ch == EOF or ch == '\n' or ch == field_separator) {
            std::ungetc(ch, input);
            return TrimBlanks(&value);
        }
        value += static_cast<char>(ch);
    }
}

void BacktraceSignalHandler(int signal_no) {
    void *stack_return_addresses[20];
    const size_t number_of_addresses(::backtrace(stack_return_addresses, DIM(stack_return_addresses)));
    char err_msg[1024] = "Caught signal ";
    char *cp = err_msg + std::strlen(err_msg);
    if (signal_no > 10)
        *cp++ = '0' + (signal_no / 10);
    *cp++ = '0' + (signal_no % 10);
    *cp++ = '.';
    *cp++ = '\n';
    *cp = '\0';
    ssize_t unused(::write(STDERR_FILENO, err_msg, std::strlen(err_msg)));
    (void)unused;
    ::backtrace_symbols_fd(stack_return_addresses, number_of_addresses, STDERR_FILENO);
    ::_exit(EXIT_FAILURE);
}

int InstallSegvSignalHandler(void handler(int)) {
    ::signal(SIGSEGV, handler);
    return 0;
}

volatile int dummy = InstallSegvSignalHandler(BacktraceSignalHandler);

} // unnamed namespace

bool DSVReader::readLine(std::vector<std::string> * const values) {
    values->clear();
    ++line_no_;

    int ch;
    for (;;) {
        if (not values->empty()) {
            SkipFieldPadding(input_);
            ch = std::fgetc(input_);
            if (ch == EOF)
                return not values->empty();
            if (ch == '\n')
                return true;
            if (ch != field_separator_)
                throw std::runtime_error("in DSVReader::readLine: on line " + std::to_string(line_no_)
                                         + ": field separator expected, found '"
                                         + std::string(1, static_cast<char>(ch)) + "' instead!");
        }

        SkipFieldPadding(input_);
        ch = std::fgetc(input_);
        if (ch == '\n')
            return true;
        if (ch == EOF)
            return not values->empty();
        if (ch == field_separator_) {
            std::ungetc(ch, input_);
            values->emplace_back("");
        } else if (ch == field_delimiter_) {
            std::ungetc(ch, input_);
            values->emplace_back(ReadQuotedValue(input_, field_delimiter_, field_separator_));
        } else {
            std::ungetc(ch, input_);
            values->emplace_back(ReadNonQuotedValue(input_, field_separator_));
        }
    }
}

[[noreturn]] void Usage(const std::string &usage_message) {
    std::cerr << "Usage: " << ::progname << " [--min-log-level] " << usage_message << '\n';
    std::exit(EXIT_FAILURE);
}
<commit_msg>Added formmating for usage messages.<commit_after>/** \file    util.cc
 *  \brief   Implementation of various utility functions.
 *  \author  Dr. Johannes Ruscheinski
 */

/*
    Copyright (C) 2015,2017,2018 Library of the University of Tübingen

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as
    published by the Free Software Foundation, either version 3 of the
    License, or (at your option) any later version.

    This program 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 Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
#include "util.h"
#include <iostream>
#include <iterator>
#include <stdexcept>
#include <cctype>
#include <cstdlib>
#include <execinfo.h>
#include <signal.h>
#include "Compiler.h"
#include "MiscUtil.h"
#include "StringUtil.h"
#include "TimeUtil.h"

// Macro to determine the number of entries in a one-dimensional array:
#define DIM(array) (sizeof(array) / sizeof(array[0]))

char *progname; // Must be set in main() with "progname = argv[0];";

Logger::Logger()
    : fd_(STDERR_FILENO), log_process_pids_(false), log_no_decorations_(false), log_strip_call_site_(false),
      min_log_level_(LL_INFO)
{
    const char * const min_log_level(::getenv("MIN_LOG_LEVEL"));
    if (min_log_level != nullptr)
        min_log_level_ = Logger::StringToLogLevel(min_log_level);
    const char * const logger_format(::getenv("LOGGER_FORMAT"));
    if (logger_format != nullptr) {
        if (std::strstr(logger_format, "process_pids") != nullptr)
            log_process_pids_ = true;
        if (std::strstr(logger_format, "no_decorations") != nullptr)
            log_no_decorations_ = true;
        if (std::strstr(logger_format, "strip_call_site") != nullptr)
            log_strip_call_site_ = true;
    }
}

void Logger::error(const std::string &msg) {
    std::lock_guard<std::mutex> mutex_locker(mutex_);

    std::string error_message_string;
    if (errno != 0)
        error_message_string = " (" + std::string(std::strerror(errno)) + ")";

    writeString("SEVERE", msg + error_message_string);
    if (::getenv("BACKTRACE") != nullptr) {
        const bool saved_log_no_decorations(log_no_decorations_);
        log_no_decorations_ = true;
        writeString("", "Backtrace:");
        for (const auto &stack_entry : MiscUtil::GetCallStack())
            writeString("", "  " + stack_entry);
        log_no_decorations_ = saved_log_no_decorations;
    }

    std::exit(EXIT_FAILURE);
}

void Logger::warning(const std::string &msg) {
    if (min_log_level_ < LL_WARNING)
        return;

    std::lock_guard<std::mutex> mutex_locker(mutex_);
    writeString("WARN", msg);
}

void Logger::info(const std::string &msg) {
    if (min_log_level_ < LL_INFO)
        return;

    std::lock_guard<std::mutex> mutex_locker(mutex_);
    writeString("INFO", msg);
}

void Logger::debug(const std::string &msg) {
    if ((min_log_level_ < LL_DEBUG) and (MiscUtil::SafeGetEnv("UTIL_LOG_DEBUG") != "true"))
        return;

    std::lock_guard<std::mutex> mutex_locker(mutex_);
    writeString("DEBUG", msg);
}

inline Logger *LoggerInstantiator() {
    return new Logger();
}

Logger *logger(LoggerInstantiator());

Logger::LogLevel Logger::StringToLogLevel(const std::string &level_candidate) {
    if (level_candidate == "ERROR")
        return Logger::LL_ERROR;
    if (level_candidate == "WARNING")
        return Logger::LL_WARNING;
    if (level_candidate == "INFO")
        return Logger::LL_INFO;
    if (level_candidate == "DEBUG")
        return Logger::LL_DEBUG;
    LOG_ERROR("not a valid minimum log level: \"" + level_candidate + "\"! (Use ERROR, WARNING, INFO or DEBUG)");
}

std::string Logger::LogLevelToString(const LogLevel log_level) {
    if (log_level == Logger::LL_ERROR)
        return "ERROR";
    if (log_level == Logger::LL_WARNING)
        return "WARNING";
    if (log_level == Logger::LL_INFO)
        return "INFO";
    if (log_level == Logger::LL_DEBUG)
        return "DEBUG";
    LOG_ERROR("unsupported log level, we should *never* get here!");
}

void Logger::writeString(const std::string &level, std::string msg) {
    if (unlikely(::progname == nullptr))
        msg = "You must set \"progname\" in main() with \"::progname = argv[0];\" in oder to use the Logger API!";
    else if (not log_no_decorations_) {
        msg = TimeUtil::GetCurrentDateAndTime(TimeUtil::ISO_8601_FORMAT) + " " + level + " " + std::string(::progname) + ": "
              + msg;
        if (log_process_pids_)
            msg += " (PID: " + std::to_string(::getpid()) + ")";
    }

    if (log_strip_call_site_) {
        const auto END_OF_CALL_SITE_PREFIX(msg.find("): "));
        if (END_OF_CALL_SITE_PREFIX != std::string::npos)
            msg = msg.substr(END_OF_CALL_SITE_PREFIX + 3);
    }

    msg += '\n';

    if (unlikely(::write(fd_, reinterpret_cast<const void *>(msg.data()), msg.size()) == -1)) {
        const std::string error_message("in Logger::writeString(util.cc): write to file descriptor " + std::to_string(fd_)
                                        + " failed! (errno = " + std::to_string(errno) + ")");
        #pragma GCC diagnostic ignored "-Wunused-result"
        ::write(STDERR_FILENO, error_message.data(), error_message.size());
        #pragma GCC diagnostic warning "-Wunused-result"
        _exit(EXIT_FAILURE);
    }

    if (unlikely(::progname == nullptr))
        _exit(EXIT_FAILURE);
}

DSVReader::DSVReader(const std::string &filename, const char field_separator, const char field_delimiter)
    : field_separator_(field_separator), field_delimiter_(field_delimiter), line_no_(0), filename_(filename)
{
    input_ = std::fopen(filename.c_str(), "rm");
    if (input_ == nullptr)
        throw std::runtime_error("in DSVReader::DSVReader: can't open \"" + filename + "\" for reading!");
}

DSVReader::~DSVReader() {
    if (input_ != nullptr)
        std::fclose(input_);
}

namespace {

void SkipFieldPadding(FILE * const input) {
    int ch = std::fgetc(input);
    while (isblank(ch))
        ch = std::fgetc(input);
    std::ungetc(ch, input);
}

/** \brief Remove trailing spaces and tabs from "s". */
std::string TrimBlanks(std::string * s) {
    std::string::const_reverse_iterator it(s->crbegin());
    for (/* Empty! */; it != s->crend() and std::isblank(*it); ++it)
        /* Intentionally Empty! */;
    if (it != s->crbegin())
        *s = s->substr(0, std::distance(it, s->crend()));

    return *s;
}

std::string ReadQuotedValue(FILE * const input, const char field_delimiter, const char field_separator) {
    std::string value;
    bool delimiter_seen(false);
    for (;;) {
        const int ch(std::fgetc(input));
        if (ch == EOF)
            throw std::runtime_error("unexpected EOF while reading a quoted DSV value!");
        if (ch == field_delimiter) {
            if (delimiter_seen) {
                // ignore if it's not the outermost delimiter
                const int next(std::fgetc(input));
                std::ungetc(next, input);

                if (next == field_separator or next == '\n' or next == EOF)
                    return value;
            } else
                delimiter_seen = true;
        } else {
            if (ch == '\n' or ch == EOF) {
                std::ungetc(ch, input);
                return TrimBlanks(&value);
            }
            value += static_cast<char>(ch);
        }
    }
}

std::string ReadNonQuotedValue(FILE * const input, const char field_separator) {
    std::string value;
    for (;;) {
        const int ch(std::fgetc(input));
        if (ch == EOF or ch == '\n' or ch == field_separator) {
            std::ungetc(ch, input);
            return TrimBlanks(&value);
        }
        value += static_cast<char>(ch);
    }
}

void BacktraceSignalHandler(int signal_no) {
    void *stack_return_addresses[20];
    const size_t number_of_addresses(::backtrace(stack_return_addresses, DIM(stack_return_addresses)));
    char err_msg[1024] = "Caught signal ";
    char *cp = err_msg + std::strlen(err_msg);
    if (signal_no > 10)
        *cp++ = '0' + (signal_no / 10);
    *cp++ = '0' + (signal_no % 10);
    *cp++ = '.';
    *cp++ = '\n';
    *cp = '\0';
    ssize_t unused(::write(STDERR_FILENO, err_msg, std::strlen(err_msg)));
    (void)unused;
    ::backtrace_symbols_fd(stack_return_addresses, number_of_addresses, STDERR_FILENO);
    ::_exit(EXIT_FAILURE);
}

int InstallSegvSignalHandler(void handler(int)) {
    ::signal(SIGSEGV, handler);
    return 0;
}

volatile int dummy = InstallSegvSignalHandler(BacktraceSignalHandler);

} // unnamed namespace

bool DSVReader::readLine(std::vector<std::string> * const values) {
    values->clear();
    ++line_no_;

    int ch;
    for (;;) {
        if (not values->empty()) {
            SkipFieldPadding(input_);
            ch = std::fgetc(input_);
            if (ch == EOF)
                return not values->empty();
            if (ch == '\n')
                return true;
            if (ch != field_separator_)
                throw std::runtime_error("in DSVReader::readLine: on line " + std::to_string(line_no_)
                                         + ": field separator expected, found '"
                                         + std::string(1, static_cast<char>(ch)) + "' instead!");
        }

        SkipFieldPadding(input_);
        ch = std::fgetc(input_);
        if (ch == '\n')
            return true;
        if (ch == EOF)
            return not values->empty();
        if (ch == field_separator_) {
            std::ungetc(ch, input_);
            values->emplace_back("");
        } else if (ch == field_delimiter_) {
            std::ungetc(ch, input_);
            values->emplace_back(ReadQuotedValue(input_, field_delimiter_, field_separator_));
        } else {
            std::ungetc(ch, input_);
            values->emplace_back(ReadNonQuotedValue(input_, field_separator_));
        }
    }
}

[[noreturn]] void Usage(const std::string &usage_message) {
    std::vector<std::string> lines;
    StringUtil::SplitThenTrimWhite(usage_message, '\n', &lines);
    auto line(lines.begin());
    if (unlikely(line == lines.cend()))
        LOG_ERROR("missing usage message!");

    std::cerr << "Usage: " << ::progname << " [--min-log-level] " << *line << '\n';
    const std::string padding(__builtin_strlen("Usage: ") + __builtin_strlen(::progname) + 1, ' ');
    for (++line; line != lines.cend(); ++line)
        std::cerr << padding << *line << '\n';

    std::exit(EXIT_FAILURE);
}
<|endoftext|>


<commit_before>/*
  A program that generates various statistical data from a user in-putted bunch
  of numbers. Specifically, it calculates the mean, median (AKA middle quartile),
  lower quartile and upper quartile. Support for the mode is coming.
*/

#include <cmath>
#include <algorithm>
#include <unordered_map>
#include <boost/algorithm/string.hpp>

float mean(std::vector<float> numbers)
{
  // Self-explanatory, this calculates the mean of the numbers
  float mean_value = std::accumulate(numbers.begin(), numbers.end(), 0.0) / numbers.size();
  return mean_value;
}

float median(std::vector<float> numbers)
{
  int vector_size = numbers.size(); // So we don't have to recompute it often

  // Cases for where the vector size is odd and even, respectively
  if (vector_size % 2 != 0)
    {
      return numbers[vector_size / 2];
    }
  else
    {
      float median_value = (numbers[vector_size / 2] + numbers[(vector_size / 2) - 1]) / 2;
      return median_value;
    }
}

// std::vector<float> mode(std::vector<float> numbers)
// {
//   std::vector<float> mode_values; // What the mode(s) will be put into
//   unsigned int last_N_occurrences = 0; // Holds the current largest number of occurrences

//   for (unsigned int n = 0; n < numbers.size(); n++)
//     {
//       unsigned int n_occurrences = 0; // The number of occurrences for the current n
//       for (unsigned int f = 0; f < numbers.size(); f++)
//         {
//           if (numbers[n] == numbers[f])
//             {
//               n_occurrences++;
//               //              std::cout << "Got to 49" << std::endl;
//             }
//         }

//       //      std::cout << n_occurrences << std::endl;
//       if (n_occurrences > last_N_occurrences)
//         {
//           last_N_occurrences = n_occurrences;
//           mode_values.clear();
//           mode_values.push_back(numbers[n]);
//         }
//       else if (n_occurrences == last_N_occurrences)
//         {
//           mode_values.push_back(numbers[n]);
//         }
//     }

//   return mode_values;
// }
std::unordered_map<float, int> mode(std::vector<float> nums)
{
  std::unordered_map<float, int> mode_values;

  for (auto num : nums) {
    if (mode_values.find(num) == mode_values.end())
      {
        mode_values[num] = 1;
      }
    else
      {
        mode_values[num] += 1;
      }
  }
  return m;
}

float lower_quartile(std::vector<float> numbers)
{
  std::vector<float> lower_half;
  float numbers_median = median(numbers); // So we don't have to recompute it often
  float lower_quartile_value;

  // If the median is in the numbers vector, then include it in the lower_half
  // vector, else don't include it.
  if (std::find(numbers.begin(), numbers.end(), numbers_median) != numbers.end())
    {
      for (int n = 0; numbers[n] <= numbers_median; n++)
        {
          lower_half.push_back(numbers[n]);
        }
    }
  else
    {
      for (int n = 0; numbers[n] < numbers_median; n++)
        {
          lower_half.push_back(numbers[n]);
        }
    }

  lower_quartile_value = median(lower_half);

  return lower_quartile_value;
}

float upper_quartile(std::vector<float> numbers)
{
  std::vector<float> upper_half;
  float numbers_median = median(numbers); // So we don't have to recompute it often
  float upper_quartile_value;

  // If the median is in the numbers vector, then include it in the upper_half
  // vector, else don't include it.
  if (std::find(numbers.begin(), numbers.end(), numbers_median) != numbers.end())
    {
      for (float n : numbers)
        {
          if (n >= numbers_median)
            {
              upper_half.push_back(n);
            }
          else
            {
              continue;
            }
        }
    }
  else
    {
      for (float n : numbers)
        {
          if (n > numbers_median)
            {
              upper_half.push_back(n);
            }
          else
            {
              continue;
            }
        }
    }

  upper_quartile_value = median(upper_half);

  return upper_quartile_value;
}

int main()
{
  std::vector<float> numbers_vect;
  std::string raw_input;
  std::vector<std::string> raw_input_vect;

  // Input section
  std::cout << "Enter the list of numbers separated by spaces: ";
  std::getline(std::cin, raw_input);
  // Split numbers_str by whitespace, then converts the string vector into an float vector
  boost::split(raw_input_vect, raw_input, boost::is_any_of("\t "));
  std::transform(raw_input_vect.begin(), raw_input_vect.end(), std::back_inserter(numbers_vect), [](const std::string& val) { return std::stof(val); });

  // Sorts the numbers numerically
  std::sort(numbers_vect.begin(), numbers_vect.end());

  //  std::vector<float> mode_vector = mode(numbers_vect);
  std::unordered_map<float, int> mode_vector = mode(numbers_vect);

  std::cout << "Mean: " << mean(numbers_vect) << std::endl;
  std::cout << "Median (also middle quartile): " << median(numbers_vect) << std::endl;
  std::cout << "Lower Quartile: " << lower_quartile(numbers_vect) << std::endl;
  std::cout << "Upper Quartile: " << upper_quartile(numbers_vect) << std::endl;

  std::cout << "Mode(s): " << std::endl;
  for (auto kv : mode_vector)
    {
      printf("%f shows up %d times.\n", kv.first, kv.second);
    }
  std::cout << std::endl;

  // if (mode_vector.size() == 0)
  //   {
  //     std::cout << "No mode found!" << std::endl;
  //   }
  // else if (mode_vector.size() == 1)
  //   {
  //     std::cout << "Mode: " << mode_vector[0] << std::endl;
  //   }
  // else
  //   {
  //     for (float n = 0; n < (mode_vector.size() - 1); n++)
  //       {
  //         std::cout << mode_vector[n] << ", ";
  //       }
  //     std::cout << mode_vector.back() << std::endl;
  //   }
}
<commit_msg>mode() is sort-of working. Fails on unsorted input for some horrendously weird reason<commit_after>/*
  A program that generates various statistical data from a user in-putted bunch
  of numbers. Specifically, it calculates the mean, median (AKA middle quartile),
  mode, lower quartile and upper quartile.
*/

#include <cmath>
#include <iostream>
#include <algorithm>
#include <unordered_map>
#include <boost/algorithm/string.hpp>

float mean(std::vector<float> numbers)
{
  // Self-explanatory, this calculates the mean of the numbers
  float mean_value = std::accumulate(numbers.begin(), numbers.end(), 0.0) / numbers.size();
  return mean_value;
}

float median(std::vector<float> numbers)
{
  int vector_size = numbers.size(); // So we don't have to recompute it often

  // Cases for where the vector size is odd and even, respectively
  if (vector_size % 2 != 0)
    {
      return numbers[vector_size / 2];
    }
  else
    {
      float median_value = (numbers[vector_size / 2] + numbers[(vector_size / 2) - 1]) / 2;
      return median_value;
    }
}

std::vector<float> mode(std::vector<float> numbers)
{
  std::vector<float> mode_values; // What the mode(s) will be put into
  unsigned int last_N_occurrences = 0; // Holds the current largest number of occurrences

  for (float n : numbers)
    {
      unsigned int n_occurrences = std::count(numbers.begin(), numbers.end(), n); // The number of occurrences for the current n

      // Is the number of occurrences more than the last mode? If so, then clear
      // mode_values and replace with new mode. Else append.
      if (n_occurrences > last_N_occurrences)
        {
          last_N_occurrences = n_occurrences;
          mode_values.clear();
          mode_values.push_back(numbers[n]);
        }
      else if (n_occurrences == last_N_occurrences)
        {
          mode_values.push_back(numbers[n]);
        }
    }

  // Remove doubles from mode_values, could be optimized
  std::vector<float>::iterator rm_doubles = std::unique(mode_values.begin(), mode_values.end());
  mode_values.resize(std::distance(mode_values.begin(), rm_doubles));

  return mode_values;
}

float lower_quartile(std::vector<float> numbers)
{
  std::vector<float> lower_half;
  float numbers_median = median(numbers); // So we don't have to recompute it often
  float lower_quartile_value;

  // If the median is in the numbers vector, then include it in the lower_half
  // vector, else don't include it.
  if (std::find(numbers.begin(), numbers.end(), numbers_median) != numbers.end())
    {
      for (int n = 0; numbers[n] <= numbers_median; n++)
        {
          lower_half.push_back(numbers[n]);
        }
    }
  else
    {
      for (int n = 0; numbers[n] < numbers_median; n++)
        {
          lower_half.push_back(numbers[n]);
        }
    }

  lower_quartile_value = median(lower_half);

  return lower_quartile_value;
}

float upper_quartile(std::vector<float> numbers)
{
  std::vector<float> upper_half;
  float numbers_median = median(numbers); // So we don't have to recompute it often
  float upper_quartile_value;

  // If the median is in the numbers vector, then include it in the upper_half
  // vector, else don't include it.
  if (std::find(numbers.begin(), numbers.end(), numbers_median) != numbers.end())
    {
      for (float n : numbers)
        {
          if (n >= numbers_median)
            {
              upper_half.push_back(n);
            }
          else
            {
              continue;
            }
        }
    }
  else
    {
      for (float n : numbers)
        {
          if (n > numbers_median)
            {
              upper_half.push_back(n);
            }
          else
            {
              continue;
            }
        }
    }

  upper_quartile_value = median(upper_half);

  return upper_quartile_value;
}

int main()
{
  std::vector<float> numbers_vect;
  std::string raw_input;
  std::vector<std::string> raw_input_vect;

  // Input section
  std::cout << "Enter the list of numbers separated by spaces: ";
  std::getline(std::cin, raw_input);
  // Split numbers_str by whitespace, then converts the string vector into an float vector
  boost::split(raw_input_vect, raw_input, boost::is_any_of("\t "));
  std::transform(raw_input_vect.begin(), raw_input_vect.end(), std::back_inserter(numbers_vect), [](const std::string& val) { return std::stof(val); });

  // Sorts the numbers numerically
  std::sort(numbers_vect.begin(), numbers_vect.end());

  std::cout << "Mean: " << mean(numbers_vect) << std::endl;
  std::cout << "Median (also middle quartile): " << median(numbers_vect) << std::endl;
  std::cout << "Lower Quartile: " << lower_quartile(numbers_vect) << std::endl;
  std::cout << "Upper Quartile: " << upper_quartile(numbers_vect) << std::endl;
  std::cout << "Mode: ";

  std::vector<float> mode_vector = mode(numbers_vect);
  if (mode_vector.size() == numbers_vect.size())
    {
      std::cout << "No mode found!" << std::endl;
    }
  else if (mode_vector.size() == 1)
    {
      std::cout << mode_vector[0] << std::endl;
    }
  else
    {
      for (float n = 0; n < (mode_vector.size() - 1); n++)
        {
          std::cout << mode_vector[n] << ", ";
        }
      std::cout << mode_vector.back() << std::endl;
    }
}
<|endoftext|>


<commit_before>//----------------------------------*-C++-*----------------------------------//
/*!
 * \file   DeviceTraits.hh
 * \author Steven Hamilton
 * \brief  Templated interface for Kokkos devices.
 */
//---------------------------------------------------------------------------//

#ifndef mc_solvers_DeviceTraits_hh
#define mc_solvers_DeviceTraits_hh

#include "KokkosCore_config.h"

#ifdef KOKKOS_HAVE_OPENMP
#include <omp.h>
#endif

#include "Kokkos_hwloc.hpp"

// "New" Kokkos nodes
#include "Kokkos_Serial.hpp"
#include "Kokkos_OpenMP.hpp"
#include "Kokkos_Threads.hpp"

#include "Teuchos_RCP.hpp"
#include "Teuchos_ParameterList.hpp"

namespace alea
{

//---------------------------------------------------------------------------//
/*!
 * \class DeviceTraits
 * \brief Templated interface for initializing/finalizing Kokkos devices.
 *
 * This is a generic implementation for a single thread with trivial
 * initialization/finalization which should be suitable for Kokkos::Serial.
 */
//---------------------------------------------------------------------------//
template <class DeviceType>
class DeviceTraits
{
  public:

    //! \brief Initialize device on specified number of threads.
    static inline void initialize(
        Teuchos::RCP<Teuchos::ParameterList> pl)
    {
    }

    //! \brief Finalize device.
    static inline void finalize(){}
};

//---------------------------------------------------------------------------//
/*!
 * \class DeviceTraits<Kokkos::OpenMP>
 * \brief Specialization of DeviceTraits for Kokkos::OpenMP.
 */
//---------------------------------------------------------------------------//
#ifdef KOKKOS_HAVE_OPENMP
template <>
class DeviceTraits<Kokkos::OpenMP>
{
  public:

    //! \brief Initialize device on specified number of threads.
    static inline void initialize(
        Teuchos::RCP<Teuchos::ParameterList> pl)
    {
        int threads = pl->get("num_threads",1);
        bool print_config = pl->get("print_config",false);
        if( !Kokkos::OpenMP::is_initialized() )
            Kokkos::OpenMP::initialize( threads );
        if( print_config )
            Kokkos::OpenMP::print_configuration(std::cout,true);
    }

    //! \brief Finalize device.
    static inline void finalize()
    {
        if( Kokkos::OpenMP::is_initialized() )
            Kokkos::OpenMP::finalize();
    }
};
#endif

//---------------------------------------------------------------------------//
/*!
 * \class DeviceTraits<Kokkos::Threads>
 * \brief Specialization of DeviceTraits for Kokkos::Threads.
 */
//---------------------------------------------------------------------------//
template <>
class DeviceTraits<Kokkos::Threads>
{
  public:

    //! \brief Initialize device on specified number of threads.
    static inline void initialize(
        Teuchos::RCP<Teuchos::ParameterList> pl)
    {
        int threads = pl->get("num_threads",1);
        bool print_config = pl->get("print_config",false);
        if( !Kokkos::Threads::is_initialized() )
            Kokkos::Threads::initialize( threads );
        if( print_config )
            Kokkos::Threads::print_configuration(std::cout,true);
    }

    //! \brief Finalize device.
    static inline void finalize()
    {
        if( Kokkos::Threads::is_initialized() )
            Kokkos::Threads::finalize();
    }
};

//---------------------------------------------------------------------------//
/*!
 * \class DeviceTraits<Kokkos::Cuda>
 * \brief Specialization of DeviceTraits for Kokkos::Cuda.
 */
//---------------------------------------------------------------------------//
template <>
class DeviceTraits<Kokkos::Cuda>
{
  public:

    //! \brief Initialize device
    static inline void initialize(
        Teuchos::RCP<Teuchos::ParameterList> pl)
    {
        int threads = pl->get("num_threads",1);
        bool print_config = pl->get("print_config",false);
        if( !HOST::is_initialized() )
        {
            HOST::initialize( threads );
        }

        if( !Kokkos::Cuda::is_initialized() )
        {
            Kokkos::Cuda::initialize();
        }

        if( print_config )
        {
            std::cout << "Host configuration:" << std::endl;
            HOST::print_configuration(std::cout,true);
            std::cout << "Device configuration:" << std::endl;
            Kokkos::Cuda::print_configuration(std::cout,true);
        }
    }

    //! \brief Finalize device.
    static inline void finalize()
    {
        if( HOST::is_initialized() )
        {
            HOST::finalize();
        }
        if( Kokkos::Cuda::is_initialized() )
        {
            Kokkos::Cuda::finalize();
        }
    }
};

} // namespace alea

#endif // mc_solvers_DeviceTraits_hh

<commit_msg>Guarding off cuda code for non-cuda builds.<commit_after>//----------------------------------*-C++-*----------------------------------//
/*!
 * \file   DeviceTraits.hh
 * \author Steven Hamilton
 * \brief  Templated interface for Kokkos devices.
 */
//---------------------------------------------------------------------------//

#ifndef mc_solvers_DeviceTraits_hh
#define mc_solvers_DeviceTraits_hh

#include "KokkosCore_config.h"

#ifdef KOKKOS_HAVE_OPENMP
#include <omp.h>
#endif

#include "Kokkos_hwloc.hpp"

// "New" Kokkos nodes
#include "Kokkos_Serial.hpp"
#include "Kokkos_OpenMP.hpp"
#include "Kokkos_Threads.hpp"

#include "Teuchos_RCP.hpp"
#include "Teuchos_ParameterList.hpp"

namespace alea
{

//---------------------------------------------------------------------------//
/*!
 * \class DeviceTraits
 * \brief Templated interface for initializing/finalizing Kokkos devices.
 *
 * This is a generic implementation for a single thread with trivial
 * initialization/finalization which should be suitable for Kokkos::Serial.
 */
//---------------------------------------------------------------------------//
template <class DeviceType>
class DeviceTraits
{
  public:

    //! \brief Initialize device on specified number of threads.
    static inline void initialize(
        Teuchos::RCP<Teuchos::ParameterList> pl)
    {
    }

    //! \brief Finalize device.
    static inline void finalize(){}
};

//---------------------------------------------------------------------------//
/*!
 * \class DeviceTraits<Kokkos::OpenMP>
 * \brief Specialization of DeviceTraits for Kokkos::OpenMP.
 */
//---------------------------------------------------------------------------//
#ifdef KOKKOS_HAVE_OPENMP
template <>
class DeviceTraits<Kokkos::OpenMP>
{
  public:

    //! \brief Initialize device on specified number of threads.
    static inline void initialize(
        Teuchos::RCP<Teuchos::ParameterList> pl)
    {
        int threads = pl->get("num_threads",1);
        bool print_config = pl->get("print_config",false);
        if( !Kokkos::OpenMP::is_initialized() )
            Kokkos::OpenMP::initialize( threads );
        if( print_config )
            Kokkos::OpenMP::print_configuration(std::cout,true);
    }

    //! \brief Finalize device.
    static inline void finalize()
    {
        if( Kokkos::OpenMP::is_initialized() )
            Kokkos::OpenMP::finalize();
    }
};
#endif

//---------------------------------------------------------------------------//
/*!
 * \class DeviceTraits<Kokkos::Threads>
 * \brief Specialization of DeviceTraits for Kokkos::Threads.
 */
//---------------------------------------------------------------------------//
template <>
class DeviceTraits<Kokkos::Threads>
{
  public:

    //! \brief Initialize device on specified number of threads.
    static inline void initialize(
        Teuchos::RCP<Teuchos::ParameterList> pl)
    {
        int threads = pl->get("num_threads",1);
        bool print_config = pl->get("print_config",false);
        if( !Kokkos::Threads::is_initialized() )
            Kokkos::Threads::initialize( threads );
        if( print_config )
            Kokkos::Threads::print_configuration(std::cout,true);
    }

    //! \brief Finalize device.
    static inline void finalize()
    {
        if( Kokkos::Threads::is_initialized() )
            Kokkos::Threads::finalize();
    }
};

//---------------------------------------------------------------------------//
/*!
 * \class DeviceTraits<Kokkos::Cuda>
 * \brief Specialization of DeviceTraits for Kokkos::Cuda.
 */
//---------------------------------------------------------------------------//
#ifdef KOKKOS_HAVE_CUDA
template <>
class DeviceTraits<Kokkos::Cuda>
{
  public:

    //! \brief Initialize device
    static inline void initialize(
        Teuchos::RCP<Teuchos::ParameterList> pl)
    {
        int threads = pl->get("num_threads",1);
        bool print_config = pl->get("print_config",false);
        if( !HOST::is_initialized() )
        {
            HOST::initialize( threads );
        }

        if( !Kokkos::Cuda::is_initialized() )
        {
            Kokkos::Cuda::initialize();
        }

        if( print_config )
        {
            std::cout << "Host configuration:" << std::endl;
            HOST::print_configuration(std::cout,true);
            std::cout << "Device configuration:" << std::endl;
            Kokkos::Cuda::print_configuration(std::cout,true);
        }
    }

    //! \brief Finalize device.
    static inline void finalize()
    {
        if( HOST::is_initialized() )
        {
            HOST::finalize();
        }
        if( Kokkos::Cuda::is_initialized() )
        {
            Kokkos::Cuda::finalize();
        }
    }
};
#endif // KOKKOS_HAVE_CUDA

} // namespace alea

#endif // mc_solvers_DeviceTraits_hh

<|endoftext|>