<commit_before>/*
 * Main Send File Transfer Window
 *
 * Copyright (C) 2011 David Edmundson <kde@davidedmundson.co.uk>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "mainwindow.h"
#include "ui_mainwindow.h"

#include <KFileItem>
#include <KFileItemList>
#include <KIO/PreviewJob>
#include <KApplication>
#include <KCmdLineArgs>
#include <KMimeType>
#include <KDebug>

#include <QAbstractItemDelegate>
#include <QPainter>
#include <QRect>
#include <QStyle>
#include <QDebug>

#include <TelepathyQt4/AccountManager>
#include <TelepathyQt4/PendingChannelRequest>
#include <TelepathyQt4/PendingReady>

#include "accounts-model.h"
#include "flat-model-proxy.h"
#include "account-filter-model.h"
#include "contact-model-item.h"

//FIXME, copy and paste the approver code for loading this from a config file into this, the contact list and the chat handler.
#define PREFERRED_FILETRANSFER_HANDLER "org.freedesktop.Telepathy.Client.KDE.FileTransfer"

class ContactGridDelegate : public QAbstractItemDelegate {
public:
    ContactGridDelegate(QObject *parent);
    void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const;
    QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const;
};

ContactGridDelegate::ContactGridDelegate(QObject *parent)
    : QAbstractItemDelegate(parent)
{

}

void ContactGridDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    QStyle *style = QApplication::style();
    int textHeight = option.fontMetrics.height()*2;

    style->drawPrimitive(QStyle::PE_PanelItemViewItem, &option, painter);

    QRect avatarRect = option.rect.adjusted(0,0,0,-textHeight);
    QRect textRect = option.rect.adjusted(0,option.rect.height()-textHeight,0,-3);

    QPixmap avatar = index.data(Qt::DecorationRole).value<QPixmap>();
    if (avatar.isNull()) {
        avatar = KIcon("im-user-online").pixmap(QSize(70,70));
    }

    //resize larger avatars
    if (avatar.width() > 80 || avatar.height()> 80) {
        avatar = avatar.scaled(QSize(80,80), Qt::KeepAspectRatio);
        //draw leaving paddings on smaller (or non square) avatars
    }
    style->drawItemPixmap(painter, avatarRect, Qt::AlignCenter, avatar);

    QTextOption textOption;
    textOption.setAlignment(Qt::AlignCenter);
    textOption.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);
    painter->drawText(textRect, index.data().toString(), textOption);

}

QSize ContactGridDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    int textHeight = option.fontMetrics.height()*2;
    return QSize(80,80+textHeight+3);
}

MainWindow::MainWindow(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::MainWindow),
    m_accountsModel(0)
{
    Tp::registerTypes();

    ui->setupUi(this);

    kDebug() << KApplication::arguments();

    KUrl filePath (KCmdLineArgs::parsedArgs()->arg(0));
    ui->filePreview->showPreview(filePath);
    ui->fileNameLabel->setText(filePath.fileName());

    Tp::AccountFactoryPtr  accountFactory = Tp::AccountFactory::create(QDBusConnection::sessionBus(),
                                                                       Tp::Features() << Tp::Account::FeatureCore
                                                                       << Tp::Account::FeatureAvatar
                                                                       << Tp::Account::FeatureProtocolInfo
                                                                       << Tp::Account::FeatureProfile);

    Tp::ConnectionFactoryPtr connectionFactory = Tp::ConnectionFactory::create(QDBusConnection::sessionBus(),
                                                                               Tp::Features() << Tp::Connection::FeatureCore
                                                                               << Tp::Connection::FeatureRosterGroups
                                                                               << Tp::Connection::FeatureRoster
                                                                               << Tp::Connection::FeatureSelfContact);

    Tp::ContactFactoryPtr contactFactory = Tp::ContactFactory::create(Tp::Features()  << Tp::Contact::FeatureAlias
                                                                      << Tp::Contact::FeatureAvatarData
                                                                      << Tp::Contact::FeatureSimplePresence
                                                                      << Tp::Contact::FeatureCapabilities);

    Tp::ChannelFactoryPtr channelFactory = Tp::ChannelFactory::create(QDBusConnection::sessionBus());

    m_accountManager = Tp::AccountManager::create(QDBusConnection::sessionBus(),
                                                  accountFactory,
                                                  connectionFactory,
                                                  channelFactory,
                                                  contactFactory);

    connect(m_accountManager->becomeReady(), SIGNAL(finished(Tp::PendingOperation*)), SLOT(onAccountManagerReady()));

    connect(ui->buttonBox, SIGNAL(accepted()), SLOT(onDialogAccepted()));
    connect(ui->buttonBox, SIGNAL(rejected()), SLOT(close()));
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::onAccountManagerReady()
{
    m_accountsModel = new AccountsModel(m_accountManager, this);
    AccountFilterModel *filterModel = new AccountFilterModel(this);
    filterModel->setSourceModel(m_accountsModel);
    filterModel->filterOfflineUsers(true);
    FlatModelProxy *flatProxyModel = new FlatModelProxy(filterModel);

    ui->listView->setModel(flatProxyModel);
    ui->listView->setItemDelegate(new ContactGridDelegate(this));
}

void MainWindow::onDialogAccepted()
{
    // don't do anytghing if no contact has been selected
    if (!ui->listView->currentIndex().isValid()) {
        // show message box?
        return;
    }

    ContactModelItem *contactModelItem = ui->listView->currentIndex().data(AccountsModel::ItemRole).value<ContactModelItem*>();
    Tp::ContactPtr contact = contactModelItem->contact();
    Tp::AccountPtr sendingAccount = m_accountsModel->accountForContactItem(contactModelItem);

    if (sendingAccount.isNull()) {
        kDebug() << "sending account: NULL";
    } else {
        kDebug() << "Account is: " << sendingAccount->displayName();
        kDebug() << "sending to: " << contact->alias();
    }

    // start sending file
    QString filePath (KCmdLineArgs::parsedArgs()->arg(0));
    qDebug() << "FILE TO SEND: " << filePath;

    Tp::FileTransferChannelCreationProperties fileTransferProperties(filePath, KMimeType::findByFileContent(filePath)->name());

    Tp::PendingChannelRequest* channelRequest = sendingAccount->createFileTransfer(contact,
                                                                                fileTransferProperties,
                                                                                QDateTime::currentDateTime(),
                                                                                PREFERRED_FILETRANSFER_HANDLER);

    connect(channelRequest, SIGNAL(finished(Tp::PendingOperation*)), SLOT(slotFileTransferFinished(Tp::PendingOperation*)));
}

void MainWindow::slotFileTransferFinished(Tp::PendingOperation* op)
{
    if (op->isError()) {
        //FIXME map to human readable strings.
        QString errorMsg(op->errorName() + ": " + op->errorMessage());
        kDebug() << "ERROR!: " << errorMsg;
    } else {
        kDebug() << "FUCK YEAH TRANSFER STARTED";
        // now I can close the dialog
        close();
    }
}

<commit_msg>remove debug profanity<commit_after>/*
 * Main Send File Transfer Window
 *
 * Copyright (C) 2011 David Edmundson <kde@davidedmundson.co.uk>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "mainwindow.h"
#include "ui_mainwindow.h"

#include <KFileItem>
#include <KFileItemList>
#include <KIO/PreviewJob>
#include <KApplication>
#include <KCmdLineArgs>
#include <KMimeType>
#include <KDebug>

#include <QAbstractItemDelegate>
#include <QPainter>
#include <QRect>
#include <QStyle>
#include <QDebug>

#include <TelepathyQt4/AccountManager>
#include <TelepathyQt4/PendingChannelRequest>
#include <TelepathyQt4/PendingReady>

#include "accounts-model.h"
#include "flat-model-proxy.h"
#include "account-filter-model.h"
#include "contact-model-item.h"

//FIXME, copy and paste the approver code for loading this from a config file into this, the contact list and the chat handler.
#define PREFERRED_FILETRANSFER_HANDLER "org.freedesktop.Telepathy.Client.KDE.FileTransfer"

class ContactGridDelegate : public QAbstractItemDelegate {
public:
    ContactGridDelegate(QObject *parent);
    void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const;
    QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const;
};

ContactGridDelegate::ContactGridDelegate(QObject *parent)
    : QAbstractItemDelegate(parent)
{

}

void ContactGridDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    QStyle *style = QApplication::style();
    int textHeight = option.fontMetrics.height()*2;

    style->drawPrimitive(QStyle::PE_PanelItemViewItem, &option, painter);

    QRect avatarRect = option.rect.adjusted(0,0,0,-textHeight);
    QRect textRect = option.rect.adjusted(0,option.rect.height()-textHeight,0,-3);

    QPixmap avatar = index.data(Qt::DecorationRole).value<QPixmap>();
    if (avatar.isNull()) {
        avatar = KIcon("im-user-online").pixmap(QSize(70,70));
    }

    //resize larger avatars
    if (avatar.width() > 80 || avatar.height()> 80) {
        avatar = avatar.scaled(QSize(80,80), Qt::KeepAspectRatio);
        //draw leaving paddings on smaller (or non square) avatars
    }
    style->drawItemPixmap(painter, avatarRect, Qt::AlignCenter, avatar);

    QTextOption textOption;
    textOption.setAlignment(Qt::AlignCenter);
    textOption.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);
    painter->drawText(textRect, index.data().toString(), textOption);

}

QSize ContactGridDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    int textHeight = option.fontMetrics.height()*2;
    return QSize(80,80+textHeight+3);
}

MainWindow::MainWindow(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::MainWindow),
    m_accountsModel(0)
{
    Tp::registerTypes();

    ui->setupUi(this);

    kDebug() << KApplication::arguments();

    KUrl filePath (KCmdLineArgs::parsedArgs()->arg(0));
    ui->filePreview->showPreview(filePath);
    ui->fileNameLabel->setText(filePath.fileName());

    Tp::AccountFactoryPtr  accountFactory = Tp::AccountFactory::create(QDBusConnection::sessionBus(),
                                                                       Tp::Features() << Tp::Account::FeatureCore
                                                                       << Tp::Account::FeatureAvatar
                                                                       << Tp::Account::FeatureProtocolInfo
                                                                       << Tp::Account::FeatureProfile);

    Tp::ConnectionFactoryPtr connectionFactory = Tp::ConnectionFactory::create(QDBusConnection::sessionBus(),
                                                                               Tp::Features() << Tp::Connection::FeatureCore
                                                                               << Tp::Connection::FeatureRosterGroups
                                                                               << Tp::Connection::FeatureRoster
                                                                               << Tp::Connection::FeatureSelfContact);

    Tp::ContactFactoryPtr contactFactory = Tp::ContactFactory::create(Tp::Features()  << Tp::Contact::FeatureAlias
                                                                      << Tp::Contact::FeatureAvatarData
                                                                      << Tp::Contact::FeatureSimplePresence
                                                                      << Tp::Contact::FeatureCapabilities);

    Tp::ChannelFactoryPtr channelFactory = Tp::ChannelFactory::create(QDBusConnection::sessionBus());

    m_accountManager = Tp::AccountManager::create(QDBusConnection::sessionBus(),
                                                  accountFactory,
                                                  connectionFactory,
                                                  channelFactory,
                                                  contactFactory);

    connect(m_accountManager->becomeReady(), SIGNAL(finished(Tp::PendingOperation*)), SLOT(onAccountManagerReady()));

    connect(ui->buttonBox, SIGNAL(accepted()), SLOT(onDialogAccepted()));
    connect(ui->buttonBox, SIGNAL(rejected()), SLOT(close()));
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::onAccountManagerReady()
{
    m_accountsModel = new AccountsModel(m_accountManager, this);
    AccountFilterModel *filterModel = new AccountFilterModel(this);
    filterModel->setSourceModel(m_accountsModel);
    filterModel->filterOfflineUsers(true);
    FlatModelProxy *flatProxyModel = new FlatModelProxy(filterModel);

    ui->listView->setModel(flatProxyModel);
    ui->listView->setItemDelegate(new ContactGridDelegate(this));
}

void MainWindow::onDialogAccepted()
{
    // don't do anytghing if no contact has been selected
    if (!ui->listView->currentIndex().isValid()) {
        // show message box?
        return;
    }

    ContactModelItem *contactModelItem = ui->listView->currentIndex().data(AccountsModel::ItemRole).value<ContactModelItem*>();
    Tp::ContactPtr contact = contactModelItem->contact();
    Tp::AccountPtr sendingAccount = m_accountsModel->accountForContactItem(contactModelItem);

    if (sendingAccount.isNull()) {
        kDebug() << "sending account: NULL";
    } else {
        kDebug() << "Account is: " << sendingAccount->displayName();
        kDebug() << "sending to: " << contact->alias();
    }

    // start sending file
    QString filePath (KCmdLineArgs::parsedArgs()->arg(0));
    qDebug() << "FILE TO SEND: " << filePath;

    Tp::FileTransferChannelCreationProperties fileTransferProperties(filePath, KMimeType::findByFileContent(filePath)->name());

    Tp::PendingChannelRequest* channelRequest = sendingAccount->createFileTransfer(contact,
                                                                                fileTransferProperties,
                                                                                QDateTime::currentDateTime(),
                                                                                PREFERRED_FILETRANSFER_HANDLER);

    connect(channelRequest, SIGNAL(finished(Tp::PendingOperation*)), SLOT(slotFileTransferFinished(Tp::PendingOperation*)));
}

void MainWindow::slotFileTransferFinished(Tp::PendingOperation* op)
{
    if (op->isError()) {
        //FIXME map to human readable strings.
        QString errorMsg(op->errorName() + ": " + op->errorMessage());
        kDebug() << "ERROR!: " << errorMsg;
    } else {
        kDebug() << "Transfer started";
        // now I can close the dialog
        close();
    }
}

<|endoftext|>


<commit_before>//===- StringMatcher.cpp - Generate a matcher for input strings -----------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the StringMatcher class.
//
//===----------------------------------------------------------------------===//

#include "llvm/TableGen/StringMatcher.h"
#include "llvm/Support/raw_ostream.h"
#include <map>
using namespace llvm;

/// FindFirstNonCommonLetter - Find the first character in the keys of the
/// string pairs that is not shared across the whole set of strings.  All
/// strings are assumed to have the same length.
static unsigned
FindFirstNonCommonLetter(const std::vector<const
                              StringMatcher::StringPair*> &Matches) {
  assert(!Matches.empty());
  for (unsigned i = 0, e = Matches[0]->first.size(); i != e; ++i) {
    // Check to see if letter i is the same across the set.
    char Letter = Matches[0]->first[i];

    for (unsigned str = 0, e = Matches.size(); str != e; ++str)
      if (Matches[str]->first[i] != Letter)
        return i;
  }

  return Matches[0]->first.size();
}

/// EmitStringMatcherForChar - Given a set of strings that are known to be the
/// same length and whose characters leading up to CharNo are the same, emit
/// code to verify that CharNo and later are the same.
///
/// \return - True if control can leave the emitted code fragment.
bool StringMatcher::
EmitStringMatcherForChar(const std::vector<const StringPair*> &Matches,
                         unsigned CharNo, unsigned IndentCount) const {
  assert(!Matches.empty() && "Must have at least one string to match!");
  std::string Indent(IndentCount*2+4, ' ');

  // If we have verified that the entire string matches, we're done: output the
  // matching code.
  if (CharNo == Matches[0]->first.size()) {
    assert(Matches.size() == 1 && "Had duplicate keys to match on");

    // If the to-execute code has \n's in it, indent each subsequent line.
    StringRef Code = Matches[0]->second;

    std::pair<StringRef, StringRef> Split = Code.split('\n');
    OS << Indent << Split.first << "\t // \"" << Matches[0]->first << "\"\n";

    Code = Split.second;
    while (!Code.empty()) {
      Split = Code.split('\n');
      OS << Indent << Split.first << "\n";
      Code = Split.second;
    }
    return false;
  }

  // Bucket the matches by the character we are comparing.
  std::map<char, std::vector<const StringPair*> > MatchesByLetter;

  for (unsigned i = 0, e = Matches.size(); i != e; ++i)
    MatchesByLetter[Matches[i]->first[CharNo]].push_back(Matches[i]);

  // If we have exactly one bucket to match, see how many characters are common
  // across the whole set and match all of them at once.
  if (MatchesByLetter.size() == 1) {
    unsigned FirstNonCommonLetter = FindFirstNonCommonLetter(Matches);
    unsigned NumChars = FirstNonCommonLetter-CharNo;

    // Emit code to break out if the prefix doesn't match.
    if (NumChars == 1) {
      // Do the comparison with if (Str[1] != 'f')
      // FIXME: Need to escape general characters.
      OS << Indent << "if (" << StrVariableName << "[" << CharNo << "] != '"
      << Matches[0]->first[CharNo] << "')\n";
      OS << Indent << "  break;\n";
    } else {
      // Do the comparison with if (Str.substr(1, 3) != "foo").
      // FIXME: Need to escape general strings.
      OS << Indent << "if (" << StrVariableName << ".substr(" << CharNo << ", "
      << NumChars << ") != \"";
      OS << Matches[0]->first.substr(CharNo, NumChars) << "\")\n";
      OS << Indent << "  break;\n";
    }

    return EmitStringMatcherForChar(Matches, FirstNonCommonLetter, IndentCount);
  }

  // Otherwise, we have multiple possible things, emit a switch on the
  // character.
  OS << Indent << "switch (" << StrVariableName << "[" << CharNo << "]) {\n";
  OS << Indent << "default: break;\n";

  for (std::map<char, std::vector<const StringPair*> >::iterator LI =
       MatchesByLetter.begin(), E = MatchesByLetter.end(); LI != E; ++LI) {
    // TODO: escape hard stuff (like \n) if we ever care about it.
    OS << Indent << "case '" << LI->first << "':\t // "
       << LI->second.size() << " string";
    if (LI->second.size() != 1) OS << 's';
    OS << " to match.\n";
    if (EmitStringMatcherForChar(LI->second, CharNo+1, IndentCount+1))
      OS << Indent << "  break;\n";
  }

  OS << Indent << "}\n";
  return true;
}

/// Emit - Top level entry point.
///
void StringMatcher::Emit(unsigned Indent) const {
  // If nothing to match, just fall through.
  if (Matches.empty()) return;

  // First level categorization: group strings by length.
  std::map<unsigned, std::vector<const StringPair*> > MatchesByLength;

  for (unsigned i = 0, e = Matches.size(); i != e; ++i)
    MatchesByLength[Matches[i].first.size()].push_back(&Matches[i]);

  // Output a switch statement on length and categorize the elements within each
  // bin.
  OS.indent(Indent*2+2) << "switch (" << StrVariableName << ".size()) {\n";
  OS.indent(Indent*2+2) << "default: break;\n";

  for (std::map<unsigned, std::vector<const StringPair*> >::iterator LI =
       MatchesByLength.begin(), E = MatchesByLength.end(); LI != E; ++LI) {
    OS.indent(Indent*2+2) << "case " << LI->first << ":\t // "
       << LI->second.size()
       << " string" << (LI->second.size() == 1 ? "" : "s") << " to match.\n";
    if (EmitStringMatcherForChar(LI->second, 0, Indent))
      OS.indent(Indent*2+4) << "break;\n";
  }

  OS.indent(Indent*2+2) << "}\n";
}
<commit_msg>Emit memcmp directly from the StringMatcherEmitter.<commit_after>//===- StringMatcher.cpp - Generate a matcher for input strings -----------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the StringMatcher class.
//
//===----------------------------------------------------------------------===//

#include "llvm/TableGen/StringMatcher.h"
#include "llvm/Support/raw_ostream.h"
#include <map>
using namespace llvm;

/// FindFirstNonCommonLetter - Find the first character in the keys of the
/// string pairs that is not shared across the whole set of strings.  All
/// strings are assumed to have the same length.
static unsigned
FindFirstNonCommonLetter(const std::vector<const
                              StringMatcher::StringPair*> &Matches) {
  assert(!Matches.empty());
  for (unsigned i = 0, e = Matches[0]->first.size(); i != e; ++i) {
    // Check to see if letter i is the same across the set.
    char Letter = Matches[0]->first[i];

    for (unsigned str = 0, e = Matches.size(); str != e; ++str)
      if (Matches[str]->first[i] != Letter)
        return i;
  }

  return Matches[0]->first.size();
}

/// EmitStringMatcherForChar - Given a set of strings that are known to be the
/// same length and whose characters leading up to CharNo are the same, emit
/// code to verify that CharNo and later are the same.
///
/// \return - True if control can leave the emitted code fragment.
bool StringMatcher::
EmitStringMatcherForChar(const std::vector<const StringPair*> &Matches,
                         unsigned CharNo, unsigned IndentCount) const {
  assert(!Matches.empty() && "Must have at least one string to match!");
  std::string Indent(IndentCount*2+4, ' ');

  // If we have verified that the entire string matches, we're done: output the
  // matching code.
  if (CharNo == Matches[0]->first.size()) {
    assert(Matches.size() == 1 && "Had duplicate keys to match on");

    // If the to-execute code has \n's in it, indent each subsequent line.
    StringRef Code = Matches[0]->second;

    std::pair<StringRef, StringRef> Split = Code.split('\n');
    OS << Indent << Split.first << "\t // \"" << Matches[0]->first << "\"\n";

    Code = Split.second;
    while (!Code.empty()) {
      Split = Code.split('\n');
      OS << Indent << Split.first << "\n";
      Code = Split.second;
    }
    return false;
  }

  // Bucket the matches by the character we are comparing.
  std::map<char, std::vector<const StringPair*> > MatchesByLetter;

  for (unsigned i = 0, e = Matches.size(); i != e; ++i)
    MatchesByLetter[Matches[i]->first[CharNo]].push_back(Matches[i]);

  // If we have exactly one bucket to match, see how many characters are common
  // across the whole set and match all of them at once.
  if (MatchesByLetter.size() == 1) {
    unsigned FirstNonCommonLetter = FindFirstNonCommonLetter(Matches);
    unsigned NumChars = FirstNonCommonLetter-CharNo;

    // Emit code to break out if the prefix doesn't match.
    if (NumChars == 1) {
      // Do the comparison with if (Str[1] != 'f')
      // FIXME: Need to escape general characters.
      OS << Indent << "if (" << StrVariableName << "[" << CharNo << "] != '"
      << Matches[0]->first[CharNo] << "')\n";
      OS << Indent << "  break;\n";
    } else {
      // Do the comparison with if memcmp(Str.data()+1, "foo", 3).
      // FIXME: Need to escape general strings.
      OS << Indent << "if (memcmp(" << StrVariableName << ".data()+" << CharNo
         << ", \"" << Matches[0]->first.substr(CharNo, NumChars) << "\", "
         << NumChars << "))\n";
      OS << Indent << "  break;\n";
    }

    return EmitStringMatcherForChar(Matches, FirstNonCommonLetter, IndentCount);
  }

  // Otherwise, we have multiple possible things, emit a switch on the
  // character.
  OS << Indent << "switch (" << StrVariableName << "[" << CharNo << "]) {\n";
  OS << Indent << "default: break;\n";

  for (std::map<char, std::vector<const StringPair*> >::iterator LI =
       MatchesByLetter.begin(), E = MatchesByLetter.end(); LI != E; ++LI) {
    // TODO: escape hard stuff (like \n) if we ever care about it.
    OS << Indent << "case '" << LI->first << "':\t // "
       << LI->second.size() << " string";
    if (LI->second.size() != 1) OS << 's';
    OS << " to match.\n";
    if (EmitStringMatcherForChar(LI->second, CharNo+1, IndentCount+1))
      OS << Indent << "  break;\n";
  }

  OS << Indent << "}\n";
  return true;
}

/// Emit - Top level entry point.
///
void StringMatcher::Emit(unsigned Indent) const {
  // If nothing to match, just fall through.
  if (Matches.empty()) return;

  // First level categorization: group strings by length.
  std::map<unsigned, std::vector<const StringPair*> > MatchesByLength;

  for (unsigned i = 0, e = Matches.size(); i != e; ++i)
    MatchesByLength[Matches[i].first.size()].push_back(&Matches[i]);

  // Output a switch statement on length and categorize the elements within each
  // bin.
  OS.indent(Indent*2+2) << "switch (" << StrVariableName << ".size()) {\n";
  OS.indent(Indent*2+2) << "default: break;\n";

  for (std::map<unsigned, std::vector<const StringPair*> >::iterator LI =
       MatchesByLength.begin(), E = MatchesByLength.end(); LI != E; ++LI) {
    OS.indent(Indent*2+2) << "case " << LI->first << ":\t // "
       << LI->second.size()
       << " string" << (LI->second.size() == 1 ? "" : "s") << " to match.\n";
    if (EmitStringMatcherForChar(LI->second, 0, Indent))
      OS.indent(Indent*2+4) << "break;\n";
  }

  OS.indent(Indent*2+2) << "}\n";
}
<|endoftext|>


<commit_before>#include "igl/random_points_on_mesh.h"
#include "igl/AABB.h"

#include "SLAAutoSupports.hpp"
#include "Model.hpp"

#include <iostream>

namespace Slic3r {

SLAAutoSupports::SLAAutoSupports(ModelObject& mo, const SLAAutoSupports::Config& c)
: m_model_object(mo), mesh(), m_config(c)
{}

float SLAAutoSupports::approximate_geodesic_distance(const Vec3f& p1, const Vec3f& p2, Vec3f& n1, Vec3f& n2)
{
    n1.normalize();
    n2.normalize();

    Vec3f v = (p2-p1);
    v.normalize();

    float c1 = n1.dot(v);
    float c2 = n2.dot(v);
    float result = pow(p1(0)-p2(0), 2) + pow(p1(1)-p2(1), 2) + pow(p1(2)-p2(2), 2);
    // Check for division by zero:
    if(fabs(c1 - c2) > 0.0001)
        result *= (asin(c1) - asin(c2)) / (c1 - c2);
    return result;
}

void SLAAutoSupports::generate()
{
    // Loads the ModelObject raw_mesh and transforms it by first instance's transformation matrix (disregarding translation).
    // Instances only differ in z-rotation, so it does not matter which of them will be used for the calculation.
    // The supports point will be calculated on this mesh (so scaling ang vertical direction is correctly accounted for).
    // Results will be inverse-transformed to raw_mesh coordinates.
    TriangleMesh mesh = m_model_object.raw_mesh();
    Transform3d transformation_matrix = m_model_object.instances[0]->get_matrix(true/*dont_translate*/);
    mesh.transform(transformation_matrix);

    // Check that the object is thick enough to produce any support points
    BoundingBoxf3 bb = mesh.bounding_box();
    if (bb.size()(2) < m_config.minimal_z)
        return;

    // All points that we curretly have must be transformed too, so distance to them is correcly calculated.
    for (Vec3f& point : m_model_object.sla_support_points)
        point = transformation_matrix.cast<float>() * point;

    const stl_file& stl = mesh.stl;
    Eigen::MatrixXf V;
    Eigen::MatrixXi F;
    V.resize(3 * stl.stats.number_of_facets, 3);
    F.resize(stl.stats.number_of_facets, 3);
    for (unsigned int i=0; i<stl.stats.number_of_facets; ++i) {
        const stl_facet* facet = stl.facet_start+i;
        V(3*i+0, 0) = facet->vertex[0](0); V(3*i+0, 1) = facet->vertex[0](1); V(3*i+0, 2) = facet->vertex[0](2);
        V(3*i+1, 0) = facet->vertex[1](0); V(3*i+1, 1) = facet->vertex[1](1); V(3*i+1, 2) = facet->vertex[1](2);
        V(3*i+2, 0) = facet->vertex[2](0); V(3*i+2, 1) = facet->vertex[2](1); V(3*i+2, 2) = facet->vertex[2](2);
        F(i, 0) = 3*i+0;
        F(i, 1) = 3*i+1;
        F(i, 2) = 3*i+2;
    }

    // In order to calculate distance to already placed points, we must keep know which facet the point lies on.
    std::vector<Vec3f> facets_normals;

    // The AABB hierarchy will be used to find normals of already placed points.
    // The points added automatically will just push_back the new normal on the fly.
    igl::AABB<Eigen::MatrixXf,3> aabb;
    aabb.init(V, F);
    for (unsigned int i=0; i<m_model_object.sla_support_points.size(); ++i) {
        int facet_idx = 0;
        Eigen::Matrix<float, 1, 3> dump;
        Eigen::MatrixXf query_point = m_model_object.sla_support_points[i];
        aabb.squared_distance(V, F, query_point, facet_idx, dump);
        Vec3f a1 = V.row(F(facet_idx,1)) - V.row(F(facet_idx,0));
        Vec3f a2 = V.row(F(facet_idx,2)) - V.row(F(facet_idx,0));
        Vec3f normal = a1.cross(a2);
        normal.normalize();
        facets_normals.push_back(normal);
    }

    // New potential support point is randomly generated on the mesh and distance to all already placed points is calculated.
    // In case it is never smaller than certain limit (depends on the new point's facet normal), the point is accepted.
    // The process stops after certain number of points is refused in a row.
    Vec3f point;
    Vec3f normal;
    int added_points = 0;
    int refused_points = 0;
    const int refused_limit = 30;
    // Angle at which the density reaches zero:
    const float threshold_angle = std::min(M_PI_2, M_PI_4 * acos(0.f/m_config.density_at_horizontal) / acos(m_config.density_at_45/m_config.density_at_horizontal));

    srand(time(NULL)); // rand() is used by igl::random_point_on_mesh
    while (refused_points < refused_limit) {
        // Place a random point on the mesh and calculate corresponding facet's normal:
        Eigen::VectorXi FI;
        Eigen::MatrixXf B;
        igl::random_points_on_mesh(1, V, F, B, FI);
        point = B(0,0)*V.row(F(FI(0),0)) +
                B(0,1)*V.row(F(FI(0),1)) +
                B(0,2)*V.row(F(FI(0),2));
        if (point(2) - bb.min(2) < m_config.minimal_z)
            continue;

        Vec3f a1 = V.row(F(FI(0),1)) - V.row(F(FI(0),0));
        Vec3f a2 = V.row(F(FI(0),2)) - V.row(F(FI(0),0));
        normal = a1.cross(a2);
        normal.normalize();

        // calculate angle between the normal and vertical:
        float angle = angle_from_normal(normal);
        if (angle > threshold_angle)
            continue;

        const float distance_limit = 1./(2.4*get_required_density(angle));
        bool add_it = true;
        for (unsigned int i=0; i<m_model_object.sla_support_points.size(); ++i) {
            if (approximate_geodesic_distance(m_model_object.sla_support_points[i], point, facets_normals[i], normal) < distance_limit) {
                add_it = false;
                ++refused_points;
                break;
            }
        }
        if (add_it) {
            m_model_object.sla_support_points.push_back(point);
            facets_normals.push_back(normal);
            ++added_points;
            refused_points = 0;
        }
    }

    // Now transform all support points to mesh coordinates:
    for (Vec3f& point : m_model_object.sla_support_points)
        point = transformation_matrix.inverse().cast<float>() * point;
}

float SLAAutoSupports::get_required_density(float angle) const
{
    // calculation would be density_0 * cos(angle). To provide one more degree of freedom, we will scale the angle
    // to get the user-set density for 45 deg. So it ends up as density_0 * cos(K * angle).
    float K = 4*acos(m_config.density_at_45/m_config.density_at_horizontal) / M_PI;
    return std::max(0., m_config.density_at_horizontal * cos(K*angle));
}

} // namespace Slic3r<commit_msg>Fix of a visual studio compilation issue.<commit_after>#include "igl/random_points_on_mesh.h"
#include "igl/AABB.h"

#include "SLAAutoSupports.hpp"
#include "Model.hpp"

#include <iostream>

namespace Slic3r {

SLAAutoSupports::SLAAutoSupports(ModelObject& mo, const SLAAutoSupports::Config& c)
: m_model_object(mo), mesh(), m_config(c)
{}

float SLAAutoSupports::approximate_geodesic_distance(const Vec3f& p1, const Vec3f& p2, Vec3f& n1, Vec3f& n2)
{
    n1.normalize();
    n2.normalize();

    Vec3f v = (p2-p1);
    v.normalize();

    float c1 = n1.dot(v);
    float c2 = n2.dot(v);
    float result = pow(p1(0)-p2(0), 2) + pow(p1(1)-p2(1), 2) + pow(p1(2)-p2(2), 2);
    // Check for division by zero:
    if(fabs(c1 - c2) > 0.0001)
        result *= (asin(c1) - asin(c2)) / (c1 - c2);
    return result;
}

void SLAAutoSupports::generate()
{
    // Loads the ModelObject raw_mesh and transforms it by first instance's transformation matrix (disregarding translation).
    // Instances only differ in z-rotation, so it does not matter which of them will be used for the calculation.
    // The supports point will be calculated on this mesh (so scaling ang vertical direction is correctly accounted for).
    // Results will be inverse-transformed to raw_mesh coordinates.
    TriangleMesh mesh = m_model_object.raw_mesh();
    Transform3d transformation_matrix = m_model_object.instances[0]->get_matrix(true/*dont_translate*/);
    mesh.transform(transformation_matrix);

    // Check that the object is thick enough to produce any support points
    BoundingBoxf3 bb = mesh.bounding_box();
    if (bb.size()(2) < m_config.minimal_z)
        return;

    // All points that we curretly have must be transformed too, so distance to them is correcly calculated.
    for (Vec3f& point : m_model_object.sla_support_points)
        point = transformation_matrix.cast<float>() * point;

    const stl_file& stl = mesh.stl;
    Eigen::MatrixXf V;
    Eigen::MatrixXi F;
    V.resize(3 * stl.stats.number_of_facets, 3);
    F.resize(stl.stats.number_of_facets, 3);
    for (unsigned int i=0; i<stl.stats.number_of_facets; ++i) {
        const stl_facet* facet = stl.facet_start+i;
        V(3*i+0, 0) = facet->vertex[0](0); V(3*i+0, 1) = facet->vertex[0](1); V(3*i+0, 2) = facet->vertex[0](2);
        V(3*i+1, 0) = facet->vertex[1](0); V(3*i+1, 1) = facet->vertex[1](1); V(3*i+1, 2) = facet->vertex[1](2);
        V(3*i+2, 0) = facet->vertex[2](0); V(3*i+2, 1) = facet->vertex[2](1); V(3*i+2, 2) = facet->vertex[2](2);
        F(i, 0) = 3*i+0;
        F(i, 1) = 3*i+1;
        F(i, 2) = 3*i+2;
    }

    // In order to calculate distance to already placed points, we must keep know which facet the point lies on.
    std::vector<Vec3f> facets_normals;

    // The AABB hierarchy will be used to find normals of already placed points.
    // The points added automatically will just push_back the new normal on the fly.
    igl::AABB<Eigen::MatrixXf,3> aabb;
    aabb.init(V, F);
    for (unsigned int i=0; i<m_model_object.sla_support_points.size(); ++i) {
        int facet_idx = 0;
        Eigen::Matrix<float, 1, 3> dump;
        Eigen::MatrixXf query_point = m_model_object.sla_support_points[i];
        aabb.squared_distance(V, F, query_point, facet_idx, dump);
        Vec3f a1 = V.row(F(facet_idx,1)) - V.row(F(facet_idx,0));
        Vec3f a2 = V.row(F(facet_idx,2)) - V.row(F(facet_idx,0));
        Vec3f normal = a1.cross(a2);
        normal.normalize();
        facets_normals.push_back(normal);
    }

    // New potential support point is randomly generated on the mesh and distance to all already placed points is calculated.
    // In case it is never smaller than certain limit (depends on the new point's facet normal), the point is accepted.
    // The process stops after certain number of points is refused in a row.
    Vec3f point;
    Vec3f normal;
    int added_points = 0;
    int refused_points = 0;
    const int refused_limit = 30;
    // Angle at which the density reaches zero:
    const float threshold_angle = std::min(M_PI_2, M_PI_4 * acos(0.f/m_config.density_at_horizontal) / acos(m_config.density_at_45/m_config.density_at_horizontal));

    srand(time(NULL)); // rand() is used by igl::random_point_on_mesh
    while (refused_points < refused_limit) {
        // Place a random point on the mesh and calculate corresponding facet's normal:
        Eigen::VectorXi FI;
        Eigen::MatrixXf B;
        igl::random_points_on_mesh(1, V, F, B, FI);
        point = B(0,0)*V.row(F(FI(0),0)) +
                B(0,1)*V.row(F(FI(0),1)) +
                B(0,2)*V.row(F(FI(0),2));
        if (point(2) - bb.min(2) < m_config.minimal_z)
            continue;

        Vec3f a1 = V.row(F(FI(0),1)) - V.row(F(FI(0),0));
        Vec3f a2 = V.row(F(FI(0),2)) - V.row(F(FI(0),0));
        normal = a1.cross(a2);
        normal.normalize();

        // calculate angle between the normal and vertical:
        float angle = angle_from_normal(normal);
        if (angle > threshold_angle)
            continue;

        const float distance_limit = 1./(2.4*get_required_density(angle));
        bool add_it = true;
        for (unsigned int i=0; i<m_model_object.sla_support_points.size(); ++i) {
            if (approximate_geodesic_distance(m_model_object.sla_support_points[i], point, facets_normals[i], normal) < distance_limit) {
                add_it = false;
                ++refused_points;
                break;
            }
        }
        if (add_it) {
            m_model_object.sla_support_points.push_back(point);
            facets_normals.push_back(normal);
            ++added_points;
            refused_points = 0;
        }
    }

    // Now transform all support points to mesh coordinates:
    for (Vec3f& point : m_model_object.sla_support_points)
        point = transformation_matrix.inverse().cast<float>() * point;
}

float SLAAutoSupports::get_required_density(float angle) const
{
    // calculation would be density_0 * cos(angle). To provide one more degree of freedom, we will scale the angle
    // to get the user-set density for 45 deg. So it ends up as density_0 * cos(K * angle).
    float K = 4.f * float(acos(m_config.density_at_45/m_config.density_at_horizontal) / M_PI);
    return std::max(0.f, float(m_config.density_at_horizontal * cos(K*angle)));
}

} // namespace Slic3r<|endoftext|>


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

namespace np {
using namespace std;
using namespace np::util;

/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/

void
junit_listener_t::begin()
{
}

string
junit_listener_t::get_hostname() const
{
    char hostname[1024];
    int r = gethostname(hostname, sizeof(hostname));
    return (r < 0 ? string("localhost") : string(hostname));
}

void
junit_listener_t::end()
{
    string hostname = get_hostname();
    string timestamp = abs_format_iso8601(abs_now());

    map<string, suite_t>::iterator sitr;
    for (sitr = suites_.begin() ; sitr != suites_.end() ; ++sitr)
    {
	const string &suitename = sitr->first;
	suite_t *s = &sitr->second;

	xmlpp::Document *xdoc = new xmlpp::Document();
	// If only there were a standard DTD URL...
	// instead we have a Schema from
	// http://windyroad.org/dl/OpenSource/JUnit.xsd
	xmlpp::Element *xsuite = xdoc->create_root_node("testsuite");
	xsuite->set_attribute("name", suitename);
	xsuite->set_attribute("failures", "0");
	xsuite->set_attribute("tests", dec(s->cases_.size()));
	xsuite->set_attribute("hostname", hostname);
	xsuite->set_attribute("timestamp", timestamp);

	xsuite->add_child("properties");

	unsigned int nerrs = 0;
	int64_t sns = 0;
	map<string, case_t>::iterator citr;
	for (citr = s->cases_.begin() ; citr != s->cases_.end() ; ++citr)
	{
	    const string &casename = citr->first;
	    case_t *c = &citr->second;

	    xmlpp::Element *xcase = xsuite->add_child("testcase");
	    xcase->set_attribute("name", casename);
	    // TODO: this is wrong
	    xcase->set_attribute("classname", casename);

	    sns += c->elapsed_;
	    xcase->set_attribute("time", rel_format(c->elapsed_));

	    if (c->event_)
	    {
		event_t *e = c->event_;
		xmlpp::Element *xerror = xcase->add_child("error");
		xerror->set_attribute("type", e->which_as_string());
		xerror->set_attribute("message", e->description);
		xerror->add_child_text(e->as_string() +
				       "\n" +
				       e->get_long_location());
	    }
	    if (c->result_ == R_FAIL)
		nerrs++;
	}
	xsuite->set_attribute("errors", dec(nerrs));
	xsuite->set_attribute("time", rel_format(sns));

	xsuite->add_child("system-out");
	xsuite->add_child("system-err");

	string filename = string("reports/TEST-") + suitename + ".xml";

	// TODO: mkdir
	try
	{
	    xdoc->write_to_file(filename, "UTF-8");
	}
	catch (const xmlpp::exception& ex)
	{
	    fprintf(stderr, "np: caught xmlpp exception writing file %s: %s\n",
		    filename.c_str(), ex.what());
	}
	delete xdoc;
    }
}

junit_listener_t::case_t *
junit_listener_t::find_case(const job_t *j)
{
    string suitename = j->get_node()->get_parent()->get_fullname();

    string jobname = j->as_string();
    int off = jobname.find(suitename);
    string casename(jobname, off+suitename.length()+1);

    return &suites_[suitename].cases_[casename];
}

void
junit_listener_t::begin_job(const job_t *j __attribute__((unused)))
{
}

void
junit_listener_t::end_job(const job_t *j, result_t res)
{
    case_t *c = find_case(j);
    c->result_ = res;
    c->elapsed_ = j->get_elapsed();
}

void
junit_listener_t::add_event(const job_t *j, const event_t *ev)
{
    case_t *c = find_case(j);
    if (ev->get_result() == R_FAIL && !c->event_)
	c->event_ = ev->clone();
}

// close the namespace
};
<commit_msg>Automatically build the JUnit reports/ directory<commit_after>/*
 * Copyright 2011-2012 Gregory Banks
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#include "np/util/common.hxx"
#include <sys/stat.h>
#include <libxml++/document.h>
#include "np/junit_listener.hxx"
#include "np/job.hxx"
#include "except.h"

namespace np {
using namespace std;
using namespace np::util;

/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/

void
junit_listener_t::begin()
{
}

string
junit_listener_t::get_hostname() const
{
    char hostname[1024];
    int r = gethostname(hostname, sizeof(hostname));
    return (r < 0 ? string("localhost") : string(hostname));
}

void
junit_listener_t::end()
{
    string hostname = get_hostname();
    string timestamp = abs_format_iso8601(abs_now());

    // TODO: mkdir_p
    string directory = "reports";
    int r = mkdir(directory.c_str(), 0777);
    if (r < 0 && errno != EEXIST)
    {
	fprintf(stderr, "np: cannot make directory %s: %s\n",
		directory.c_str(), strerror(errno));
	return;
    }

    map<string, suite_t>::iterator sitr;
    for (sitr = suites_.begin() ; sitr != suites_.end() ; ++sitr)
    {
	const string &suitename = sitr->first;
	suite_t *s = &sitr->second;

	xmlpp::Document *xdoc = new xmlpp::Document();
	// If only there were a standard DTD URL...
	// instead we have a Schema from
	// http://windyroad.org/dl/OpenSource/JUnit.xsd
	xmlpp::Element *xsuite = xdoc->create_root_node("testsuite");
	xsuite->set_attribute("name", suitename);
	xsuite->set_attribute("failures", "0");
	xsuite->set_attribute("tests", dec(s->cases_.size()));
	xsuite->set_attribute("hostname", hostname);
	xsuite->set_attribute("timestamp", timestamp);

	xsuite->add_child("properties");

	unsigned int nerrs = 0;
	int64_t sns = 0;
	map<string, case_t>::iterator citr;
	for (citr = s->cases_.begin() ; citr != s->cases_.end() ; ++citr)
	{
	    const string &casename = citr->first;
	    case_t *c = &citr->second;

	    xmlpp::Element *xcase = xsuite->add_child("testcase");
	    xcase->set_attribute("name", casename);
	    // TODO: this is wrong
	    xcase->set_attribute("classname", casename);

	    sns += c->elapsed_;
	    xcase->set_attribute("time", rel_format(c->elapsed_));

	    if (c->event_)
	    {
		event_t *e = c->event_;
		xmlpp::Element *xerror = xcase->add_child("error");
		xerror->set_attribute("type", e->which_as_string());
		xerror->set_attribute("message", e->description);
		xerror->add_child_text(e->as_string() +
				       "\n" +
				       e->get_long_location());
	    }
	    if (c->result_ == R_FAIL)
		nerrs++;
	}
	xsuite->set_attribute("errors", dec(nerrs));
	xsuite->set_attribute("time", rel_format(sns));

	xsuite->add_child("system-out");
	xsuite->add_child("system-err");

	string filename = directory + string("/TEST-") + suitename + ".xml";

	try
	{
	    xdoc->write_to_file(filename, "UTF-8");
	}
	catch (const xmlpp::exception& ex)
	{
	    fprintf(stderr, "np: caught xmlpp exception writing file %s: %s\n",
		    filename.c_str(), ex.what());
	}
	delete xdoc;
    }
}

junit_listener_t::case_t *
junit_listener_t::find_case(const job_t *j)
{
    string suitename = j->get_node()->get_parent()->get_fullname();

    string jobname = j->as_string();
    int off = jobname.find(suitename);
    string casename(jobname, off+suitename.length()+1);

    return &suites_[suitename].cases_[casename];
}

void
junit_listener_t::begin_job(const job_t *j __attribute__((unused)))
{
}

void
junit_listener_t::end_job(const job_t *j, result_t res)
{
    case_t *c = find_case(j);
    c->result_ = res;
    c->elapsed_ = j->get_elapsed();
}

void
junit_listener_t::add_event(const job_t *j, const event_t *ev)
{
    case_t *c = find_case(j);
    if (ev->get_result() == R_FAIL && !c->event_)
	c->event_ = ev->clone();
}

// close the namespace
};
<|endoftext|>


<commit_before>// ------------------------------------------------------------------------
// eca-preset-map: Dynamic register for storing effect presets
// Copyright (C) 2000,2001 Kai Vehmanen (kai.vehmanen@wakkanet.fi)
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
// ------------------------------------------------------------------------

#include <algorithm>
#include <list>
#include <vector>
#include <string>

#include <kvutils/dbc.h>

#include "eca-object.h"
#include "eca-resources.h"
#include "eca-preset-map.h"
#include "global-preset.h"

using std::map;
using std::string;
using std::list;
using std::vector;

ECA_PRESET_MAP::ECA_PRESET_MAP(void) {
  ECA_RESOURCES ecarc;

  string filename =
    ecarc.resource("user-resource-directory") + "/" + ecarc.resource("resource-file-effect-presets");
  string global_filename =
    ecarc.resource("resource-directory") + "/" + ecarc.resource("resource-file-effect-presets");

  load_preset_file(global_filename);
  load_preset_file(filename);
}

void ECA_PRESET_MAP::load_preset_file(const string& fname) {
  RESOURCE_FILE preset_file;
  preset_file.resource_file(fname);
  preset_file.load();
  const vector<string>& pmap = preset_file.keywords();
  vector<string>::const_iterator p = pmap.begin();
  while(p != pmap.end()) {
    preset_keywords_rep.push_back(*p);
    ++p;
  }
}

void ECA_PRESET_MAP::register_object(const string& keyword, const string& matchstr, PRESET* object) {
  if (find(preset_keywords_rep.begin(), preset_keywords_rep.end(), keyword) == preset_keywords_rep.end())
    preset_keywords_rep.push_back(keyword);

  ECA_OBJECT_MAP::register_object(keyword, matchstr, object);
}

void ECA_PRESET_MAP::unregister_object(const string& keyword) {
  preset_keywords_rep.remove(keyword);
  ECA_OBJECT_MAP::unregister_object(keyword);
}

const list<string>& ECA_PRESET_MAP::registered_objects(void) const {
  return(preset_keywords_rep);
}

bool ECA_PRESET_MAP::has_keyword(const std::string& keyword) const {
  if (find(preset_keywords_rep.begin(), preset_keywords_rep.end(), keyword) == preset_keywords_rep.end())
    return(false);

  return (true);
}

const ECA_OBJECT* ECA_PRESET_MAP::object_expr(const string& expr) const {
  if (find(preset_keywords_rep.begin(), preset_keywords_rep.end(), expr) != preset_keywords_rep.end()) {
    return(object(expr));
  }
  return(0);
}

const ECA_OBJECT* ECA_PRESET_MAP::object(const string& keyword) const {
  const PRESET* retobj = 0;

  if (find(preset_keywords_rep.begin(), preset_keywords_rep.end(), keyword) != preset_keywords_rep.end()) {
    const list<string>& objlist = ECA_OBJECT_MAP::registered_objects();

    if (find(objlist.begin(), objlist.end(), keyword) == objlist.end()) {
      try {
	PRESET* obj = dynamic_cast<const PRESET*>(new GLOBAL_PRESET(keyword));
	if (obj != 0) {
	  const_cast<ECA_PRESET_MAP*>(this)->register_object(keyword, "^" + keyword + "$", obj);
	  retobj = obj;
	  //  std::cerr << "(eca-preset-map) registering obj; " << keyword << ".\n";
	}
	//  else std::cerr << "(eca-preset-map) fail (3); " << keyword << ".\n";

      }
      catch(...) { retobj = 0; }

      DBC_CHECK(find(objlist.begin(), objlist.end(), keyword) != objlist.end());
    }
    else {
      retobj = dynamic_cast<const PRESET*>(ECA_OBJECT_MAP::object(keyword));
      //  if (retobj == 0) std::cerr << "(eca-preset-map) fail (2); " << keyword << ".\n";
    }
  }
  //  else std::cerr << "(eca-preset-map) fail (1); " << keyword << ".\n";

  return(retobj);
}
<commit_msg>Fix to preset map compiling.<commit_after>// ------------------------------------------------------------------------
// eca-preset-map: Dynamic register for storing effect presets
// Copyright (C) 2000,2001 Kai Vehmanen (kai.vehmanen@wakkanet.fi)
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
// ------------------------------------------------------------------------

#include <algorithm>
#include <list>
#include <vector>
#include <string>

#include <kvutils/dbc.h>

#include "eca-object.h"
#include "eca-resources.h"
#include "eca-preset-map.h"
#include "global-preset.h"

using std::map;
using std::string;
using std::list;
using std::vector;

ECA_PRESET_MAP::ECA_PRESET_MAP(void) {
  ECA_RESOURCES ecarc;

  string filename =
    ecarc.resource("user-resource-directory") + "/" + ecarc.resource("resource-file-effect-presets");
  string global_filename =
    ecarc.resource("resource-directory") + "/" + ecarc.resource("resource-file-effect-presets");

  load_preset_file(global_filename);
  load_preset_file(filename);
}

void ECA_PRESET_MAP::load_preset_file(const string& fname) {
  RESOURCE_FILE preset_file;
  preset_file.resource_file(fname);
  preset_file.load();
  const vector<string>& pmap = preset_file.keywords();
  vector<string>::const_iterator p = pmap.begin();
  while(p != pmap.end()) {
    preset_keywords_rep.push_back(*p);
    ++p;
  }
}

void ECA_PRESET_MAP::register_object(const string& keyword, const string& matchstr, PRESET* object) {
  if (find(preset_keywords_rep.begin(), preset_keywords_rep.end(), keyword) == preset_keywords_rep.end())
    preset_keywords_rep.push_back(keyword);

  ECA_OBJECT_MAP::register_object(keyword, matchstr, object);
}

void ECA_PRESET_MAP::unregister_object(const string& keyword) {
  preset_keywords_rep.remove(keyword);
  ECA_OBJECT_MAP::unregister_object(keyword);
}

const list<string>& ECA_PRESET_MAP::registered_objects(void) const {
  return(preset_keywords_rep);
}

bool ECA_PRESET_MAP::has_keyword(const std::string& keyword) const {
  if (find(preset_keywords_rep.begin(), preset_keywords_rep.end(), keyword) == preset_keywords_rep.end())
    return(false);

  return (true);
}

const ECA_OBJECT* ECA_PRESET_MAP::object_expr(const string& expr) const {
  if (find(preset_keywords_rep.begin(), preset_keywords_rep.end(), expr) != preset_keywords_rep.end()) {
    return(object(expr));
  }
  return(0);
}

const ECA_OBJECT* ECA_PRESET_MAP::object(const string& keyword) const {
  const PRESET* retobj = 0;

  if (find(preset_keywords_rep.begin(), preset_keywords_rep.end(), keyword) != preset_keywords_rep.end()) {
    const list<string>& objlist = ECA_OBJECT_MAP::registered_objects();

    if (find(objlist.begin(), objlist.end(), keyword) == objlist.end()) {
      try {
	PRESET* obj = dynamic_cast<PRESET*>(new GLOBAL_PRESET(keyword));
	if (obj != 0) {
	  const_cast<ECA_PRESET_MAP*>(this)->register_object(keyword, "^" + keyword + "$", obj);
	  retobj = obj;
	  //  std::cerr << "(eca-preset-map) registering obj; " << keyword << ".\n";
	}
	//  else std::cerr << "(eca-preset-map) fail (3); " << keyword << ".\n";

      }
      catch(...) { retobj = 0; }

      DBC_CHECK(find(objlist.begin(), objlist.end(), keyword) != objlist.end());
    }
    else {
      retobj = dynamic_cast<const PRESET*>(ECA_OBJECT_MAP::object(keyword));
      //  if (retobj == 0) std::cerr << "(eca-preset-map) fail (2); " << keyword << ".\n";
    }
  }
  //  else std::cerr << "(eca-preset-map) fail (1); " << keyword << ".\n";

  return(retobj);
}
<|endoftext|>


<commit_before>//===- PruneEH.cpp - Pass which deletes unused exception handlers ---------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements a simple interprocedural pass which walks the
// call-graph, turning invoke instructions into calls, iff the callee cannot
// throw an exception, and marking functions 'nounwind' if they cannot throw.
// It implements this as a bottom-up traversal of the call-graph.
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "prune-eh"
#include "llvm/Transforms/IPO.h"
#include "llvm/CallGraphSCCPass.h"
#include "llvm/Constants.h"
#include "llvm/Function.h"
#include "llvm/Instructions.h"
#include "llvm/Analysis/CallGraph.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Support/CFG.h"
#include "llvm/Support/Compiler.h"
#include <set>
#include <algorithm>
using namespace llvm;

STATISTIC(NumRemoved, "Number of invokes removed");
STATISTIC(NumUnreach, "Number of noreturn calls optimized");

namespace {
  struct VISIBILITY_HIDDEN PruneEH : public CallGraphSCCPass {
    static char ID; // Pass identification, replacement for typeid
    PruneEH() : CallGraphSCCPass((intptr_t)&ID) {}

    // runOnSCC - Analyze the SCC, performing the transformation if possible.
    bool runOnSCC(const std::vector<CallGraphNode *> &SCC);

    bool SimplifyFunction(Function *F);
    void DeleteBasicBlock(BasicBlock *BB);
  };

  char PruneEH::ID = 0;
  RegisterPass<PruneEH> X("prune-eh", "Remove unused exception handling info");
}

Pass *llvm::createPruneEHPass() { return new PruneEH(); }

bool PruneEH::runOnSCC(const std::vector<CallGraphNode *> &SCC) {
  CallGraph &CG = getAnalysis<CallGraph>();
  bool MadeChange = false;

  // First pass, scan all of the functions in the SCC, simplifying them
  // according to what we know.
  for (unsigned i = 0, e = SCC.size(); i != e; ++i)
    if (Function *F = SCC[i]->getFunction())
      MadeChange |= SimplifyFunction(F);

  // Next, check to see if any callees might throw or if there are any external
  // functions in this SCC: if so, we cannot prune any functions in this SCC.
  // If this SCC includes the unwind instruction, we KNOW it throws, so
  // obviously the SCC might throw.
  //
  bool SCCMightUnwind = false, SCCMightReturn = false;
  for (unsigned i = 0, e = SCC.size();
       (!SCCMightUnwind || !SCCMightReturn) && i != e; ++i) {
    Function *F = SCC[i]->getFunction();
    if (F == 0) {
      SCCMightUnwind = true;
      SCCMightReturn = true;
    } else if (F->isDeclaration()) {
      SCCMightUnwind |= !F->doesNotThrow();
      SCCMightReturn |= !F->doesNotReturn();
    } else {
      bool CheckUnwind = !SCCMightUnwind && !F->doesNotThrow();
      bool CheckReturn = !SCCMightReturn && !F->doesNotReturn();

      if (!CheckUnwind && !CheckReturn)
        continue;

      // Check to see if this function performs an unwind or calls an
      // unwinding function.
      for (Function::iterator BB = F->begin(), E = F->end(); BB != E; ++BB) {
        if (CheckUnwind && isa<UnwindInst>(BB->getTerminator())) {
          // Uses unwind!
          SCCMightUnwind = true;
        } else if (CheckReturn && isa<ReturnInst>(BB->getTerminator())) {
          SCCMightReturn = true;
        }

        // Invoke instructions don't allow unwinding to continue, so we are
        // only interested in call instructions.
        if (CheckUnwind && !SCCMightUnwind)
          for (BasicBlock::iterator I = BB->begin(), E = BB->end(); I != E; ++I)
            if (CallInst *CI = dyn_cast<CallInst>(I)) {
              if (CI->doesNotThrow()) {
                // This call cannot throw.
              } else if (Function *Callee = CI->getCalledFunction()) {
                CallGraphNode *CalleeNode = CG[Callee];
                // If the callee is outside our current SCC then we may
                // throw because it might.
                if (std::find(SCC.begin(), SCC.end(), CalleeNode) == SCC.end()){
                  SCCMightUnwind = true;
                  break;
                }
              } else {
                // Indirect call, it might throw.
                SCCMightUnwind = true;
                break;
              }
            }
        if (SCCMightUnwind && SCCMightReturn) break;
      }
    }
  }

  // If the SCC doesn't unwind or doesn't throw, note this fact.
  if (!SCCMightUnwind || !SCCMightReturn)
    for (unsigned i = 0, e = SCC.size(); i != e; ++i) {
      uint16_t NewAttributes = ParamAttr::None;

      if (!SCCMightUnwind)
        NewAttributes |= ParamAttr::NoUnwind;
      if (!SCCMightReturn)
        NewAttributes |= ParamAttr::NoReturn;

      const ParamAttrsList *PAL = SCC[i]->getFunction()->getParamAttrs();
      PAL = ParamAttrsList::includeAttrs(PAL, 0, NewAttributes);
      SCC[i]->getFunction()->setParamAttrs(PAL);
    }

  for (unsigned i = 0, e = SCC.size(); i != e; ++i) {
    // Convert any invoke instructions to non-throwing functions in this node
    // into call instructions with a branch.  This makes the exception blocks
    // dead.
    if (Function *F = SCC[i]->getFunction())
      MadeChange |= SimplifyFunction(F);
  }

  return MadeChange;
}

// SimplifyFunction - Given information about callees, simplify the specified
// function if we have invokes to non-unwinding functions or code after calls to
// no-return functions.
bool PruneEH::SimplifyFunction(Function *F) {
  bool MadeChange = false;
  for (Function::iterator BB = F->begin(), E = F->end(); BB != E; ++BB) {
    if (InvokeInst *II = dyn_cast<InvokeInst>(BB->getTerminator()))
      if (II->doesNotThrow()) {
        SmallVector<Value*, 8> Args(II->op_begin()+3, II->op_end());
        // Insert a call instruction before the invoke.
        CallInst *Call = new CallInst(II->getCalledValue(),
                                      Args.begin(), Args.end(), "", II);
        Call->takeName(II);
        Call->setCallingConv(II->getCallingConv());
        Call->setParamAttrs(II->getParamAttrs());

        // Anything that used the value produced by the invoke instruction
        // now uses the value produced by the call instruction.
        II->replaceAllUsesWith(Call);
        BasicBlock *UnwindBlock = II->getUnwindDest();
        UnwindBlock->removePredecessor(II->getParent());

        // Insert a branch to the normal destination right before the
        // invoke.
        new BranchInst(II->getNormalDest(), II);

        // Finally, delete the invoke instruction!
        BB->getInstList().pop_back();

        // If the unwind block is now dead, nuke it.
        if (pred_begin(UnwindBlock) == pred_end(UnwindBlock))
          DeleteBasicBlock(UnwindBlock);  // Delete the new BB.

        ++NumRemoved;
        MadeChange = true;
      }

    for (BasicBlock::iterator I = BB->begin(), E = BB->end(); I != E; )
      if (CallInst *CI = dyn_cast<CallInst>(I++))
        if (CI->doesNotReturn() && !isa<UnreachableInst>(I)) {
          // This call calls a function that cannot return.  Insert an
          // unreachable instruction after it and simplify the code.  Do this
          // by splitting the BB, adding the unreachable, then deleting the
          // new BB.
          BasicBlock *New = BB->splitBasicBlock(I);

          // Remove the uncond branch and add an unreachable.
          BB->getInstList().pop_back();
          new UnreachableInst(BB);

          DeleteBasicBlock(New);  // Delete the new BB.
          MadeChange = true;
          ++NumUnreach;
          break;
        }

  }
  return MadeChange;
}

/// DeleteBasicBlock - remove the specified basic block from the program,
/// updating the callgraph to reflect any now-obsolete edges due to calls that
/// exist in the BB.
void PruneEH::DeleteBasicBlock(BasicBlock *BB) {
  assert(pred_begin(BB) == pred_end(BB) && "BB is not dead!");
  CallGraph &CG = getAnalysis<CallGraph>();

  CallGraphNode *CGN = CG[BB->getParent()];
  for (BasicBlock::iterator I = BB->end(), E = BB->begin(); I != E; ) {
    --I;
    if (CallInst *CI = dyn_cast<CallInst>(I)) {
      if (Function *Callee = CI->getCalledFunction())
        CGN->removeCallEdgeTo(CG[Callee]);
    } else if (InvokeInst *II = dyn_cast<InvokeInst>(I)) {
      if (Function *Callee = II->getCalledFunction())
        CGN->removeCallEdgeTo(CG[Callee]);
    }
    if (!I->use_empty())
      I->replaceAllUsesWith(UndefValue::get(I->getType()));
  }

  // Get the list of successors of this block.
  std::vector<BasicBlock*> Succs(succ_begin(BB), succ_end(BB));

  for (unsigned i = 0, e = Succs.size(); i != e; ++i)
    Succs[i]->removePredecessor(BB);

  BB->eraseFromParent();
}
<commit_msg>add missing #include<commit_after>//===- PruneEH.cpp - Pass which deletes unused exception handlers ---------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements a simple interprocedural pass which walks the
// call-graph, turning invoke instructions into calls, iff the callee cannot
// throw an exception, and marking functions 'nounwind' if they cannot throw.
// It implements this as a bottom-up traversal of the call-graph.
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "prune-eh"
#include "llvm/Transforms/IPO.h"
#include "llvm/CallGraphSCCPass.h"
#include "llvm/Constants.h"
#include "llvm/Function.h"
#include "llvm/Instructions.h"
#include "llvm/Analysis/CallGraph.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Support/CFG.h"
#include "llvm/Support/Compiler.h"
#include "llvm/ParameterAttributes.h"
#include <set>
#include <algorithm>
using namespace llvm;

STATISTIC(NumRemoved, "Number of invokes removed");
STATISTIC(NumUnreach, "Number of noreturn calls optimized");

namespace {
  struct VISIBILITY_HIDDEN PruneEH : public CallGraphSCCPass {
    static char ID; // Pass identification, replacement for typeid
    PruneEH() : CallGraphSCCPass((intptr_t)&ID) {}

    // runOnSCC - Analyze the SCC, performing the transformation if possible.
    bool runOnSCC(const std::vector<CallGraphNode *> &SCC);

    bool SimplifyFunction(Function *F);
    void DeleteBasicBlock(BasicBlock *BB);
  };

  char PruneEH::ID = 0;
  RegisterPass<PruneEH> X("prune-eh", "Remove unused exception handling info");
}

Pass *llvm::createPruneEHPass() { return new PruneEH(); }

bool PruneEH::runOnSCC(const std::vector<CallGraphNode *> &SCC) {
  CallGraph &CG = getAnalysis<CallGraph>();
  bool MadeChange = false;

  // First pass, scan all of the functions in the SCC, simplifying them
  // according to what we know.
  for (unsigned i = 0, e = SCC.size(); i != e; ++i)
    if (Function *F = SCC[i]->getFunction())
      MadeChange |= SimplifyFunction(F);

  // Next, check to see if any callees might throw or if there are any external
  // functions in this SCC: if so, we cannot prune any functions in this SCC.
  // If this SCC includes the unwind instruction, we KNOW it throws, so
  // obviously the SCC might throw.
  //
  bool SCCMightUnwind = false, SCCMightReturn = false;
  for (unsigned i = 0, e = SCC.size();
       (!SCCMightUnwind || !SCCMightReturn) && i != e; ++i) {
    Function *F = SCC[i]->getFunction();
    if (F == 0) {
      SCCMightUnwind = true;
      SCCMightReturn = true;
    } else if (F->isDeclaration()) {
      SCCMightUnwind |= !F->doesNotThrow();
      SCCMightReturn |= !F->doesNotReturn();
    } else {
      bool CheckUnwind = !SCCMightUnwind && !F->doesNotThrow();
      bool CheckReturn = !SCCMightReturn && !F->doesNotReturn();

      if (!CheckUnwind && !CheckReturn)
        continue;

      // Check to see if this function performs an unwind or calls an
      // unwinding function.
      for (Function::iterator BB = F->begin(), E = F->end(); BB != E; ++BB) {
        if (CheckUnwind && isa<UnwindInst>(BB->getTerminator())) {
          // Uses unwind!
          SCCMightUnwind = true;
        } else if (CheckReturn && isa<ReturnInst>(BB->getTerminator())) {
          SCCMightReturn = true;
        }

        // Invoke instructions don't allow unwinding to continue, so we are
        // only interested in call instructions.
        if (CheckUnwind && !SCCMightUnwind)
          for (BasicBlock::iterator I = BB->begin(), E = BB->end(); I != E; ++I)
            if (CallInst *CI = dyn_cast<CallInst>(I)) {
              if (CI->doesNotThrow()) {
                // This call cannot throw.
              } else if (Function *Callee = CI->getCalledFunction()) {
                CallGraphNode *CalleeNode = CG[Callee];
                // If the callee is outside our current SCC then we may
                // throw because it might.
                if (std::find(SCC.begin(), SCC.end(), CalleeNode) == SCC.end()){
                  SCCMightUnwind = true;
                  break;
                }
              } else {
                // Indirect call, it might throw.
                SCCMightUnwind = true;
                break;
              }
            }
        if (SCCMightUnwind && SCCMightReturn) break;
      }
    }
  }

  // If the SCC doesn't unwind or doesn't throw, note this fact.
  if (!SCCMightUnwind || !SCCMightReturn)
    for (unsigned i = 0, e = SCC.size(); i != e; ++i) {
      uint16_t NewAttributes = ParamAttr::None;

      if (!SCCMightUnwind)
        NewAttributes |= ParamAttr::NoUnwind;
      if (!SCCMightReturn)
        NewAttributes |= ParamAttr::NoReturn;

      const ParamAttrsList *PAL = SCC[i]->getFunction()->getParamAttrs();
      PAL = ParamAttrsList::includeAttrs(PAL, 0, NewAttributes);
      SCC[i]->getFunction()->setParamAttrs(PAL);
    }

  for (unsigned i = 0, e = SCC.size(); i != e; ++i) {
    // Convert any invoke instructions to non-throwing functions in this node
    // into call instructions with a branch.  This makes the exception blocks
    // dead.
    if (Function *F = SCC[i]->getFunction())
      MadeChange |= SimplifyFunction(F);
  }

  return MadeChange;
}

// SimplifyFunction - Given information about callees, simplify the specified
// function if we have invokes to non-unwinding functions or code after calls to
// no-return functions.
bool PruneEH::SimplifyFunction(Function *F) {
  bool MadeChange = false;
  for (Function::iterator BB = F->begin(), E = F->end(); BB != E; ++BB) {
    if (InvokeInst *II = dyn_cast<InvokeInst>(BB->getTerminator()))
      if (II->doesNotThrow()) {
        SmallVector<Value*, 8> Args(II->op_begin()+3, II->op_end());
        // Insert a call instruction before the invoke.
        CallInst *Call = new CallInst(II->getCalledValue(),
                                      Args.begin(), Args.end(), "", II);
        Call->takeName(II);
        Call->setCallingConv(II->getCallingConv());
        Call->setParamAttrs(II->getParamAttrs());

        // Anything that used the value produced by the invoke instruction
        // now uses the value produced by the call instruction.
        II->replaceAllUsesWith(Call);
        BasicBlock *UnwindBlock = II->getUnwindDest();
        UnwindBlock->removePredecessor(II->getParent());

        // Insert a branch to the normal destination right before the
        // invoke.
        new BranchInst(II->getNormalDest(), II);

        // Finally, delete the invoke instruction!
        BB->getInstList().pop_back();

        // If the unwind block is now dead, nuke it.
        if (pred_begin(UnwindBlock) == pred_end(UnwindBlock))
          DeleteBasicBlock(UnwindBlock);  // Delete the new BB.

        ++NumRemoved;
        MadeChange = true;
      }

    for (BasicBlock::iterator I = BB->begin(), E = BB->end(); I != E; )
      if (CallInst *CI = dyn_cast<CallInst>(I++))
        if (CI->doesNotReturn() && !isa<UnreachableInst>(I)) {
          // This call calls a function that cannot return.  Insert an
          // unreachable instruction after it and simplify the code.  Do this
          // by splitting the BB, adding the unreachable, then deleting the
          // new BB.
          BasicBlock *New = BB->splitBasicBlock(I);

          // Remove the uncond branch and add an unreachable.
          BB->getInstList().pop_back();
          new UnreachableInst(BB);

          DeleteBasicBlock(New);  // Delete the new BB.
          MadeChange = true;
          ++NumUnreach;
          break;
        }

  }
  return MadeChange;
}

/// DeleteBasicBlock - remove the specified basic block from the program,
/// updating the callgraph to reflect any now-obsolete edges due to calls that
/// exist in the BB.
void PruneEH::DeleteBasicBlock(BasicBlock *BB) {
  assert(pred_begin(BB) == pred_end(BB) && "BB is not dead!");
  CallGraph &CG = getAnalysis<CallGraph>();

  CallGraphNode *CGN = CG[BB->getParent()];
  for (BasicBlock::iterator I = BB->end(), E = BB->begin(); I != E; ) {
    --I;
    if (CallInst *CI = dyn_cast<CallInst>(I)) {
      if (Function *Callee = CI->getCalledFunction())
        CGN->removeCallEdgeTo(CG[Callee]);
    } else if (InvokeInst *II = dyn_cast<InvokeInst>(I)) {
      if (Function *Callee = II->getCalledFunction())
        CGN->removeCallEdgeTo(CG[Callee]);
    }
    if (!I->use_empty())
      I->replaceAllUsesWith(UndefValue::get(I->getType()));
  }

  // Get the list of successors of this block.
  std::vector<BasicBlock*> Succs(succ_begin(BB), succ_end(BB));

  for (unsigned i = 0, e = Succs.size(); i != e; ++i)
    Succs[i]->removePredecessor(BB);

  BB->eraseFromParent();
}
<|endoftext|>


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

namespace np {

enum proxy_call
{
    PROXY_INVALID = 0,
    PROXY_EVENT = 1,
    PROXY_FINISHED = 2,
};

/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/

static void
serialise_uint(int fd, unsigned int i)
{
    write(fd, &i, sizeof(i));
}

static void
serialise_string(int fd, const char *s)
{
    unsigned int len = (s ? strlen(s) : 0);
    serialise_uint(fd, len);
    if (len)
    {
	write(fd, s, len);
	write(fd, "\0", 1);
    }
}

static void
serialise_event(int fd, const event_t *ev)
{
    serialise_uint(fd, ev->which);
    serialise_string(fd, ev->description);
    serialise_uint(fd, ev->locflags);
    serialise_string(fd, ev->filename);
    serialise_uint(fd, ev->lineno);
    serialise_string(fd, ev->function);
    serialise_uint(fd, ev->functype);
}

static bool
deserialise_bytes(int fd, char *p, unsigned int len)
{
    int r;

    while (len)
    {
	r = read(fd, p, len);
	if (r < 0) {
	    perror("np: error reading from proxy");
	    return false;
	}
	if (r == 0) {
	    fprintf(stderr, "np: unexpected EOF deserialising from proxy\n");
	    return false;
	}
	len -= r;
	p += r;
    }
    return true;
}

static bool
deserialise_uint(int fd, unsigned int *ip)
{
    return deserialise_bytes(fd, (char *)ip, sizeof(*ip));
}

static bool
deserialise_string(int fd, char *buf, unsigned int maxlen)
{
    unsigned int len;

    if (!(deserialise_uint(fd, &len)))
	return false;
    if (len >= maxlen)
    {
	fprintf(stderr, "np: string too long to copy\n");
	return false;
    }
    if (!len)
    {
	buf[0] = '\0';
	return true;
    }
    return deserialise_bytes(fd, buf, len+1);
}

static bool
deserialise_event(int fd, event_t *ev)
{
    int r;
    unsigned int which;
    unsigned int locflags;
    unsigned int lineno;
    unsigned int ft;
    static char description_buf[1024];
    static char filename_buf[1024];
    static char function_buf[1024];

    if (!(deserialise_uint(fd, &which)))
	return false;
    if (!(deserialise_string(fd, description_buf,
			     sizeof(description_buf))))
	return false;
    if (!(deserialise_uint(fd, &locflags)))
	return false;
    if (!(deserialise_string(fd, filename_buf,
			     sizeof(filename_buf))))
	return false;
    if (!(deserialise_uint(fd, &lineno)))
	return false;
    if (!(deserialise_string(fd, function_buf,
			     sizeof(function_buf))))
	return false;
    if (!(deserialise_uint(fd, &ft)))
	return false;
    ev->which = (enum events_t)which;
    ev->description = description_buf;
    ev->locflags = locflags;
    ev->lineno = lineno;
    ev->filename = filename_buf;
    ev->function = function_buf;
    ev->functype = (functype_t)ft;
    return true;
}

/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/

proxy_listener_t::proxy_listener_t(int fd)
 :  fd_(fd)
{
}

proxy_listener_t::~proxy_listener_t()
{
}

void
proxy_listener_t::begin()
{
}

void
proxy_listener_t::end()
{
}

void
proxy_listener_t::begin_job(const job_t *)
{
}

void
proxy_listener_t::end_job(const job_t *j __attribute__((unused)),
			  result_t res)
{
    serialise_uint(fd_, PROXY_FINISHED);
    serialise_uint(fd_, res);
}

void
proxy_listener_t::add_event(const job_t *j __attribute__((unused)),
			    const event_t *ev)
{
    serialise_uint(fd_, PROXY_EVENT);
    serialise_event(fd_, ev);
}

/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/

/*
 * Handles input on the read end of the event pipe.  Returns false
 * when we should stop calling it, which might be due to a normal
 * end of test condition (FINISHED proxy call) or to some error.
 * Updates *@resp if necessary.
 */
bool
proxy_listener_t::handle_call(int fd, job_t *j, result_t *resp)
{
    unsigned int which = PROXY_INVALID;
    event_t ev;
    unsigned int res;

#if _NP_DEBUG
    fprintf(stderr, "np: proxy_listener_t::handle_call()\n");
#endif
    if (deserialise_uint(fd, &which))
    {
        switch (which)
        {
        case PROXY_EVENT:
#if _NP_DEBUG
            fprintf(stderr, "np: deserializing EVENT\n");
#endif
            if (deserialise_event(fd, &ev))
            {
                *resp = merge(*resp, np::runner_t::running()->raise_event(j, &ev));
                return true;  /* call me again */
            }
            break;
        case PROXY_FINISHED:
#if _NP_DEBUG
            fprintf(stderr, "np: deserializing FINISHED\n");
#endif
            if (deserialise_uint(fd, &res))
            {
                *resp = merge(*resp, (result_t)res);
                return false;	      /* end of test, expect no more calls */
            }
            break;
        default:
            break;
        }
    }

    /* Decoding failed somehow so fail the test and tell the user */
    *resp = merge(*resp, R_FAIL);
    fprintf(stderr, "np: can't decode proxy call (which=%u)\n", which);
    return false;
}

// close the namespace
};
<commit_msg>Malloc memory instead of assuming the string is less than 1024 characters<commit_after>/*
 * Copyright 2011-2012 Gregory Banks
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#include "np/proxy_listener.hxx"
#include "except.h"
#include "np_priv.h"

namespace np {

enum proxy_call
{
    PROXY_INVALID = 0,
    PROXY_EVENT = 1,
    PROXY_FINISHED = 2,
};

/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/

static void
serialise_uint(int fd, unsigned int i)
{
    write(fd, &i, sizeof(i));
}

static void
serialise_string(int fd, const char *s)
{
    unsigned int len = (s ? strlen(s) : 0);
    serialise_uint(fd, len);
    if (len)
    {
	write(fd, s, len);
	write(fd, "\0", 1);
    }
}

static void
serialise_event(int fd, const event_t *ev)
{
    serialise_uint(fd, ev->which);
    serialise_string(fd, ev->description);
    serialise_uint(fd, ev->locflags);
    serialise_string(fd, ev->filename);
    serialise_uint(fd, ev->lineno);
    serialise_string(fd, ev->function);
    serialise_uint(fd, ev->functype);
}

static bool
deserialise_bytes(int fd, char *p, unsigned int len)
{
    int r;

    while (len)
    {
	r = read(fd, p, len);
	if (r < 0) {
	    perror("np: error reading from proxy");
	    return false;
	}
	if (r == 0) {
	    fprintf(stderr, "np: unexpected EOF deserialising from proxy\n");
	    return false;
	}
	len -= r;
	p += r;
    }
    return true;
}

static bool
deserialise_uint(int fd, unsigned int *ip)
{
    return deserialise_bytes(fd, (char *)ip, sizeof(*ip));
}

static bool
deserialise_string(int fd, char **buf)
{
    unsigned int len;

    if (!(deserialise_uint(fd, &len)))
	return false;
    *buf = (char *) malloc(sizeof(char) * (len + 1));
    if (!len)
    {
        *buf[0] = '\0';
        return true;
    }
    return deserialise_bytes(fd, *buf, len+1);
}

static bool
deserialise_event(int fd, event_t *ev)
{
    int r;
    unsigned int which;
    unsigned int locflags;
    unsigned int lineno;
    unsigned int ft;
    char * description = NULL;
    char * filename = NULL;
    char * function = NULL;

    if (!(deserialise_uint(fd, &which)))
	return false;
    if (!(deserialise_string(fd, &description)))
	return false;
    if (!(deserialise_uint(fd, &locflags)))
	return false;
    if (!(deserialise_string(fd, &filename)))
	return false;
    if (!(deserialise_uint(fd, &lineno)))
	return false;
    if (!(deserialise_string(fd, &function)))
	return false;
    if (!(deserialise_uint(fd, &ft)))
	return false;
    ev->which = (enum events_t)which;
    ev->description = description;
    ev->locflags = locflags;
    ev->lineno = lineno;
    ev->filename = filename;
    ev->function = function;
    ev->functype = (functype_t)ft;
    return true;
}

static void
deserialise_event_cleanup(event_t *ev)
{
    if (ev->description)
        free((void *)ev->description);
    if (ev->filename)
        free((void *)ev->filename);
    if (ev->function)
        free((void *)ev->function);
}

/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/

proxy_listener_t::proxy_listener_t(int fd)
 :  fd_(fd)
{
}

proxy_listener_t::~proxy_listener_t()
{
}

void
proxy_listener_t::begin()
{
}

void
proxy_listener_t::end()
{
}

void
proxy_listener_t::begin_job(const job_t *)
{
}

void
proxy_listener_t::end_job(const job_t *j __attribute__((unused)),
			  result_t res)
{
    serialise_uint(fd_, PROXY_FINISHED);
    serialise_uint(fd_, res);
}

void
proxy_listener_t::add_event(const job_t *j __attribute__((unused)),
			    const event_t *ev)
{
    serialise_uint(fd_, PROXY_EVENT);
    serialise_event(fd_, ev);
}

/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/

/*
 * Handles input on the read end of the event pipe.  Returns false
 * when we should stop calling it, which might be due to a normal
 * end of test condition (FINISHED proxy call) or to some error.
 * Updates *@resp if necessary.
 */
bool
proxy_listener_t::handle_call(int fd, job_t *j, result_t *resp)
{
    unsigned int which = PROXY_INVALID;
    event_t ev;
    unsigned int res;

#if _NP_DEBUG
    fprintf(stderr, "np: proxy_listener_t::handle_call()\n");
#endif
    if (deserialise_uint(fd, &which))
    {
        switch (which)
        {
        case PROXY_EVENT:
#if _NP_DEBUG
            fprintf(stderr, "np: deserializing EVENT\n");
#endif
            if (deserialise_event(fd, &ev))
            {
                *resp = merge(*resp, np::runner_t::running()->raise_event(j, &ev));
                deserialise_event_cleanup(&ev);
                return true;  /* call me again */
            }
            deserialise_event_cleanup(&ev);
            break;
        case PROXY_FINISHED:
#if _NP_DEBUG
            fprintf(stderr, "np: deserializing FINISHED\n");
#endif
            if (deserialise_uint(fd, &res))
            {
                *resp = merge(*resp, (result_t)res);
                return false;	      /* end of test, expect no more calls */
            }
            break;
        default:
            break;
        }
    }

    /* Decoding failed somehow so fail the test and tell the user */
    *resp = merge(*resp, R_FAIL);
    fprintf(stderr, "np: can't decode proxy call (which=%u)\n", which);
    return false;
}

// close the namespace
};
<|endoftext|>