<commit_before>/* BEGIN_COMMON_COPYRIGHT_HEADER
 * (c)LGPL2+
 *
 * LXDE-Qt - a lightweight, Qt based, desktop toolset
 * http://razor-qt.org
 *
 * Copyright: 2012 Razor team
 * Authors:
 *   Petr Vanek <petr@scribus.info>
 *
 * This program or library is free software; you can redistribute it
 * and/or modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.

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

#include <QPainter>
#include <QUrl>
#include <QFile>
#include <QDateTime>
#include <QtDBus/QDBusArgument>
#include <QDebug>
#include <XdgIcon>
#include <KWindowSystem/KWindowSystem>

#include "notification.h"
#include "notificationwidgets.h"

#define ICONSIZE QSize(32, 32)

Notification::Notification(const QString &application,
                           const QString &summary, const QString &body,
                           const QString &icon, int timeout,
                           const QStringList& actions, const QVariantMap& hints,
                           QWidget *parent)
    : QWidget(parent),
      m_timer(0),
      m_actionWidget(0)
{
    setupUi(this);
    setObjectName("Notification");
    setMouseTracking(true);

    setMaximumWidth(parent->width());
    setMinimumWidth(parent->width());

    setValues(application, summary, body, icon, timeout, actions, hints);

    connect(closeButton, SIGNAL(clicked()), this, SLOT(closeButton_clicked()));
}

void Notification::setValues(const QString &application,
                             const QString &summary, const QString &body,
                             const QString &icon, int timeout,
                             const QStringList& actions, const QVariantMap& hints)
{
    // Basic properties *********************

    // Notifications spec set real order here:
    // An implementation which only displays one image or icon must
    // choose which one to display using the following order:
    //  - "image-data"
    //  - "image-path"
    //  - app_icon parameter
    //  - for compatibility reason, "icon_data"
    if (!hints["image_data"].isNull())
    {
        m_pixmap = getPixmapFromHint(hints["image_data"]);
//        qDebug() << application << "from image_data" << m_pixmap.isNull();
    }
    else if (!hints["image_path"].isNull())
    {
        m_pixmap = getPixmapFromString(hints["image_path"].toString());
//        qDebug() << application << "from image_path" << m_pixmap.isNull();
    }
    else if (!icon.isEmpty())
    {
        m_pixmap = getPixmapFromString(icon);
//        qDebug() << application << "from icon" << icon << m_pixmap.isNull();
    }
    else if (!hints["icon_data"].isNull())
    {
       m_pixmap = getPixmapFromHint(hints["icon_data"]);
//       qDebug() << application << "from icon_data" << m_pixmap.isNull();
    }
    // issue #325: Do not display icon if it's not found...
    if (m_pixmap.isNull())
    {
        iconLabel->hide();
    }
    else
    {
        if (m_pixmap.size().width() > ICONSIZE.width()
            || m_pixmap.size().height() > ICONSIZE.height())
        {
            m_pixmap = m_pixmap.scaled(ICONSIZE, Qt::KeepAspectRatio, Qt::SmoothTransformation);
        }
        iconLabel->setPixmap(m_pixmap);
        iconLabel->show();
    }
    //XXX: workaround to properly set text labels widths (for correct sizeHints after setText)
    adjustSize();

    // application
    appLabel->setVisible(!application.isEmpty());
    appLabel->setFixedWidth(appLabel->width());
    appLabel->setText(application);

    // summary
    summaryLabel->setVisible(!summary.isEmpty() && application != summary);
    summaryLabel->setFixedWidth(summaryLabel->width());
    summaryLabel->setText(summary);

    // body
    bodyLabel->setVisible(!body.isEmpty());
    bodyLabel->setFixedWidth(bodyLabel->width());
    //https://developer.gnome.org/notification-spec
    //Body - This is a multi-line body of text. Each line is a paragraph, server implementations are free to word wrap them as they see fit.
    //XXX: remove all unsupported tags?!? (supported , , , , )
    QString formatted(body);
    bodyLabel->setText(formatted.replace('\n', QStringLiteral("
")));

    // Timeout
    // Special values:
    //  < 0: server decides timeout
    //    0: infifite
    if (m_timer)
    {
        m_timer->stop();
        m_timer->deleteLater();
    }

    // -1 for server decides is handled in notifyd to save QSettings instance
    if (timeout > 0)
    {
        m_timer = new NotificationTimer(this);
        connect(m_timer, SIGNAL(timeout()), this, SIGNAL(timeout()));
        m_timer->start(timeout);
    }

    // Categories *********************
    // TODO/FIXME: Categories - how to handle it?
    if (!hints["category"].isNull())
    {
        qDebug() << "Notification" << application << "category" << hints["category"];
    }

    // Urgency Levels *********************
    // Type    Description
    // 0   Low
    // 1   Normal
    // 2   Critical
    // TODO/FIXME: Urgencies - how to handle it?
    if (!hints["urgency"].isNull())
    {
        qDebug() << "Notification" << application << "urgency" << hints["urgency"];
    }

    // Actions
    if (actions.count() && m_actionWidget == 0)
    {
        if (actions.count()/2 < 4)
            m_actionWidget = new NotificationActionsButtonsWidget(actions, this);
        else
            m_actionWidget = new NotificationActionsComboWidget(actions, this);
        connect(m_actionWidget, SIGNAL(actionTriggered(const QString &)),
                this, SIGNAL(actionTriggered(const QString &)));
        actionsLayout->addWidget(m_actionWidget);
        m_actionWidget->show();
    }

    adjustSize();
    // ensure layout expansion
    setMinimumHeight(qMax(rect().height(), childrenRect().height()));
}

QString Notification::application() const
{
    return appLabel->text();
}

QString Notification::summary() const
{
    return summaryLabel->text();
}

QString Notification::body() const
{
    return bodyLabel->text();
}

void Notification::closeButton_clicked()
{
    if (m_timer)
        m_timer->stop();
    emit userCanceled();
}

void Notification::paintEvent(QPaintEvent *)
{
    QStyleOption opt;
    opt.init(this);
    QPainter p(this);
    style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
}

QPixmap Notification::getPixmapFromHint(const QVariant &argument) const
{
    int width, height, rowstride, bitsPerSample, channels;
    bool hasAlpha;
    QByteArray data;

    const QDBusArgument arg = argument.value<QDBusArgument>();
    arg.beginStructure();
    arg >> width;
    arg >> height;
    arg >> rowstride;
    arg >> hasAlpha;
    arg >> bitsPerSample;
    arg >> channels;
    arg >> data;
    arg.endStructure();
    QImage img = QImage((uchar*)data.constData(), width, height, QImage::Format_ARGB32).rgbSwapped();

    return QPixmap::fromImage(img);
}

QPixmap Notification::getPixmapFromString(const QString &str) const
{
    QUrl url(str);
    if (url.isValid() && QFile::exists(url.toLocalFile()))
    {
//        qDebug() << "    getPixmapFromString by URL" << url;
        return QPixmap(url.toLocalFile());
    }
    else
    {
//        qDebug() << "    getPixmapFromString by XdgIcon theme" << str << ICONSIZE << XdgIcon::themeName();
//        qDebug() << "       " << XdgIcon::fromTheme(str) << "isnull:" << XdgIcon::fromTheme(str).isNull();
        // They say: do not display an icon if it;s not found - see #325
        return XdgIcon::fromTheme(str/*, XdgIcon::defaultApplicationIcon()*/).pixmap(ICONSIZE);
    }
}

void Notification::enterEvent(QEvent * event)
{
    if (m_timer)
        m_timer->pause();
}

void Notification::leaveEvent(QEvent * event)
{
    if (m_timer)
        m_timer->resume();
}

void Notification::mouseReleaseEvent(QMouseEvent * event)
{
//    qDebug() << "CLICKED" << event;
    QString appName;
    QString windowTitle;

    if (m_actionWidget && m_actionWidget->hasDefaultAction())
    {
        emit actionTriggered(m_actionWidget->defaultAction());
        return;
    }

    foreach (WId i, KWindowSystem::stackingOrder())
    {
        KWindowInfo info = KWindowInfo(i, NET::WMName | NET::WMVisibleName);
        appName = info.name();
        windowTitle = info.visibleName();
        // qDebug() << "    " << i << "APPNAME" << appName << "TITLE" << windowTitle;
        if (appName.isEmpty())
        {
            QWidget::mouseReleaseEvent(event);
            return;
        }
        if (appName == appLabel->text() || windowTitle == appLabel->text())
        {
            KWindowSystem::raiseWindow(i);
            closeButton_clicked();
            return;
        }
    }
}

NotificationTimer::NotificationTimer(QObject *parent)
    : QTimer(parent),
      m_intervalMsec(-1)
{
}

void NotificationTimer::start(int msec)
{
    m_startTime = QDateTime::currentDateTime();
    m_intervalMsec = msec;
    QTimer::start(msec);
}

void NotificationTimer::pause()
{
    if (!isActive())
        return;

    stop();
    m_intervalMsec = m_startTime.msecsTo(QDateTime());
}

void NotificationTimer::resume()
{
    if (isActive())
        return;

    start(m_intervalMsec);
}
<commit_msg>Fix notifications disappearing on mouse leave<commit_after>/* BEGIN_COMMON_COPYRIGHT_HEADER
 * (c)LGPL2+
 *
 * LXDE-Qt - a lightweight, Qt based, desktop toolset
 * http://razor-qt.org
 *
 * Copyright: 2012 Razor team
 * Authors:
 *   Petr Vanek <petr@scribus.info>
 *
 * This program or library is free software; you can redistribute it
 * and/or modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.

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

#include <QPainter>
#include <QUrl>
#include <QFile>
#include <QDateTime>
#include <QtDBus/QDBusArgument>
#include <QDebug>
#include <XdgIcon>
#include <KWindowSystem/KWindowSystem>

#include "notification.h"
#include "notificationwidgets.h"

#define ICONSIZE QSize(32, 32)

Notification::Notification(const QString &application,
                           const QString &summary, const QString &body,
                           const QString &icon, int timeout,
                           const QStringList& actions, const QVariantMap& hints,
                           QWidget *parent)
    : QWidget(parent),
      m_timer(0),
      m_actionWidget(0)
{
    setupUi(this);
    setObjectName("Notification");
    setMouseTracking(true);

    setMaximumWidth(parent->width());
    setMinimumWidth(parent->width());

    setValues(application, summary, body, icon, timeout, actions, hints);

    connect(closeButton, SIGNAL(clicked()), this, SLOT(closeButton_clicked()));
}

void Notification::setValues(const QString &application,
                             const QString &summary, const QString &body,
                             const QString &icon, int timeout,
                             const QStringList& actions, const QVariantMap& hints)
{
    // Basic properties *********************

    // Notifications spec set real order here:
    // An implementation which only displays one image or icon must
    // choose which one to display using the following order:
    //  - "image-data"
    //  - "image-path"
    //  - app_icon parameter
    //  - for compatibility reason, "icon_data"
    if (!hints["image_data"].isNull())
    {
        m_pixmap = getPixmapFromHint(hints["image_data"]);
//        qDebug() << application << "from image_data" << m_pixmap.isNull();
    }
    else if (!hints["image_path"].isNull())
    {
        m_pixmap = getPixmapFromString(hints["image_path"].toString());
//        qDebug() << application << "from image_path" << m_pixmap.isNull();
    }
    else if (!icon.isEmpty())
    {
        m_pixmap = getPixmapFromString(icon);
//        qDebug() << application << "from icon" << icon << m_pixmap.isNull();
    }
    else if (!hints["icon_data"].isNull())
    {
       m_pixmap = getPixmapFromHint(hints["icon_data"]);
//       qDebug() << application << "from icon_data" << m_pixmap.isNull();
    }
    // issue #325: Do not display icon if it's not found...
    if (m_pixmap.isNull())
    {
        iconLabel->hide();
    }
    else
    {
        if (m_pixmap.size().width() > ICONSIZE.width()
            || m_pixmap.size().height() > ICONSIZE.height())
        {
            m_pixmap = m_pixmap.scaled(ICONSIZE, Qt::KeepAspectRatio, Qt::SmoothTransformation);
        }
        iconLabel->setPixmap(m_pixmap);
        iconLabel->show();
    }
    //XXX: workaround to properly set text labels widths (for correct sizeHints after setText)
    adjustSize();

    // application
    appLabel->setVisible(!application.isEmpty());
    appLabel->setFixedWidth(appLabel->width());
    appLabel->setText(application);

    // summary
    summaryLabel->setVisible(!summary.isEmpty() && application != summary);
    summaryLabel->setFixedWidth(summaryLabel->width());
    summaryLabel->setText(summary);

    // body
    bodyLabel->setVisible(!body.isEmpty());
    bodyLabel->setFixedWidth(bodyLabel->width());
    //https://developer.gnome.org/notification-spec
    //Body - This is a multi-line body of text. Each line is a paragraph, server implementations are free to word wrap them as they see fit.
    //XXX: remove all unsupported tags?!? (supported , , , , )
    QString formatted(body);
    bodyLabel->setText(formatted.replace('\n', QStringLiteral("
")));

    // Timeout
    // Special values:
    //  < 0: server decides timeout
    //    0: infifite
    if (m_timer)
    {
        m_timer->stop();
        m_timer->deleteLater();
    }

    // -1 for server decides is handled in notifyd to save QSettings instance
    if (timeout > 0)
    {
        m_timer = new NotificationTimer(this);
        connect(m_timer, SIGNAL(timeout()), this, SIGNAL(timeout()));
        m_timer->start(timeout);
    }

    // Categories *********************
    // TODO/FIXME: Categories - how to handle it?
    if (!hints["category"].isNull())
    {
        qDebug() << "Notification" << application << "category" << hints["category"];
    }

    // Urgency Levels *********************
    // Type    Description
    // 0   Low
    // 1   Normal
    // 2   Critical
    // TODO/FIXME: Urgencies - how to handle it?
    if (!hints["urgency"].isNull())
    {
        qDebug() << "Notification" << application << "urgency" << hints["urgency"];
    }

    // Actions
    if (actions.count() && m_actionWidget == 0)
    {
        if (actions.count()/2 < 4)
            m_actionWidget = new NotificationActionsButtonsWidget(actions, this);
        else
            m_actionWidget = new NotificationActionsComboWidget(actions, this);
        connect(m_actionWidget, SIGNAL(actionTriggered(const QString &)),
                this, SIGNAL(actionTriggered(const QString &)));
        actionsLayout->addWidget(m_actionWidget);
        m_actionWidget->show();
    }

    adjustSize();
    // ensure layout expansion
    setMinimumHeight(qMax(rect().height(), childrenRect().height()));
}

QString Notification::application() const
{
    return appLabel->text();
}

QString Notification::summary() const
{
    return summaryLabel->text();
}

QString Notification::body() const
{
    return bodyLabel->text();
}

void Notification::closeButton_clicked()
{
    if (m_timer)
        m_timer->stop();
    emit userCanceled();
}

void Notification::paintEvent(QPaintEvent *)
{
    QStyleOption opt;
    opt.init(this);
    QPainter p(this);
    style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
}

QPixmap Notification::getPixmapFromHint(const QVariant &argument) const
{
    int width, height, rowstride, bitsPerSample, channels;
    bool hasAlpha;
    QByteArray data;

    const QDBusArgument arg = argument.value<QDBusArgument>();
    arg.beginStructure();
    arg >> width;
    arg >> height;
    arg >> rowstride;
    arg >> hasAlpha;
    arg >> bitsPerSample;
    arg >> channels;
    arg >> data;
    arg.endStructure();
    QImage img = QImage((uchar*)data.constData(), width, height, QImage::Format_ARGB32).rgbSwapped();

    return QPixmap::fromImage(img);
}

QPixmap Notification::getPixmapFromString(const QString &str) const
{
    QUrl url(str);
    if (url.isValid() && QFile::exists(url.toLocalFile()))
    {
//        qDebug() << "    getPixmapFromString by URL" << url;
        return QPixmap(url.toLocalFile());
    }
    else
    {
//        qDebug() << "    getPixmapFromString by XdgIcon theme" << str << ICONSIZE << XdgIcon::themeName();
//        qDebug() << "       " << XdgIcon::fromTheme(str) << "isnull:" << XdgIcon::fromTheme(str).isNull();
        // They say: do not display an icon if it;s not found - see #325
        return XdgIcon::fromTheme(str/*, XdgIcon::defaultApplicationIcon()*/).pixmap(ICONSIZE);
    }
}

void Notification::enterEvent(QEvent * event)
{
    if (m_timer)
        m_timer->pause();
}

void Notification::leaveEvent(QEvent * event)
{
    if (m_timer)
        m_timer->resume();
}

void Notification::mouseReleaseEvent(QMouseEvent * event)
{
//    qDebug() << "CLICKED" << event;
    QString appName;
    QString windowTitle;

    if (m_actionWidget && m_actionWidget->hasDefaultAction())
    {
        emit actionTriggered(m_actionWidget->defaultAction());
        return;
    }

    foreach (WId i, KWindowSystem::stackingOrder())
    {
        KWindowInfo info = KWindowInfo(i, NET::WMName | NET::WMVisibleName);
        appName = info.name();
        windowTitle = info.visibleName();
        // qDebug() << "    " << i << "APPNAME" << appName << "TITLE" << windowTitle;
        if (appName.isEmpty())
        {
            QWidget::mouseReleaseEvent(event);
            return;
        }
        if (appName == appLabel->text() || windowTitle == appLabel->text())
        {
            KWindowSystem::raiseWindow(i);
            closeButton_clicked();
            return;
        }
    }
}

NotificationTimer::NotificationTimer(QObject *parent)
    : QTimer(parent),
      m_intervalMsec(-1)
{
}

void NotificationTimer::start(int msec)
{
    m_startTime = QDateTime::currentDateTime();
    m_intervalMsec = msec;
    QTimer::start(msec);
}

void NotificationTimer::pause()
{
    if (!isActive())
        return;

    stop();
    m_intervalMsec = m_startTime.msecsTo(QDateTime::currentDateTime());
}

void NotificationTimer::resume()
{
    if (isActive())
        return;

    start(m_intervalMsec);
}
<|endoftext|>


<commit_before>// vim:ts=2:sw=2:expandtab:autoindent:filetype=cpp:
/*
Copyright (c) 2009 Aristid Breitkreuz, Ash Berlin, Ruediger Sonderfeld

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

#ifndef FLUSSFPERD_CLASS_DESCRIPTION_HPP
#define FLUSSFPERD_CLASS_DESCRIPTION_HPP

#ifndef PREPROC_DEBUG
#include "class.hpp"
#include "native_object_base.hpp"
#endif
#include <boost/preprocessor.hpp>

/* 2-tuple seq */

#define FLUSSPFERD_PP_GEN_TUPLE2SEQ_PROCESS2(x, y) \
  ((x, y)) \
  FLUSSPFERD_PP_GEN_TUPLE2SEQ_PROCESS

#define FLUSSPFERD_PP_GEN_TUPLE2SEQ_PROCESS(x, y) \
  ((x, y)) \
  FLUSSPFERD_PP_GEN_TUPLE2SEQ_PROCESS2

#define FLUSSPFERD_PP_GEN_TUPLE2SEQ_PROCESS_ELIM
#define FLUSSPFERD_PP_GEN_TUPLE2SEQ_PROCESS2_ELIM

#define FLUSSPFERD_PP_GEN_TUPLE2SEQ(x) \
  BOOST_PP_CAT(FLUSSPFERD_PP_GEN_TUPLE2SEQ_PROCESS x, _ELIM)

/* 3-tuple seq */

#define FLUSSPFERD_PP_GEN_TUPLE3SEQ_PROCESS2(x, y, z) \
  ((x, y, z)) \
  FLUSSPFERD_PP_GEN_TUPLE3SEQ_PROCESS

#define FLUSSPFERD_PP_GEN_TUPLE3SEQ_PROCESS(x, y, z) \
  ((x, y, z)) \
  FLUSSPFERD_PP_GEN_TUPLE3SEQ_PROCESS2

#define FLUSSPFERD_PP_GEN_TUPLE3SEQ_PROCESS_ELIM
#define FLUSSPFERD_PP_GEN_TUPLE3SEQ_PROCESS2_ELIM

#define FLUSSPFERD_PP_GEN_TUPLE3SEQ(x) \
  BOOST_PP_CAT(FLUSSPFERD_PP_GEN_TUPLE3SEQ_PROCESS x, _ELIM)

/* -- */

#define FLUSSPFERD_CD_PARAM_FOLD(s, state, elem) \
  BOOST_PP_ARRAY_REPLACE( \
    state, \
    BOOST_PP_EXPAND( \
      BOOST_PP_CAT(FLUSSPFERD_CD_PARAM__, \
        BOOST_PP_TUPLE_ELEM(2, 0, elem))), \
    BOOST_PP_TUPLE_ELEM(2, 1, elem)) \
  /* */

#define FLUSSPFERD_CD_PARAM_INITIAL \
  (8, ( \
    ~cpp_name~,            /* name */ \
    ~constructor_name~,    /* constructor name */ \
    0,                     /* constructor arity */ \
    ~full_name~,           /* full name */ \
    ~methods~,             /* methods */ \
    0,                     /* NO methods */ \
    0,                     /* augment constructor */ \
    true                   /* constructible */ \
  )) \
  /* */

#define FLUSSPFERD_CD_PARAM__cpp_name               0
#define FLUSSPFERD_CD_PARAM__constructor_name       1
#define FLUSSPFERD_CD_PARAM__constructor_arity      2
#define FLUSSPFERD_CD_PARAM__full_name              3
#define FLUSSPFERD_CD_PARAM__methods                4
#define FLUSSPFERD_CD_PARAM__no_methods             5
#define FLUSSPFERD_CD_PARAM__augment_constructor    6
#define FLUSSPFERD_CD_PARAM__constructible          7

#define FLUSSPFERD_CD_PARAM(tuple_seq) \
  BOOST_PP_SEQ_FOLD_LEFT( \
    FLUSSPFERD_CD_PARAM_FOLD, \
    FLUSSPFERD_CD_PARAM_INITIAL, \
    FLUSSPFERD_PP_GEN_TUPLE2SEQ(tuple_seq) \
  ) \
  /* */

#define FLUSSPFERD_CLASS_DESCRIPTION_A(array) \
  BOOST_PP_EXPAND(FLUSSPFERD_CLASS_DESCRIPTION_P BOOST_PP_ARRAY_DATA(array)) \
  /* */

#define FLUSSPFERD_CLASS_DESCRIPTION_P( \
  p_cpp_name, \
  p_constructor_name, \
  p_constructor_arity, \
  p_full_name, \
  p_methods, \
  p_no_methods, \
  p_augment_constructor, \
  p_constructible \
) \
  class p_cpp_name : public ::flusspferd::native_object_base { \
  public: \
    struct class_info : ::flusspferd::class_info { \
      typedef boost::mpl::bool_< (p_constructible) > constructible; \
      static char const *constructor_name() { \
        return (p_constructor_name); \
      } \
      typedef ::boost::mpl::size_t< (p_constructor_arity) > constructor_arity; \
      static char const *full_name() { \
        return (p_full_name); \
      } \
      static ::flusspferd::object create_prototype() { \
        ::flusspferd::object proto = ::flusspferd::create_object(); \
        BOOST_PP_IIF( \
          p_no_methods, \
          BOOST_PP_TUPLE_EAT(2), \
          FLUSSPFERD_CD_METHODS \
        ) (p_cpp_name, p_methods) \
        return proto; \
      } \
      BOOST_PP_EXPR_IF( \
        p_augment_constructor, \
        static void augment_constructor(::flusspferd::object &); \
      ) \
    }; \
  private: \
  /* */

#define FLUSSPFERD_CD_METHODS(p_cpp_name, p_methods) \
  BOOST_PP_SEQ_FOR_EACH( \
    FLUSSPFERD_CD_METHOD, \
    p_cpp_name, \
    FLUSSPFERD_PP_GEN_TUPLE3SEQ(p_methods)) \
  /* */

#define FLUSSPFERD_CD_METHOD(r, p_cpp_name, p_method) \
  BOOST_PP_CAT( \
    FLUSSPFERD_CD_METHOD__, \
    BOOST_PP_TUPLE_ELEM(3, 1, p_method) \
  ) ( \
    p_cpp_name, \
    BOOST_PP_TUPLE_ELEM(3, 0, p_method), \
    BOOST_PP_TUPLE_ELEM(3, 2, p_method) \
  ) \
  /* */

#define FLUSSPFERD_CD_METHOD__bind(p_cpp_name, p_method_name, p_bound) \
  ::flusspferd::create_native_method( \
      proto, \
      (p_method_name), \
      & p_cpp_name :: p_bound); \
  /* */

#define FLUSSPFERD_CD_METHOD__alias(p_cpp_name, p_method_name, p_alias) \
  proto.define_property( \
    (p_method_name), \
    proto.get_property((p_alias)), \
    ::flusspferd::dont_enumerate); \
  /* */

#define FLUSSPFERD_CLASS_DESCRIPTION(tuple_seq) \
  FLUSSPFERD_CLASS_DESCRIPTION_A(FLUSSPFERD_CD_PARAM(tuple_seq)) \
  /* */

#define FLUSSPFERD_CLASS_DESCRIPTION_END() \
  }; \
  /* */

#endif
<commit_msg>class_macros: add custom_enumerate param<commit_after>// vim:ts=2:sw=2:expandtab:autoindent:filetype=cpp:
/*
Copyright (c) 2009 Aristid Breitkreuz, Ash Berlin, Ruediger Sonderfeld

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

#ifndef FLUSSFPERD_CLASS_DESCRIPTION_HPP
#define FLUSSFPERD_CLASS_DESCRIPTION_HPP

#ifndef PREPROC_DEBUG
#include "class.hpp"
#include "native_object_base.hpp"
#endif
#include <boost/preprocessor.hpp>

/* 2-tuple seq */

#define FLUSSPFERD_PP_GEN_TUPLE2SEQ_PROCESS2(x, y) \
  ((x, y)) \
  FLUSSPFERD_PP_GEN_TUPLE2SEQ_PROCESS

#define FLUSSPFERD_PP_GEN_TUPLE2SEQ_PROCESS(x, y) \
  ((x, y)) \
  FLUSSPFERD_PP_GEN_TUPLE2SEQ_PROCESS2

#define FLUSSPFERD_PP_GEN_TUPLE2SEQ_PROCESS_ELIM
#define FLUSSPFERD_PP_GEN_TUPLE2SEQ_PROCESS2_ELIM

#define FLUSSPFERD_PP_GEN_TUPLE2SEQ(x) \
  BOOST_PP_CAT(FLUSSPFERD_PP_GEN_TUPLE2SEQ_PROCESS x, _ELIM)

/* 3-tuple seq */

#define FLUSSPFERD_PP_GEN_TUPLE3SEQ_PROCESS2(x, y, z) \
  ((x, y, z)) \
  FLUSSPFERD_PP_GEN_TUPLE3SEQ_PROCESS

#define FLUSSPFERD_PP_GEN_TUPLE3SEQ_PROCESS(x, y, z) \
  ((x, y, z)) \
  FLUSSPFERD_PP_GEN_TUPLE3SEQ_PROCESS2

#define FLUSSPFERD_PP_GEN_TUPLE3SEQ_PROCESS_ELIM
#define FLUSSPFERD_PP_GEN_TUPLE3SEQ_PROCESS2_ELIM

#define FLUSSPFERD_PP_GEN_TUPLE3SEQ(x) \
  BOOST_PP_CAT(FLUSSPFERD_PP_GEN_TUPLE3SEQ_PROCESS x, _ELIM)

/* -- */

#define FLUSSPFERD_CD_PARAM_FOLD(s, state, elem) \
  BOOST_PP_ARRAY_REPLACE( \
    state, \
    BOOST_PP_EXPAND( \
      BOOST_PP_CAT(FLUSSPFERD_CD_PARAM__, \
        BOOST_PP_TUPLE_ELEM(2, 0, elem))), \
    BOOST_PP_TUPLE_ELEM(2, 1, elem)) \
  /* */

#define FLUSSPFERD_CD_PARAM_INITIAL \
  (9, ( \
    ~cpp_name~,            /* name */ \
    ~constructor_name~,    /* constructor name */ \
    0,                     /* constructor arity */ \
    ~full_name~,           /* full name */ \
    ~methods~,             /* methods */ \
    0,                     /* NO methods */ \
    0,                     /* augment constructor */ \
    true,                  /* constructible */ \
    false                  /* custom enumerate */ \
  )) \
  /* */

#define FLUSSPFERD_CD_PARAM__cpp_name               0
#define FLUSSPFERD_CD_PARAM__constructor_name       1
#define FLUSSPFERD_CD_PARAM__constructor_arity      2
#define FLUSSPFERD_CD_PARAM__full_name              3
#define FLUSSPFERD_CD_PARAM__methods                4
#define FLUSSPFERD_CD_PARAM__no_methods             5
#define FLUSSPFERD_CD_PARAM__augment_constructor    6
#define FLUSSPFERD_CD_PARAM__constructible          7
#define FLUSSPFERD_CD_PARAM__custom_enumerate       8

#define FLUSSPFERD_CD_PARAM(tuple_seq) \
  BOOST_PP_SEQ_FOLD_LEFT( \
    FLUSSPFERD_CD_PARAM_FOLD, \
    FLUSSPFERD_CD_PARAM_INITIAL, \
    FLUSSPFERD_PP_GEN_TUPLE2SEQ(tuple_seq) \
  ) \
  /* */

#define FLUSSPFERD_CLASS_DESCRIPTION_A(array) \
  BOOST_PP_EXPAND(FLUSSPFERD_CLASS_DESCRIPTION_P BOOST_PP_ARRAY_DATA(array)) \
  /* */

#define FLUSSPFERD_CLASS_DESCRIPTION_P( \
  p_cpp_name, \
  p_constructor_name, \
  p_constructor_arity, \
  p_full_name, \
  p_methods, \
  p_no_methods, \
  p_augment_constructor, \
  p_constructible, \
  p_custom_enumerate \
) \
  class p_cpp_name : public ::flusspferd::native_object_base { \
  public: \
    struct class_info : ::flusspferd::class_info { \
      typedef boost::mpl::bool_< (p_constructible) > constructible; \
      static char const *constructor_name() { \
        return (p_constructor_name); \
      } \
      typedef ::boost::mpl::size_t< (p_constructor_arity) > constructor_arity; \
      static char const *full_name() { \
        return (p_full_name); \
      } \
      static ::flusspferd::object create_prototype() { \
        ::flusspferd::object proto = ::flusspferd::create_object(); \
        BOOST_PP_IIF( \
          p_no_methods, \
          BOOST_PP_TUPLE_EAT(2), \
          FLUSSPFERD_CD_METHODS \
        ) (p_cpp_name, p_methods) \
        return proto; \
      } \
      BOOST_PP_EXPR_IF( \
        p_augment_constructor, \
        static void augment_constructor(::flusspferd::object &); \
      ) \
      typedef boost::mpl::bool_< (p_custom_enumerate) > custom_enumerate; \
    }; \
  private: \
  /* */

#define FLUSSPFERD_CD_METHODS(p_cpp_name, p_methods) \
  BOOST_PP_SEQ_FOR_EACH( \
    FLUSSPFERD_CD_METHOD, \
    p_cpp_name, \
    FLUSSPFERD_PP_GEN_TUPLE3SEQ(p_methods)) \
  /* */

#define FLUSSPFERD_CD_METHOD(r, p_cpp_name, p_method) \
  BOOST_PP_CAT( \
    FLUSSPFERD_CD_METHOD__, \
    BOOST_PP_TUPLE_ELEM(3, 1, p_method) \
  ) ( \
    p_cpp_name, \
    BOOST_PP_TUPLE_ELEM(3, 0, p_method), \
    BOOST_PP_TUPLE_ELEM(3, 2, p_method) \
  ) \
  /* */

#define FLUSSPFERD_CD_METHOD__bind(p_cpp_name, p_method_name, p_bound) \
  ::flusspferd::create_native_method( \
      proto, \
      (p_method_name), \
      & p_cpp_name :: p_bound); \
  /* */

#define FLUSSPFERD_CD_METHOD__alias(p_cpp_name, p_method_name, p_alias) \
  proto.define_property( \
    (p_method_name), \
    proto.get_property((p_alias)), \
    ::flusspferd::dont_enumerate); \
  /* */

#define FLUSSPFERD_CLASS_DESCRIPTION(tuple_seq) \
  FLUSSPFERD_CLASS_DESCRIPTION_A(FLUSSPFERD_CD_PARAM(tuple_seq)) \
  /* */

#define FLUSSPFERD_CLASS_DESCRIPTION_END() \
  }; \
  /* */

#endif
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  $RCSfile: c_tydef.hxx,v $
 *
 *  $Revision: 1.2 $
 *
 *  last change: $Author: hr $ $Date: 2003-06-30 15:25:09 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (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.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifndef ARY_CPP_C_TYDEF_HXX
#define ARY_CPP_C_TYDEF_HXX

// USED SERVICES
    // BASE CLASSES
#include <ary/ce.hxx>
    // COMPONENTS
#include <ary/cessentl.hxx>
#include <ary/cpp/c_etypes.hxx>
    // PARAMETERS

namespace ary
{
namespace cpp
{

class Typedef : public CodeEntity
{
  public:
    // LIFECYCLE
                        Typedef();
                        Typedef(
                            Cid                 i_nId,
                            const udmstri &     i_sLocalName,
                            Cid                 i_nOwner,
                            E_Protection        i_eProtection,
                            Lid                 i_nFile,
                            Tid                 i_nDescribingType );
                        ~Typedef();
    // INQUIRY
    static RCid         RC_()                   { return 0x1004; }

    Tid                 DescribingType() const;
    E_Protection        Protection() const      { return eProtection; }

  private:
    // Interface ary::CodeEntity
    virtual Cid         inq_Id() const;
    virtual const udmstri &
                        inq_LocalName() const;
    virtual Cid         inq_Owner() const;
    virtual Lid         inq_Location() const;

    // Interface ary::RepositoryEntity
    virtual void        do_StoreAt(
                            ary::Display &      o_rOut ) const;
    virtual RCid        inq_RC() const;
    virtual const Documentation &
                        inq_Info() const;
    virtual void        do_Add_Documentation(
                            DYN Documentation & let_drInfo );

    // DATA
    CeEssentials        aEssentials;
    Tid                 nDescribingType;
    E_Protection        eProtection;
};

// IMPLEMENTATION

inline Tid
Typedef::DescribingType() const
    { return nDescribingType; }

}   //  namespace cpp
}   //  namespace ary

#endif

<commit_msg>INTEGRATION: CWS ooo19126 (1.2.96); FILE MERGED 2005/09/05 13:09:09 rt 1.2.96.1: #i54170# Change license header: remove SISSL<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: c_tydef.hxx,v $
 *
 *  $Revision: 1.3 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-07 16:01:23 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef ARY_CPP_C_TYDEF_HXX
#define ARY_CPP_C_TYDEF_HXX

// USED SERVICES
    // BASE CLASSES
#include <ary/ce.hxx>
    // COMPONENTS
#include <ary/cessentl.hxx>
#include <ary/cpp/c_etypes.hxx>
    // PARAMETERS

namespace ary
{
namespace cpp
{

class Typedef : public CodeEntity
{
  public:
    // LIFECYCLE
                        Typedef();
                        Typedef(
                            Cid                 i_nId,
                            const udmstri &     i_sLocalName,
                            Cid                 i_nOwner,
                            E_Protection        i_eProtection,
                            Lid                 i_nFile,
                            Tid                 i_nDescribingType );
                        ~Typedef();
    // INQUIRY
    static RCid         RC_()                   { return 0x1004; }

    Tid                 DescribingType() const;
    E_Protection        Protection() const      { return eProtection; }

  private:
    // Interface ary::CodeEntity
    virtual Cid         inq_Id() const;
    virtual const udmstri &
                        inq_LocalName() const;
    virtual Cid         inq_Owner() const;
    virtual Lid         inq_Location() const;

    // Interface ary::RepositoryEntity
    virtual void        do_StoreAt(
                            ary::Display &      o_rOut ) const;
    virtual RCid        inq_RC() const;
    virtual const Documentation &
                        inq_Info() const;
    virtual void        do_Add_Documentation(
                            DYN Documentation & let_drInfo );

    // DATA
    CeEssentials        aEssentials;
    Tid                 nDescribingType;
    E_Protection        eProtection;
};

// IMPLEMENTATION

inline Tid
Typedef::DescribingType() const
    { return nDescribingType; }

}   //  namespace cpp
}   //  namespace ary

#endif

<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: symtreenode.hxx,v $
 *
 *  $Revision: 1.2 $
 *
 *  last change: $Author: hr $ $Date: 2007-11-02 14:43:58 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef ARY_SYMTREE_NODE_HXX
#define ARY_SYMTREE_NODE_HXX

// USED SERVICES
    // BASE CLASSES
    // OTHER

namespace ary
{
namespace symtree
{

/** Represents a node in a tree of symbols like a namespace tree or a
    directory tree.

    @tpl NODE_TRAITS
    Needs to define the types:
        entity_base_type:   The type of the entities in that storage,
                            e.g. ->ary::cpp::CodeEntity.
        id_type:            The type of the ids of those entities,
                            e.g. ->ary::cpp::Ce_id.

    Needs to define the functions:
     1. static entity_base_type &
                            EntityOf_(
                                id_type             i_id );
     2. static id_type      IdOf_(
                                const entity_base_type &
                                                    i_entity );
     3. static symtree::Node<LeNode_Traits> *
                            NodeOf_(
                                const entity_base_type &
                                                    i_entity );
     4. static const String &
                            LocalNameOf_(
                                const entity_base_type &
                                                    i_entity );
     5. static entity_base_type *
                            ParentOf_(
                                const entity_base_type &
                                                    i_entity );
     6. template <class KEY>
        static id_t         Search_(
                                const entity_base_type &
                                                    i_entity,
                                const KEY &         i_localKey );
*/
template <class NODE_TRAITS>
class Node
{
  public:
    typedef Node<NODE_TRAITS>                         node_self;
    typedef typename NODE_TRAITS::entity_base_type    entity_t;
    typedef typename NODE_TRAITS::id_type             id_t;

    // LIFECYCLE
    /// @attention Always needs to be followed by ->Assign_Entity()!
                        Node();
    explicit            Node(
                            entity_t &          i_entity );
    void                Assign_Entity(
                            entity_t &          i_entity );
                        ~Node();
    // INQUIRY
    id_t                Id();
    const String        Name() const;
    int                 Depth() const;
    const entity_t &    Entity() const;
    const node_self *   Parent() const;

    /** Gets a child with a specific name and of a specific type.

        There may be more childs with the same name.

        @return id_t(0), if no matching child is found.
    */
    template <class KEY>
    typename NODE_TRAITS::id_type
                        Search(
                            const KEY &         i_localKey ) const
    {
        // Inline here to workaround SUNW8 compiler bug, works in SUNW12.
        return NODE_TRAITS::Search_(Entity(), i_localKey);
    }

    /** Gets a child with a specific qualified name below this node.

        The child may not exists.
    */
    template <class KEY>
    void                SearchBelow(
                            id_t &              o_return,   // Workaround SUNW8 compiler bug
                            StringVector::const_iterator
                                                i_qualifiedSearchedName_begin,
                            StringVector::const_iterator
                                                i_qualifiedSearchedName_end,
                            const KEY &         i_localKey ) const;

    /** Gets a child with a specific qualified name, either below this node
        or below any of the parent nodes.

        The child may not exists.
    */
    template <class KEY>
    void                SearchUp(
                            id_t &              o_return,   // Workaround SUNW8 compiler bug
                            StringVector::const_iterator
                                                i_qualifiedSearchedName_begin,
                            StringVector::const_iterator
                                                i_qualifiedSearchedName_end,
                            const KEY &         i_localKey ) const;
    // ACCESS
    entity_t &          Entity();
    node_self *         Parent();

  private:
    // Forbid copying:
    Node(const node_self&);
    node_self& operator=(const node_self&);

    // Locals
    void                InitDepth();
    node_self *         Get_Parent() const;
    node_self *         NodeOf(
                            id_t                i_id ) const;

    // DATA
    entity_t *          pEntity;
    int                 nDepth;
};

// IMPLEMENTATION

template <class NODE_TRAITS>
inline const typename Node<NODE_TRAITS>::entity_t &
Node<NODE_TRAITS>::Entity() const
{
    csv_assert(pEntity != 0);
    return *pEntity;
}

template <class NODE_TRAITS>
inline Node<NODE_TRAITS> *
Node<NODE_TRAITS>::NodeOf(id_t i_id) const
{
    if (i_id.IsValid())
        return NODE_TRAITS::NodeOf_(NODE_TRAITS::EntityOf_(i_id));
    return 0;
}

template <class NODE_TRAITS>
inline Node<NODE_TRAITS> *
Node<NODE_TRAITS>::Get_Parent() const
{
    entity_t *
        parent = NODE_TRAITS::ParentOf_(Entity());
    if (parent != 0)
        return NODE_TRAITS::NodeOf_(*parent);
    return 0;
}

template <class NODE_TRAITS>
Node<NODE_TRAITS>::Node()
    :   pEntity(0),
        nDepth(0)
{
}

template <class NODE_TRAITS>
Node<NODE_TRAITS>::Node(entity_t & i_entity)
    :   pEntity(&i_entity),
        nDepth(0)
{
    InitDepth();
}

template <class NODE_TRAITS>
void
Node<NODE_TRAITS>::Assign_Entity(entity_t & i_entity)
{
    pEntity = &i_entity;
    InitDepth();
}

template <class NODE_TRAITS>
Node<NODE_TRAITS>::~Node()
{
}

template <class NODE_TRAITS>
inline typename Node<NODE_TRAITS>::id_t
Node<NODE_TRAITS>::Id()
{
    return NODE_TRAITS::IdOf(Entity());
}

template <class NODE_TRAITS>
inline const String
Node<NODE_TRAITS>::Name() const
{
    return NODE_TRAITS::LocalNameOf_(Entity());
}

template <class NODE_TRAITS>
inline int
Node<NODE_TRAITS>::Depth() const
{
    return nDepth;
}

template <class NODE_TRAITS>
inline const Node<NODE_TRAITS> *
Node<NODE_TRAITS>::Parent() const
{
    return Get_Parent();
}

template <class NODE_TRAITS>
template <class KEY>
void
Node<NODE_TRAITS>::SearchBelow(
                          id_t &              o_return,   // Workaround SUNW8 compiler bug
                          StringVector::const_iterator i_qualifiedSearchedName_begin,
                          StringVector::const_iterator i_qualifiedSearchedName_end,
                          const KEY &                  i_localKey ) const
{
    if (i_qualifiedSearchedName_begin != i_qualifiedSearchedName_end)
    {
        id_t
            next = Search(*i_qualifiedSearchedName_begin);
        if (next.IsValid())
        {
            const node_self *
                subnode = NodeOf(next);
            if (subnode != 0)
            {
                subnode->SearchBelow( o_return,
                                      i_qualifiedSearchedName_begin+1,
                                      i_qualifiedSearchedName_end   ,
                                      i_localKey );
                return;
            }
        }
        o_return = id_t(0);
        return;
    }

    o_return = Search(i_localKey);
}

template <class NODE_TRAITS>
template <class KEY>
void
Node<NODE_TRAITS>::SearchUp(
                          id_t &              o_return,   // Workaround SUNW8 compiler bug
                          StringVector::const_iterator i_qualifiedSearchedName_begin,
                          StringVector::const_iterator i_qualifiedSearchedName_end,
                          const KEY &                  i_localKey ) const
{
    SearchBelow( o_return,
                 i_qualifiedSearchedName_begin,
                 i_qualifiedSearchedName_end,
                 i_localKey );
    if (o_return.IsValid())
        return;

    node_self *
        parent = Get_Parent();
    if (parent != 0)
    {
        parent->SearchUp( o_return,
                          i_qualifiedSearchedName_begin,
                          i_qualifiedSearchedName_end,
                          i_localKey );
    }
}

template <class NODE_TRAITS>
typename Node<NODE_TRAITS>::entity_t &
Node<NODE_TRAITS>::Entity()
{
    csv_assert(pEntity != 0);
    return *pEntity;
}

template <class NODE_TRAITS>
inline Node<NODE_TRAITS> *
Node<NODE_TRAITS>::Parent()
{
    return Get_Parent();
}

template <class NODE_TRAITS>
void
Node<NODE_TRAITS>::InitDepth()
{
    Node<NODE_TRAITS> *
        pp = Get_Parent();
    if (pp != 0)
        nDepth = pp->Depth() + 1;
    else
        nDepth = 0;
}

}   // namespace symtree
}   // namespace ary
#endif
<commit_msg>INTEGRATION: CWS changefileheader (1.2.22); FILE MERGED 2008/03/28 16:00:59 rt 1.2.22.1: #i87441# Change license header to LPGL v3.<commit_after>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: symtreenode.hxx,v $
 * $Revision: 1.3 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org 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 version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

#ifndef ARY_SYMTREE_NODE_HXX
#define ARY_SYMTREE_NODE_HXX

// USED SERVICES
    // BASE CLASSES
    // OTHER

namespace ary
{
namespace symtree
{

/** Represents a node in a tree of symbols like a namespace tree or a
    directory tree.

    @tpl NODE_TRAITS
    Needs to define the types:
        entity_base_type:   The type of the entities in that storage,
                            e.g. ->ary::cpp::CodeEntity.
        id_type:            The type of the ids of those entities,
                            e.g. ->ary::cpp::Ce_id.

    Needs to define the functions:
     1. static entity_base_type &
                            EntityOf_(
                                id_type             i_id );
     2. static id_type      IdOf_(
                                const entity_base_type &
                                                    i_entity );
     3. static symtree::Node<LeNode_Traits> *
                            NodeOf_(
                                const entity_base_type &
                                                    i_entity );
     4. static const String &
                            LocalNameOf_(
                                const entity_base_type &
                                                    i_entity );
     5. static entity_base_type *
                            ParentOf_(
                                const entity_base_type &
                                                    i_entity );
     6. template <class KEY>
        static id_t         Search_(
                                const entity_base_type &
                                                    i_entity,
                                const KEY &         i_localKey );
*/
template <class NODE_TRAITS>
class Node
{
  public:
    typedef Node<NODE_TRAITS>                         node_self;
    typedef typename NODE_TRAITS::entity_base_type    entity_t;
    typedef typename NODE_TRAITS::id_type             id_t;

    // LIFECYCLE
    /// @attention Always needs to be followed by ->Assign_Entity()!
                        Node();
    explicit            Node(
                            entity_t &          i_entity );
    void                Assign_Entity(
                            entity_t &          i_entity );
                        ~Node();
    // INQUIRY
    id_t                Id();
    const String        Name() const;
    int                 Depth() const;
    const entity_t &    Entity() const;
    const node_self *   Parent() const;

    /** Gets a child with a specific name and of a specific type.

        There may be more childs with the same name.

        @return id_t(0), if no matching child is found.
    */
    template <class KEY>
    typename NODE_TRAITS::id_type
                        Search(
                            const KEY &         i_localKey ) const
    {
        // Inline here to workaround SUNW8 compiler bug, works in SUNW12.
        return NODE_TRAITS::Search_(Entity(), i_localKey);
    }

    /** Gets a child with a specific qualified name below this node.

        The child may not exists.
    */
    template <class KEY>
    void                SearchBelow(
                            id_t &              o_return,   // Workaround SUNW8 compiler bug
                            StringVector::const_iterator
                                                i_qualifiedSearchedName_begin,
                            StringVector::const_iterator
                                                i_qualifiedSearchedName_end,
                            const KEY &         i_localKey ) const;

    /** Gets a child with a specific qualified name, either below this node
        or below any of the parent nodes.

        The child may not exists.
    */
    template <class KEY>
    void                SearchUp(
                            id_t &              o_return,   // Workaround SUNW8 compiler bug
                            StringVector::const_iterator
                                                i_qualifiedSearchedName_begin,
                            StringVector::const_iterator
                                                i_qualifiedSearchedName_end,
                            const KEY &         i_localKey ) const;
    // ACCESS
    entity_t &          Entity();
    node_self *         Parent();

  private:
    // Forbid copying:
    Node(const node_self&);
    node_self& operator=(const node_self&);

    // Locals
    void                InitDepth();
    node_self *         Get_Parent() const;
    node_self *         NodeOf(
                            id_t                i_id ) const;

    // DATA
    entity_t *          pEntity;
    int                 nDepth;
};

// IMPLEMENTATION

template <class NODE_TRAITS>
inline const typename Node<NODE_TRAITS>::entity_t &
Node<NODE_TRAITS>::Entity() const
{
    csv_assert(pEntity != 0);
    return *pEntity;
}

template <class NODE_TRAITS>
inline Node<NODE_TRAITS> *
Node<NODE_TRAITS>::NodeOf(id_t i_id) const
{
    if (i_id.IsValid())
        return NODE_TRAITS::NodeOf_(NODE_TRAITS::EntityOf_(i_id));
    return 0;
}

template <class NODE_TRAITS>
inline Node<NODE_TRAITS> *
Node<NODE_TRAITS>::Get_Parent() const
{
    entity_t *
        parent = NODE_TRAITS::ParentOf_(Entity());
    if (parent != 0)
        return NODE_TRAITS::NodeOf_(*parent);
    return 0;
}

template <class NODE_TRAITS>
Node<NODE_TRAITS>::Node()
    :   pEntity(0),
        nDepth(0)
{
}

template <class NODE_TRAITS>
Node<NODE_TRAITS>::Node(entity_t & i_entity)
    :   pEntity(&i_entity),
        nDepth(0)
{
    InitDepth();
}

template <class NODE_TRAITS>
void
Node<NODE_TRAITS>::Assign_Entity(entity_t & i_entity)
{
    pEntity = &i_entity;
    InitDepth();
}

template <class NODE_TRAITS>
Node<NODE_TRAITS>::~Node()
{
}

template <class NODE_TRAITS>
inline typename Node<NODE_TRAITS>::id_t
Node<NODE_TRAITS>::Id()
{
    return NODE_TRAITS::IdOf(Entity());
}

template <class NODE_TRAITS>
inline const String
Node<NODE_TRAITS>::Name() const
{
    return NODE_TRAITS::LocalNameOf_(Entity());
}

template <class NODE_TRAITS>
inline int
Node<NODE_TRAITS>::Depth() const
{
    return nDepth;
}

template <class NODE_TRAITS>
inline const Node<NODE_TRAITS> *
Node<NODE_TRAITS>::Parent() const
{
    return Get_Parent();
}

template <class NODE_TRAITS>
template <class KEY>
void
Node<NODE_TRAITS>::SearchBelow(
                          id_t &              o_return,   // Workaround SUNW8 compiler bug
                          StringVector::const_iterator i_qualifiedSearchedName_begin,
                          StringVector::const_iterator i_qualifiedSearchedName_end,
                          const KEY &                  i_localKey ) const
{
    if (i_qualifiedSearchedName_begin != i_qualifiedSearchedName_end)
    {
        id_t
            next = Search(*i_qualifiedSearchedName_begin);
        if (next.IsValid())
        {
            const node_self *
                subnode = NodeOf(next);
            if (subnode != 0)
            {
                subnode->SearchBelow( o_return,
                                      i_qualifiedSearchedName_begin+1,
                                      i_qualifiedSearchedName_end   ,
                                      i_localKey );
                return;
            }
        }
        o_return = id_t(0);
        return;
    }

    o_return = Search(i_localKey);
}

template <class NODE_TRAITS>
template <class KEY>
void
Node<NODE_TRAITS>::SearchUp(
                          id_t &              o_return,   // Workaround SUNW8 compiler bug
                          StringVector::const_iterator i_qualifiedSearchedName_begin,
                          StringVector::const_iterator i_qualifiedSearchedName_end,
                          const KEY &                  i_localKey ) const
{
    SearchBelow( o_return,
                 i_qualifiedSearchedName_begin,
                 i_qualifiedSearchedName_end,
                 i_localKey );
    if (o_return.IsValid())
        return;

    node_self *
        parent = Get_Parent();
    if (parent != 0)
    {
        parent->SearchUp( o_return,
                          i_qualifiedSearchedName_begin,
                          i_qualifiedSearchedName_end,
                          i_localKey );
    }
}

template <class NODE_TRAITS>
typename Node<NODE_TRAITS>::entity_t &
Node<NODE_TRAITS>::Entity()
{
    csv_assert(pEntity != 0);
    return *pEntity;
}

template <class NODE_TRAITS>
inline Node<NODE_TRAITS> *
Node<NODE_TRAITS>::Parent()
{
    return Get_Parent();
}

template <class NODE_TRAITS>
void
Node<NODE_TRAITS>::InitDepth()
{
    Node<NODE_TRAITS> *
        pp = Get_Parent();
    if (pp != 0)
        nDepth = pp->Depth() + 1;
    else
        nDepth = 0;
}

}   // namespace symtree
}   // namespace ary
#endif
<|endoftext|>


<commit_before>#include "Cache.h"

#include "preprocessor/llvm_includes_start.h"
#include <llvm/IR/Module.h>
#include <llvm/IR/LLVMContext.h>
#include <llvm/IR/Instructions.h>
#include <llvm/ExecutionEngine/ExecutionEngine.h>
#include <llvm/Support/Path.h>
#include <llvm/Support/FileSystem.h>
#include <llvm/Support/raw_os_ostream.h>
#include "preprocessor/llvm_includes_end.h"

#include "ExecutionEngine.h"
#include "Utils.h"
#include "BuildInfo.gen.h"

namespace dev
{
namespace eth
{
namespace jit
{

namespace
{
	CacheMode g_mode;
	llvm::MemoryBuffer* g_lastObject;
	ExecutionEngineListener* g_listener;
	static const size_t c_versionStampLength = 32;

	llvm::StringRef getLibVersionStamp()
	{
		static auto version = llvm::SmallString<c_versionStampLength>{};
		if (version.empty())
		{
			version = EVMJIT_VERSION_FULL;
			version.resize(c_versionStampLength);
		}
		return version;
	}
}

ObjectCache* Cache::getObjectCache(CacheMode _mode, ExecutionEngineListener* _listener)
{
	static ObjectCache objectCache;
	g_mode = _mode;
	g_listener = _listener;
	return &objectCache;
}

void Cache::clear()
{
	using namespace llvm::sys;
	llvm::SmallString<256> cachePath;
	path::system_temp_directory(false, cachePath);
	path::append(cachePath, "evm_objs");

	std::error_code err;
	for (auto it = fs::directory_iterator{cachePath.str(), err}; it != fs::directory_iterator{}; it.increment(err))
		fs::remove(it->path());
}

void Cache::preload(llvm::ExecutionEngine& _ee, std::unordered_map<std::string, uint64_t>& _funcCache)
{
	// TODO: Cache dir should be in one place
	using namespace llvm::sys;
	llvm::SmallString<256> cachePath;
	path::system_temp_directory(false, cachePath);
	path::append(cachePath, "evm_objs");

	// Disable listener
	auto listener = g_listener;
	g_listener = nullptr;

	std::error_code err;
	for (auto it = fs::directory_iterator{cachePath.str(), err}; it != fs::directory_iterator{}; it.increment(err))
	{
		auto name = it->path().substr(cachePath.size() + 1);
		if (auto module = getObject(name))
		{
			DLOG(cache) << "Preload: " << name << "\n";
			_ee.addModule(module.get());
			module.release();
			auto addr = _ee.getFunctionAddress(name);
			assert(addr);
			_funcCache[std::move(name)] = addr;
		}
	}

	g_listener = listener;
}

std::unique_ptr<llvm::Module> Cache::getObject(std::string const& id)
{
	if (g_mode != CacheMode::on && g_mode != CacheMode::read)
		return nullptr;

	if (g_listener)
		g_listener->stateChanged(ExecState::CacheLoad);

	DLOG(cache) << id << ": search\n";
	if (!CHECK(!g_lastObject))
		g_lastObject = nullptr;

	llvm::SmallString<256> cachePath;
	llvm::sys::path::system_temp_directory(false, cachePath);
	llvm::sys::path::append(cachePath, "evm_objs", id);

	if (auto r = llvm::MemoryBuffer::getFile(cachePath.str(), -1, false))
	{
		auto& buf = r.get();
		auto objVersionStamp = buf->getBufferSize() >= c_versionStampLength ? llvm::StringRef{buf->getBufferEnd() - c_versionStampLength, c_versionStampLength} : llvm::StringRef{};
		if (objVersionStamp == getLibVersionStamp())
			g_lastObject = llvm::MemoryBuffer::getMemBufferCopy(r.get()->getBuffer());
		else
			DLOG(cache) << "Unmatched version: " << objVersionStamp.str() << ", expected " << getLibVersionStamp().str() << "\n";
	}
	else if (r.getError() != std::make_error_code(std::errc::no_such_file_or_directory))
		DLOG(cache) << r.getError().message(); // TODO: Add warning log

	if (g_lastObject)  // if object found create fake module
	{
		DLOG(cache) << id << ": found\n";
		auto&& context = llvm::getGlobalContext();
		auto module = std::unique_ptr<llvm::Module>(new llvm::Module(id, context));
		auto mainFuncType = llvm::FunctionType::get(llvm::Type::getVoidTy(context), {}, false);
		auto mainFunc = llvm::Function::Create(mainFuncType, llvm::Function::ExternalLinkage, id, module.get());
		auto bb = llvm::BasicBlock::Create(context, {}, mainFunc);
		bb->getInstList().push_back(new llvm::UnreachableInst{context});
		return module;
	}
	DLOG(cache) << id << ": not found\n";
	return nullptr;
}

void ObjectCache::notifyObjectCompiled(llvm::Module const* _module, llvm::MemoryBuffer const* _object)
{
	// Only in "on" and "write" mode
	if (g_mode != CacheMode::on && g_mode != CacheMode::write)
		return;

	if (g_listener)
		g_listener->stateChanged(ExecState::CacheWrite);

	auto&& id = _module->getModuleIdentifier();
	llvm::SmallString<256> cachePath;
	llvm::sys::path::system_temp_directory(false, cachePath);
	llvm::sys::path::append(cachePath, "evm_objs");

	if (llvm::sys::fs::create_directory(cachePath.str()))
		DLOG(cache) << "Cannot create cache dir " << cachePath.str().str() << "\n";

	llvm::sys::path::append(cachePath, id);

	DLOG(cache) << id << ": write\n";
	std::string error;
	llvm::raw_fd_ostream cacheFile(cachePath.c_str(), error, llvm::sys::fs::F_None);
	cacheFile << _object->getBuffer() << getLibVersionStamp();
}

llvm::MemoryBuffer* ObjectCache::getObject(llvm::Module const* _module)
{
	DLOG(cache) << _module->getModuleIdentifier() << ": use\n";
	auto o = g_lastObject;
	g_lastObject = nullptr;
	return o;
}

}
}
}
<commit_msg>Protect EVM JIT cache with mutex.<commit_after>#include "Cache.h"

#include <mutex>

#include "preprocessor/llvm_includes_start.h"
#include <llvm/IR/Module.h>
#include <llvm/IR/LLVMContext.h>
#include <llvm/IR/Instructions.h>
#include <llvm/ExecutionEngine/ExecutionEngine.h>
#include <llvm/Support/Path.h>
#include <llvm/Support/FileSystem.h>
#include <llvm/Support/raw_os_ostream.h>
#include "preprocessor/llvm_includes_end.h"

#include "ExecutionEngine.h"
#include "Utils.h"
#include "BuildInfo.gen.h"

namespace dev
{
namespace eth
{
namespace jit
{

namespace
{
	using Guard = std::lock_guard<std::mutex>;
	std::mutex x_cacheMutex;
	CacheMode g_mode;
	llvm::MemoryBuffer* g_lastObject;
	ExecutionEngineListener* g_listener;
	static const size_t c_versionStampLength = 32;

	llvm::StringRef getLibVersionStamp()
	{
		static auto version = llvm::SmallString<c_versionStampLength>{};
		if (version.empty())
		{
			version = EVMJIT_VERSION_FULL;
			version.resize(c_versionStampLength);
		}
		return version;
	}
}

ObjectCache* Cache::getObjectCache(CacheMode _mode, ExecutionEngineListener* _listener)
{
	static ObjectCache objectCache;

	Guard g{x_cacheMutex};

	g_mode = _mode;
	g_listener = _listener;
	return &objectCache;
}

void Cache::clear()
{
	Guard g{x_cacheMutex};

	using namespace llvm::sys;
	llvm::SmallString<256> cachePath;
	path::system_temp_directory(false, cachePath);
	path::append(cachePath, "evm_objs");

	std::error_code err;
	for (auto it = fs::directory_iterator{cachePath.str(), err}; it != fs::directory_iterator{}; it.increment(err))
		fs::remove(it->path());
}

void Cache::preload(llvm::ExecutionEngine& _ee, std::unordered_map<std::string, uint64_t>& _funcCache)
{
	Guard g{x_cacheMutex};

	// TODO: Cache dir should be in one place
	using namespace llvm::sys;
	llvm::SmallString<256> cachePath;
	path::system_temp_directory(false, cachePath);
	path::append(cachePath, "evm_objs");

	// Disable listener
	auto listener = g_listener;
	g_listener = nullptr;

	std::error_code err;
	for (auto it = fs::directory_iterator{cachePath.str(), err}; it != fs::directory_iterator{}; it.increment(err))
	{
		auto name = it->path().substr(cachePath.size() + 1);
		if (auto module = getObject(name))
		{
			DLOG(cache) << "Preload: " << name << "\n";
			_ee.addModule(module.get());
			module.release();
			auto addr = _ee.getFunctionAddress(name);
			assert(addr);
			_funcCache[std::move(name)] = addr;
		}
	}

	g_listener = listener;
}

std::unique_ptr<llvm::Module> Cache::getObject(std::string const& id)
{
	Guard g{x_cacheMutex};

	if (g_mode != CacheMode::on && g_mode != CacheMode::read)
		return nullptr;

	// TODO: Disabled because is not thread-safe.
	//if (g_listener)
	//	g_listener->stateChanged(ExecState::CacheLoad);

	DLOG(cache) << id << ": search\n";
	if (!CHECK(!g_lastObject))
		g_lastObject = nullptr;

	llvm::SmallString<256> cachePath;
	llvm::sys::path::system_temp_directory(false, cachePath);
	llvm::sys::path::append(cachePath, "evm_objs", id);

	if (auto r = llvm::MemoryBuffer::getFile(cachePath.str(), -1, false))
	{
		auto& buf = r.get();
		auto objVersionStamp = buf->getBufferSize() >= c_versionStampLength ? llvm::StringRef{buf->getBufferEnd() - c_versionStampLength, c_versionStampLength} : llvm::StringRef{};
		if (objVersionStamp == getLibVersionStamp())
			g_lastObject = llvm::MemoryBuffer::getMemBufferCopy(r.get()->getBuffer());
		else
			DLOG(cache) << "Unmatched version: " << objVersionStamp.str() << ", expected " << getLibVersionStamp().str() << "\n";
	}
	else if (r.getError() != std::make_error_code(std::errc::no_such_file_or_directory))
		DLOG(cache) << r.getError().message(); // TODO: Add warning log

	if (g_lastObject)  // if object found create fake module
	{
		DLOG(cache) << id << ": found\n";
		auto&& context = llvm::getGlobalContext();
		auto module = std::unique_ptr<llvm::Module>(new llvm::Module(id, context));
		auto mainFuncType = llvm::FunctionType::get(llvm::Type::getVoidTy(context), {}, false);
		auto mainFunc = llvm::Function::Create(mainFuncType, llvm::Function::ExternalLinkage, id, module.get());
		auto bb = llvm::BasicBlock::Create(context, {}, mainFunc);
		bb->getInstList().push_back(new llvm::UnreachableInst{context});
		return module;
	}
	DLOG(cache) << id << ": not found\n";
	return nullptr;
}

void ObjectCache::notifyObjectCompiled(llvm::Module const* _module, llvm::MemoryBuffer const* _object)
{
	Guard g{x_cacheMutex};

	// Only in "on" and "write" mode
	if (g_mode != CacheMode::on && g_mode != CacheMode::write)
		return;

	// TODO: Disabled because is not thread-safe.
	// if (g_listener)
		// g_listener->stateChanged(ExecState::CacheWrite);

	auto&& id = _module->getModuleIdentifier();
	llvm::SmallString<256> cachePath;
	llvm::sys::path::system_temp_directory(false, cachePath);
	llvm::sys::path::append(cachePath, "evm_objs");

	if (llvm::sys::fs::create_directory(cachePath.str()))
		DLOG(cache) << "Cannot create cache dir " << cachePath.str().str() << "\n";

	llvm::sys::path::append(cachePath, id);

	DLOG(cache) << id << ": write\n";
	std::string error;
	llvm::raw_fd_ostream cacheFile(cachePath.c_str(), error, llvm::sys::fs::F_None);
	cacheFile << _object->getBuffer() << getLibVersionStamp();
}

llvm::MemoryBuffer* ObjectCache::getObject(llvm::Module const* _module)
{
	Guard g{x_cacheMutex};

	DLOG(cache) << _module->getModuleIdentifier() << ": use\n";
	auto o = g_lastObject;
	g_lastObject = nullptr;
	return o;
}

}
}
}
<|endoftext|>


<commit_before>//===- lib/Driver/GnuLdDriver.cpp -----------------------------------------===//
//
//                             The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
///
/// \file
///
/// Concrete instance of the Driver for GNU's ld.
///
//===----------------------------------------------------------------------===//

#include "lld/Driver/Driver.h"
#include "lld/Driver/GnuLdInputGraph.h"

#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/Triple.h"
#include "llvm/Option/Arg.h"
#include "llvm/Option/Option.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Host.h"
#include "llvm/Support/ManagedStatic.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/PrettyStackTrace.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/Signals.h"

using namespace lld;

namespace {

// Create enum with OPT_xxx values for each option in GnuLdOptions.td
enum {
  OPT_INVALID = 0,
#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
               HELP, META) \
          OPT_##ID,
#include "GnuLdOptions.inc"
#undef OPTION
};

// Create prefix string literals used in GnuLdOptions.td
#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
#include "GnuLdOptions.inc"
#undef PREFIX

// Create table mapping all options defined in GnuLdOptions.td
static const llvm::opt::OptTable::Info infoTable[] = {
#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
               HELPTEXT, METAVAR)   \
  { PREFIX, NAME, HELPTEXT, METAVAR, OPT_##ID, llvm::opt::Option::KIND##Class, \
    PARAM, FLAGS, OPT_##GROUP, OPT_##ALIAS, ALIASARGS },
#include "GnuLdOptions.inc"
#undef OPTION
};

// Create OptTable class for parsing actual command line arguments
class GnuLdOptTable : public llvm::opt::OptTable {
public:
  GnuLdOptTable() : OptTable(infoTable, llvm::array_lengthof(infoTable)){}
};

} // namespace

llvm::ErrorOr<std::unique_ptr<lld::LinkerInput> >
ELFFileNode::createLinkerInput(const LinkingContext &ctx) {
  auto inputFile(FileNode::createLinkerInput(ctx));

  if (inputFile) {
    (*inputFile)->setAsNeeded(_asNeeded);
    (*inputFile)->setWholeArchive(_isWholeArchive);
  }
  return std::move(inputFile);
}

llvm::ErrorOr<StringRef> ELFFileNode::path(const LinkingContext &) const {
  if (!_isDashlPrefix)
    return _path;
  return _elfLinkingContext.searchLibrary(_path, _libraryPaths);
}

std::string ELFFileNode::errStr(llvm::error_code errc) {
  std::string errorMsg;
  if (errc == llvm::errc::no_such_file_or_directory) {
    if (_isDashlPrefix)
      errorMsg = (Twine("Unable to find library -l") + _path).str();
    else
      errorMsg = (Twine("Unable to find file ") + _path).str();
  }
  else {
    return "Unknown Error";
  }
  return std::move(errorMsg);
}

bool GnuLdDriver::linkELF(int argc, const char *argv[],
                          raw_ostream &diagnostics) {
  std::unique_ptr<ELFLinkingContext> options;
  bool error = parse(argc, argv, options, diagnostics);
  if (error)
    return true;
  if (!options)
    return false;

  return link(*options, diagnostics);
}

bool GnuLdDriver::parse(int argc, const char *argv[],
                        std::unique_ptr<ELFLinkingContext> &context,
                        raw_ostream &diagnostics) {
  // Parse command line options using GnuLdOptions.td
  std::unique_ptr<llvm::opt::InputArgList> parsedArgs;
  GnuLdOptTable table;
  unsigned missingIndex;
  unsigned missingCount;

  parsedArgs.reset(
      table.ParseArgs(&argv[1], &argv[argc], missingIndex, missingCount));
  if (missingCount) {
    diagnostics << "error: missing arg value for '"
                << parsedArgs->getArgString(missingIndex) << "' expected "
                << missingCount << " argument(s).\n";
    return true;
  }

  // Handle --help
  if (parsedArgs->getLastArg(OPT_help)) {
    table.PrintHelp(llvm::outs(), argv[0], "LLVM Linker", false);
    return false;
  }

  // Use -target or use default target triple to instantiate LinkingContext
  llvm::Triple triple;
  if (llvm::opt::Arg *trip = parsedArgs->getLastArg(OPT_target))
    triple = llvm::Triple(trip->getValue());
  else
    triple = getDefaultTarget(argv[0]);
  std::unique_ptr<ELFLinkingContext> ctx(ELFLinkingContext::create(triple));

  if (!ctx) {
    diagnostics << "unknown target triple\n";
    return true;
  }

  std::unique_ptr<InputGraph> inputGraph(new InputGraph());
  std::stack<InputElement *> controlNodeStack;

  // Positional options for an Input File
  std::vector<StringRef> searchPath;
  bool isWholeArchive = false;
  bool asNeeded = false;
  bool _outputOptionSet = false;

  // Create a dynamic executable by default
  ctx->setOutputFileType(llvm::ELF::ET_EXEC);
  ctx->setIsStaticExecutable(false);
  ctx->setAllowShlibUndefines(false);
  ctx->setUseShlibUndefines(true);

  // Set the output file to be a.out
  ctx->setOutputPath("a.out");

  // Process all the arguments and create Input Elements
  for (auto inputArg : *parsedArgs) {
    switch (inputArg->getOption().getID()) {
    case OPT_mllvm:
      ctx->appendLLVMOption(inputArg->getValue());
      break;
    case OPT_relocatable:
      ctx->setOutputFileType(llvm::ELF::ET_REL);
      ctx->setPrintRemainingUndefines(false);
      ctx->setAllowRemainingUndefines(true);
      break;
    case OPT_static:
      ctx->setOutputFileType(llvm::ELF::ET_EXEC);
      ctx->setIsStaticExecutable(true);
      break;
    case OPT_shared:
      ctx->setOutputFileType(llvm::ELF::ET_DYN);
      ctx->setAllowShlibUndefines(true);
      ctx->setUseShlibUndefines(false);
      break;
    case OPT_e:
      ctx->setEntrySymbolName(inputArg->getValue());
      break;

    case OPT_output:
      _outputOptionSet = true;
      ctx->setOutputPath(inputArg->getValue());
      break;

    case OPT_noinhibit_exec:
      ctx->setAllowRemainingUndefines(true);
      break;

    case OPT_merge_strings:
      ctx->setMergeCommonStrings(true);
      break;

    case OPT_t:
      ctx->setLogInputFiles(true);
      break;

    case OPT_no_allow_shlib_undefs:
      ctx->setAllowShlibUndefines(false);
      break;

    case OPT_allow_shlib_undefs:
      ctx->setAllowShlibUndefines(true);
      break;

    case OPT_use_shlib_undefs:
      ctx->setUseShlibUndefines(true);
      break;

    case OPT_dynamic_linker:
      ctx->setInterpreter(inputArg->getValue());
      break;

    case OPT_nmagic:
      ctx->setOutputMagic(ELFLinkingContext::OutputMagic::NMAGIC);
      ctx->setIsStaticExecutable(true);
      break;

    case OPT_omagic:
      ctx->setOutputMagic(ELFLinkingContext::OutputMagic::OMAGIC);
      ctx->setIsStaticExecutable(true);
      break;

    case OPT_no_omagic:
      ctx->setOutputMagic(ELFLinkingContext::OutputMagic::DEFAULT);
      ctx->setNoAllowDynamicLibraries();
      break;

    case OPT_u:
      ctx->addInitialUndefinedSymbol(inputArg->getValue());
      break;

    case OPT_init:
      ctx->addInitFunction(inputArg->getValue());
      break;

    case OPT_fini:
      ctx->addFiniFunction(inputArg->getValue());
      break;

    case OPT_emit_yaml:
      if (!_outputOptionSet)
        ctx->setOutputPath("-");
      ctx->setOutputYAML(true);
      break;

    case OPT_no_whole_archive:
      isWholeArchive = false;
      break;
    case OPT_whole_archive:
      isWholeArchive = true;
      break;
    case OPT_as_needed:
      asNeeded = true;
      break;
    case OPT_no_as_needed:
      asNeeded = false;
      break;
    case OPT_L:
      searchPath.push_back(inputArg->getValue());
      break;

    case OPT_start_group: {
      std::unique_ptr<InputElement> controlStart(new ELFGroup(*ctx));
      controlNodeStack.push(controlStart.get());
      (llvm::dyn_cast<ControlNode>)(controlNodeStack.top())
          ->processControlEnter();
      inputGraph->addInputElement(std::move(controlStart));
      break;
    }

    case OPT_end_group:
      (llvm::dyn_cast<ControlNode>)(controlNodeStack.top())
          ->processControlExit();
      controlNodeStack.pop();
      return false;

    case OPT_INPUT:
    case OPT_l: {
      std::unique_ptr<InputElement> inputFile =
          std::move(std::unique_ptr<InputElement>(new ELFFileNode(
              *ctx, inputArg->getValue(), searchPath, isWholeArchive, asNeeded,
              inputArg->getOption().getID() == OPT_l)));
      if (controlNodeStack.empty())
        inputGraph->addInputElement(std::move(inputFile));
      else
        (llvm::dyn_cast<ControlNode>)(controlNodeStack.top())
            ->processInputElement(std::move(inputFile));
      break;
    }

    case OPT_rpath: {
      SmallVector<StringRef, 2> rpaths;
      StringRef(inputArg->getValue()).split(rpaths, ":");
      for (auto path : rpaths)
        ctx->addRpath(path);
      break;
    }

    case OPT_rpath_link: {
      SmallVector<StringRef, 2> rpaths;
      StringRef(inputArg->getValue()).split(rpaths, ":");
      for (auto path : rpaths)
        ctx->addRpathLink(path);
      break;
    }

    case OPT_sysroot:
      ctx->setSysroot(inputArg->getValue());
      break;

    case OPT_soname:
      ctx->setSharedObjectName(inputArg->getValue());
      break;

    default:
      break;
    } // end switch on option ID
  }   // end for

  if (!inputGraph->numFiles()) {
    diagnostics << "No input files\n";
    return true;
  }

  inputGraph->addInternalFile(ctx->createInternalFiles());

  if (ctx->outputYAML())
    inputGraph->dump(diagnostics);

  // Validate the combination of options used.
  if (ctx->validate(diagnostics))
    return true;

  ctx->setInputGraph(std::move(inputGraph));

  context.swap(ctx);

  return false;
}

/// Get the default target triple based on either the program name
/// (e.g. "x86-ibm-linux-lld") or the primary target llvm was configured for.
llvm::Triple GnuLdDriver::getDefaultTarget(const char *progName) {
  SmallVector<StringRef, 4> components;
  llvm::SplitString(llvm::sys::path::stem(progName), components, "-");
  // If has enough parts to be start with a triple.
  if (components.size() >= 4) {
    llvm::Triple triple(components[0], components[1], components[2],
                        components[3]);
    // If first component looks like an arch.
    if (triple.getArch() != llvm::Triple::UnknownArch)
      return triple;
  }

  // Fallback to use whatever default triple llvm was configured for.
  return llvm::Triple(llvm::sys::getDefaultTargetTriple());
}
<commit_msg>Fallback to the default stringize function to show some meaningful error message.<commit_after>//===- lib/Driver/GnuLdDriver.cpp -----------------------------------------===//
//
//                             The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
///
/// \file
///
/// Concrete instance of the Driver for GNU's ld.
///
//===----------------------------------------------------------------------===//

#include "lld/Driver/Driver.h"
#include "lld/Driver/GnuLdInputGraph.h"

#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/Triple.h"
#include "llvm/Option/Arg.h"
#include "llvm/Option/Option.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Host.h"
#include "llvm/Support/ManagedStatic.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/PrettyStackTrace.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/Signals.h"

using namespace lld;

namespace {

// Create enum with OPT_xxx values for each option in GnuLdOptions.td
enum {
  OPT_INVALID = 0,
#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
               HELP, META) \
          OPT_##ID,
#include "GnuLdOptions.inc"
#undef OPTION
};

// Create prefix string literals used in GnuLdOptions.td
#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
#include "GnuLdOptions.inc"
#undef PREFIX

// Create table mapping all options defined in GnuLdOptions.td
static const llvm::opt::OptTable::Info infoTable[] = {
#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
               HELPTEXT, METAVAR)   \
  { PREFIX, NAME, HELPTEXT, METAVAR, OPT_##ID, llvm::opt::Option::KIND##Class, \
    PARAM, FLAGS, OPT_##GROUP, OPT_##ALIAS, ALIASARGS },
#include "GnuLdOptions.inc"
#undef OPTION
};

// Create OptTable class for parsing actual command line arguments
class GnuLdOptTable : public llvm::opt::OptTable {
public:
  GnuLdOptTable() : OptTable(infoTable, llvm::array_lengthof(infoTable)){}
};

} // namespace

llvm::ErrorOr<std::unique_ptr<lld::LinkerInput> >
ELFFileNode::createLinkerInput(const LinkingContext &ctx) {
  auto inputFile(FileNode::createLinkerInput(ctx));

  if (inputFile) {
    (*inputFile)->setAsNeeded(_asNeeded);
    (*inputFile)->setWholeArchive(_isWholeArchive);
  }
  return std::move(inputFile);
}

llvm::ErrorOr<StringRef> ELFFileNode::path(const LinkingContext &) const {
  if (!_isDashlPrefix)
    return _path;
  return _elfLinkingContext.searchLibrary(_path, _libraryPaths);
}

std::string ELFFileNode::errStr(llvm::error_code errc) {
  if (errc == llvm::errc::no_such_file_or_directory) {
    if (_isDashlPrefix)
      return (Twine("Unable to find library -l") + _path).str();
    return (Twine("Unable to find file ") + _path).str();
  }
  return FileNode::errStr(errc);
}

bool GnuLdDriver::linkELF(int argc, const char *argv[],
                          raw_ostream &diagnostics) {
  std::unique_ptr<ELFLinkingContext> options;
  bool error = parse(argc, argv, options, diagnostics);
  if (error)
    return true;
  if (!options)
    return false;

  return link(*options, diagnostics);
}

bool GnuLdDriver::parse(int argc, const char *argv[],
                        std::unique_ptr<ELFLinkingContext> &context,
                        raw_ostream &diagnostics) {
  // Parse command line options using GnuLdOptions.td
  std::unique_ptr<llvm::opt::InputArgList> parsedArgs;
  GnuLdOptTable table;
  unsigned missingIndex;
  unsigned missingCount;

  parsedArgs.reset(
      table.ParseArgs(&argv[1], &argv[argc], missingIndex, missingCount));
  if (missingCount) {
    diagnostics << "error: missing arg value for '"
                << parsedArgs->getArgString(missingIndex) << "' expected "
                << missingCount << " argument(s).\n";
    return true;
  }

  // Handle --help
  if (parsedArgs->getLastArg(OPT_help)) {
    table.PrintHelp(llvm::outs(), argv[0], "LLVM Linker", false);
    return false;
  }

  // Use -target or use default target triple to instantiate LinkingContext
  llvm::Triple triple;
  if (llvm::opt::Arg *trip = parsedArgs->getLastArg(OPT_target))
    triple = llvm::Triple(trip->getValue());
  else
    triple = getDefaultTarget(argv[0]);
  std::unique_ptr<ELFLinkingContext> ctx(ELFLinkingContext::create(triple));

  if (!ctx) {
    diagnostics << "unknown target triple\n";
    return true;
  }

  std::unique_ptr<InputGraph> inputGraph(new InputGraph());
  std::stack<InputElement *> controlNodeStack;

  // Positional options for an Input File
  std::vector<StringRef> searchPath;
  bool isWholeArchive = false;
  bool asNeeded = false;
  bool _outputOptionSet = false;

  // Create a dynamic executable by default
  ctx->setOutputFileType(llvm::ELF::ET_EXEC);
  ctx->setIsStaticExecutable(false);
  ctx->setAllowShlibUndefines(false);
  ctx->setUseShlibUndefines(true);

  // Set the output file to be a.out
  ctx->setOutputPath("a.out");

  // Process all the arguments and create Input Elements
  for (auto inputArg : *parsedArgs) {
    switch (inputArg->getOption().getID()) {
    case OPT_mllvm:
      ctx->appendLLVMOption(inputArg->getValue());
      break;
    case OPT_relocatable:
      ctx->setOutputFileType(llvm::ELF::ET_REL);
      ctx->setPrintRemainingUndefines(false);
      ctx->setAllowRemainingUndefines(true);
      break;
    case OPT_static:
      ctx->setOutputFileType(llvm::ELF::ET_EXEC);
      ctx->setIsStaticExecutable(true);
      break;
    case OPT_shared:
      ctx->setOutputFileType(llvm::ELF::ET_DYN);
      ctx->setAllowShlibUndefines(true);
      ctx->setUseShlibUndefines(false);
      break;
    case OPT_e:
      ctx->setEntrySymbolName(inputArg->getValue());
      break;

    case OPT_output:
      _outputOptionSet = true;
      ctx->setOutputPath(inputArg->getValue());
      break;

    case OPT_noinhibit_exec:
      ctx->setAllowRemainingUndefines(true);
      break;

    case OPT_merge_strings:
      ctx->setMergeCommonStrings(true);
      break;

    case OPT_t:
      ctx->setLogInputFiles(true);
      break;

    case OPT_no_allow_shlib_undefs:
      ctx->setAllowShlibUndefines(false);
      break;

    case OPT_allow_shlib_undefs:
      ctx->setAllowShlibUndefines(true);
      break;

    case OPT_use_shlib_undefs:
      ctx->setUseShlibUndefines(true);
      break;

    case OPT_dynamic_linker:
      ctx->setInterpreter(inputArg->getValue());
      break;

    case OPT_nmagic:
      ctx->setOutputMagic(ELFLinkingContext::OutputMagic::NMAGIC);
      ctx->setIsStaticExecutable(true);
      break;

    case OPT_omagic:
      ctx->setOutputMagic(ELFLinkingContext::OutputMagic::OMAGIC);
      ctx->setIsStaticExecutable(true);
      break;

    case OPT_no_omagic:
      ctx->setOutputMagic(ELFLinkingContext::OutputMagic::DEFAULT);
      ctx->setNoAllowDynamicLibraries();
      break;

    case OPT_u:
      ctx->addInitialUndefinedSymbol(inputArg->getValue());
      break;

    case OPT_init:
      ctx->addInitFunction(inputArg->getValue());
      break;

    case OPT_fini:
      ctx->addFiniFunction(inputArg->getValue());
      break;

    case OPT_emit_yaml:
      if (!_outputOptionSet)
        ctx->setOutputPath("-");
      ctx->setOutputYAML(true);
      break;

    case OPT_no_whole_archive:
      isWholeArchive = false;
      break;
    case OPT_whole_archive:
      isWholeArchive = true;
      break;
    case OPT_as_needed:
      asNeeded = true;
      break;
    case OPT_no_as_needed:
      asNeeded = false;
      break;
    case OPT_L:
      searchPath.push_back(inputArg->getValue());
      break;

    case OPT_start_group: {
      std::unique_ptr<InputElement> controlStart(new ELFGroup(*ctx));
      controlNodeStack.push(controlStart.get());
      (llvm::dyn_cast<ControlNode>)(controlNodeStack.top())
          ->processControlEnter();
      inputGraph->addInputElement(std::move(controlStart));
      break;
    }

    case OPT_end_group:
      (llvm::dyn_cast<ControlNode>)(controlNodeStack.top())
          ->processControlExit();
      controlNodeStack.pop();
      return false;

    case OPT_INPUT:
    case OPT_l: {
      std::unique_ptr<InputElement> inputFile =
          std::move(std::unique_ptr<InputElement>(new ELFFileNode(
              *ctx, inputArg->getValue(), searchPath, isWholeArchive, asNeeded,
              inputArg->getOption().getID() == OPT_l)));
      if (controlNodeStack.empty())
        inputGraph->addInputElement(std::move(inputFile));
      else
        (llvm::dyn_cast<ControlNode>)(controlNodeStack.top())
            ->processInputElement(std::move(inputFile));
      break;
    }

    case OPT_rpath: {
      SmallVector<StringRef, 2> rpaths;
      StringRef(inputArg->getValue()).split(rpaths, ":");
      for (auto path : rpaths)
        ctx->addRpath(path);
      break;
    }

    case OPT_rpath_link: {
      SmallVector<StringRef, 2> rpaths;
      StringRef(inputArg->getValue()).split(rpaths, ":");
      for (auto path : rpaths)
        ctx->addRpathLink(path);
      break;
    }

    case OPT_sysroot:
      ctx->setSysroot(inputArg->getValue());
      break;

    case OPT_soname:
      ctx->setSharedObjectName(inputArg->getValue());
      break;

    default:
      break;
    } // end switch on option ID
  }   // end for

  if (!inputGraph->numFiles()) {
    diagnostics << "No input files\n";
    return true;
  }

  inputGraph->addInternalFile(ctx->createInternalFiles());

  if (ctx->outputYAML())
    inputGraph->dump(diagnostics);

  // Validate the combination of options used.
  if (ctx->validate(diagnostics))
    return true;

  ctx->setInputGraph(std::move(inputGraph));

  context.swap(ctx);

  return false;
}

/// Get the default target triple based on either the program name
/// (e.g. "x86-ibm-linux-lld") or the primary target llvm was configured for.
llvm::Triple GnuLdDriver::getDefaultTarget(const char *progName) {
  SmallVector<StringRef, 4> components;
  llvm::SplitString(llvm::sys::path::stem(progName), components, "-");
  // If has enough parts to be start with a triple.
  if (components.size() >= 4) {
    llvm::Triple triple(components[0], components[1], components[2],
                        components[3]);
    // If first component looks like an arch.
    if (triple.getArch() != llvm::Triple::UnknownArch)
      return triple;
  }

  // Fallback to use whatever default triple llvm was configured for.
  return llvm::Triple(llvm::sys::getDefaultTargetTriple());
}
<|endoftext|>