<commit_before>/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
**
** GNU Lesser General Public License Usage
**
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this file.
** Please review the following information to ensure the GNU Lesser General
** Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**************************************************************************/

#include "persistentsettings.h"

#include <app/app_version.h>

#include <utils/fileutils.h>

#include <QDebug>
#include <QFile>
#include <QVariant>
#include <QStack>
#include <QXmlStreamAttributes>
#include <QXmlStreamReader>
#include <QXmlStreamWriter>
#include <QDateTime>

#include <utils/qtcassert.h>

/*!
    \class Utils::PersistentSettingsReader

    \brief Reads a QVariantMap of arbitrary, nested data structures from a XML file.

    Handles all string-serializable simple types and QVariantList and QVariantMap. Example:
    \code
<qtcreator>
    <data>
        <variable>ProjectExplorer.Project.ActiveTarget</variable>
        <value type="int">0</value>
    </data>
    <data>
        <variable>ProjectExplorer.Project.EditorSettings</variable>
        <valuemap type="QVariantMap">
            <value type="bool" key="EditorConfiguration.AutoIndent">true</value>
        </valuemap>
    </data>
    \endcode

    When parsing the structure, a parse stack of ParseValueStackEntry is used for each
    <data> element. ParseValueStackEntry is a variant/union of:
    \list
    \o simple value
    \o map
    \o list
    \endlist

    When entering a value element ( \c <value> / \c <valuelist> , \c <valuemap> ), entry is pushed
    accordingly. When leaving the element, the QVariant-value of the entry is taken off the stack
    and added to the stack entry below (added to list or inserted into map). The first element
    of the stack is the value of the <data> element.

    \sa Utils::PersistentSettingsWriter
*/

namespace Utils {

struct Context // Basic context containing element name string constants.
{
    Context();

    const QString qtCreatorElement;
    const QString dataElement;
    const QString variableElement;
    const QString typeAttribute;
    const QString valueElement;
    const QString valueListElement;
    const QString valueMapElement;
    const QString keyAttribute;
};

Context::Context() :
    qtCreatorElement(QLatin1String("qtcreator")),
    dataElement(QLatin1String("data")),
    variableElement(QLatin1String("variable")),
    typeAttribute(QLatin1String("type")),
    valueElement(QLatin1String("value")),
    valueListElement(QLatin1String("valuelist")),
    valueMapElement(QLatin1String("valuemap")),
    keyAttribute(QLatin1String("key"))
{
}

struct ParseValueStackEntry
{
    explicit ParseValueStackEntry(QVariant::Type t = QVariant::Invalid, const QString &k = QString()) : type(t), key(k) {}
    explicit ParseValueStackEntry(const QVariant &aSimpleValue, const QString &k);

    QVariant value() const;
    void addChild(const QString &key, const QVariant &v);

    QVariant::Type type;
    QString key;
    QVariant simpleValue;
    QVariantList listValue;
    QVariantMap mapValue;
};

ParseValueStackEntry::ParseValueStackEntry(const QVariant &aSimpleValue, const QString &k) :
    type(aSimpleValue.type()), key(k), simpleValue(aSimpleValue)
{
    QTC_ASSERT(simpleValue.isValid(), return);
}

QVariant ParseValueStackEntry::value() const
{
    switch (type) {
    case QVariant::Invalid:
        return QVariant();
    case QVariant::Map:
        return QVariant(mapValue);
    case QVariant::List:
        return QVariant(listValue);
    default:
        break;
    }
    return simpleValue;
}

void ParseValueStackEntry::addChild(const QString &key, const QVariant &v)
{
    switch (type) {
    case QVariant::Map:
        mapValue.insert(key, v);
        break;
    case QVariant::List:
        listValue.push_back(v);
        break;
    default:
        qWarning() << "ParseValueStackEntry::Internal error adding " << key << v << " to "
                 << QVariant::typeToName(type) << value();
        break;
    }
}

class ParseContext : public Context
{
public:
    QVariantMap parse(QFile &file);

private:
    enum Element { QtCreatorElement, DataElement, VariableElement,
                   SimpleValueElement, ListValueElement, MapValueElement, UnknownElement };

    Element element(const QStringRef &r) const;
    static inline bool isValueElement(Element e)
        { return e == SimpleValueElement || e == ListValueElement || e == MapValueElement; }
    QVariant readSimpleValue(QXmlStreamReader &r, const QXmlStreamAttributes &attributes) const;

    bool handleStartElement(QXmlStreamReader &r);
    bool handleEndElement(const QStringRef &name);

    QStack<ParseValueStackEntry> m_valueStack;
    QVariantMap m_result;
    QString m_currentVariableName;
};

QVariantMap ParseContext::parse(QFile &file)
{
    QXmlStreamReader r(&file);

    m_result.clear();
    m_currentVariableName.clear();

    while (!r.atEnd()) {
        switch (r.readNext()) {
        case QXmlStreamReader::StartElement:
            if (handleStartElement(r))
                return m_result;
            break;
        case QXmlStreamReader::EndElement:
            if (handleEndElement(r.name()))
                return m_result;
            break;
        case QXmlStreamReader::Invalid:
            qWarning("Error reading %s:%d: %s", qPrintable(file.fileName()),
                     int(r.lineNumber()), qPrintable(r.errorString()));
            return QVariantMap();
            break;
        default:
            break;
        } // switch token
    } // while (!r.atEnd())
    return m_result;
}

bool ParseContext::handleStartElement(QXmlStreamReader &r)
{
    const QStringRef name = r.name();
    const Element e = element(name);
    if (e == VariableElement) {
        m_currentVariableName = r.readElementText();
        return false;
    }
    if (!ParseContext::isValueElement(e))
        return false;

    const QXmlStreamAttributes attributes = r.attributes();
    const QString key = attributes.hasAttribute(keyAttribute) ?
                attributes.value(keyAttribute).toString() : QString();
    switch (e) {
    case SimpleValueElement:
        // This reads away the end element, so, handle end element right here.
        m_valueStack.push_back(ParseValueStackEntry(readSimpleValue(r, attributes), key));
        return handleEndElement(name);
    case ListValueElement:
        m_valueStack.push_back(ParseValueStackEntry(QVariant::List, key));
        break;
    case MapValueElement:
        m_valueStack.push_back(ParseValueStackEntry(QVariant::Map, key));
        break;
    default:
        break;
    }
    return false;
}

bool ParseContext::handleEndElement(const QStringRef &name)
{
    const Element e = element(name);
    if (ParseContext::isValueElement(e)) {
        QTC_ASSERT(!m_valueStack.isEmpty(), return true);
        const ParseValueStackEntry top = m_valueStack.pop();
        if (m_valueStack.isEmpty()) { // Last element? -> Done with that variable.
            QTC_ASSERT(!m_currentVariableName.isEmpty(), return true);
            m_result.insert(m_currentVariableName, top.value());
            m_currentVariableName.clear();
            return false;
        }
        m_valueStack.top().addChild(top.key, top.value());
    }
    return e == QtCreatorElement;
}

ParseContext::Element ParseContext::element(const QStringRef &r) const
{
    if (r == valueElement)
        return SimpleValueElement;
    if (r == valueListElement)
        return ListValueElement;
    if (r == valueMapElement)
        return MapValueElement;
    if (r == qtCreatorElement)
        return QtCreatorElement;
    if (r == dataElement)
        return DataElement;
    if (r == variableElement)
        return VariableElement;
    return UnknownElement;
}

QVariant ParseContext::readSimpleValue(QXmlStreamReader &r, const QXmlStreamAttributes &attributes) const
{
    // Simple value
    const QString type = attributes.value(typeAttribute).toString();
    const QString text = r.readElementText();
    if (type == QLatin1String("QChar")) { // Workaround: QTBUG-12345
        QTC_ASSERT(text.size() == 1, return QVariant());
        return QVariant(QChar(text.at(0)));
    }
    QVariant value;
    value.setValue(text);
    value.convert(QVariant::nameToType(type.toLatin1().data()));
    return value;
}

// =================================== PersistentSettingsReader

PersistentSettingsReader::PersistentSettingsReader()
{
}

QVariant PersistentSettingsReader::restoreValue(const QString &variable) const
{
    if (m_valueMap.contains(variable))
        return m_valueMap.value(variable);
    return QVariant();
}

QVariantMap PersistentSettingsReader::restoreValues() const
{
    return m_valueMap;
}

bool PersistentSettingsReader::load(const QString &fileName)
{
    m_valueMap.clear();

    QFile file(fileName);
    if (!file.open(QIODevice::ReadOnly|QIODevice::Text))
        return false;
    ParseContext ctx;
    m_valueMap = ctx.parse(file);
    file.close();
    return true;
}

/*!
    \class Utils::PersistentSettingsWriter

    \brief Serializes a QVariantMap of arbitrary, nested data structures to a XML file.
    \sa Utils::PersistentSettingsReader
*/

PersistentSettingsWriter::PersistentSettingsWriter()
{
}

static void writeVariantValue(QXmlStreamWriter &w, const Context &ctx,
                              const QVariant &variant, const QString &key = QString())
{
    switch (static_cast<int>(variant.type())) {
    case static_cast<int>(QVariant::StringList):
    case static_cast<int>(QVariant::List):
        w.writeStartElement(ctx.valueListElement);
        w.writeAttribute(ctx.typeAttribute, QLatin1String(QVariant::typeToName(QVariant::List)));
        if (!key.isEmpty())
            w.writeAttribute(ctx.keyAttribute, key);
        foreach (const QVariant &var, variant.toList())
            writeVariantValue(w, ctx, var);
        w.writeEndElement();
        break;
    case static_cast<int>(QVariant::Map): {
        w.writeStartElement(ctx.valueMapElement);
        w.writeAttribute(ctx.typeAttribute, QLatin1String(QVariant::typeToName(QVariant::Map)));
        if (!key.isEmpty())
            w.writeAttribute(ctx.keyAttribute, key);
        const QVariantMap varMap = variant.toMap();
        const QVariantMap::const_iterator cend = varMap.constEnd();
        for (QVariantMap::const_iterator i = varMap.constBegin(); i != cend; ++i)
            writeVariantValue(w, ctx, i.value(), i.key());
        w.writeEndElement();
    }
    break;
    case static_cast<int>(QMetaType::QObjectStar): // ignore QObjects!
    case static_cast<int>(QMetaType::VoidStar): // ignore void pointers!
        break;
    default:
        w.writeStartElement(ctx.valueElement);
        w.writeAttribute(ctx.typeAttribute, QLatin1String(variant.typeName()));
        if (!key.isEmpty())
            w.writeAttribute(ctx.keyAttribute, key);
        w.writeCharacters(variant.toString());
        w.writeEndElement();
        break;
    }
}

void PersistentSettingsWriter::saveValue(const QString &variable, const QVariant &value)
{
    m_valueMap.insert(variable, value);
}

bool PersistentSettingsWriter::save(const QString &fileName, const QString &docType,
                                    QWidget *parent) const
{
    Utils::FileSaver saver(fileName, QIODevice::Text);
    if (!saver.hasError()) {
        const Context ctx;
        QXmlStreamWriter w(saver.file());
        w.setAutoFormatting(true);
        w.setAutoFormattingIndent(1); // Historical, used to be QDom.
        w.writeStartDocument();
        w.writeDTD(QLatin1String("<!DOCTYPE ") + docType + QLatin1Char('>'));
        w.writeComment(QString::fromAscii(" Written by Qt Creator %1, %2. ").
                       arg(QLatin1String(Core::Constants::IDE_VERSION_LONG),
                           QDateTime::currentDateTime().toString(Qt::ISODate)));
        w.writeStartElement(ctx.qtCreatorElement);
        const QVariantMap::const_iterator cend = m_valueMap.constEnd();
        for (QVariantMap::const_iterator it =  m_valueMap.constBegin(); it != cend; ++it) {
            w.writeStartElement(ctx.dataElement);
            w.writeTextElement(ctx.variableElement, it.key());
            writeVariantValue(w, ctx, it.value());
            w.writeEndElement();
        }
        w.writeEndDocument();

        saver.setResult(&w);
    }
    return saver.finalize(parent);
}
} // namespace Utils
<commit_msg>PersistentSettingsWriter: Ensure that the directory exists<commit_after>/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
**
** GNU Lesser General Public License Usage
**
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this file.
** Please review the following information to ensure the GNU Lesser General
** Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**************************************************************************/

#include "persistentsettings.h"

#include <app/app_version.h>

#include <utils/fileutils.h>

#include <QDebug>
#include <QFile>
#include <QDir>
#include <QVariant>
#include <QStack>
#include <QXmlStreamAttributes>
#include <QXmlStreamReader>
#include <QXmlStreamWriter>
#include <QDateTime>

#include <utils/qtcassert.h>

/*!
    \class Utils::PersistentSettingsReader

    \brief Reads a QVariantMap of arbitrary, nested data structures from a XML file.

    Handles all string-serializable simple types and QVariantList and QVariantMap. Example:
    \code
<qtcreator>
    <data>
        <variable>ProjectExplorer.Project.ActiveTarget</variable>
        <value type="int">0</value>
    </data>
    <data>
        <variable>ProjectExplorer.Project.EditorSettings</variable>
        <valuemap type="QVariantMap">
            <value type="bool" key="EditorConfiguration.AutoIndent">true</value>
        </valuemap>
    </data>
    \endcode

    When parsing the structure, a parse stack of ParseValueStackEntry is used for each
    <data> element. ParseValueStackEntry is a variant/union of:
    \list
    \o simple value
    \o map
    \o list
    \endlist

    When entering a value element ( \c <value> / \c <valuelist> , \c <valuemap> ), entry is pushed
    accordingly. When leaving the element, the QVariant-value of the entry is taken off the stack
    and added to the stack entry below (added to list or inserted into map). The first element
    of the stack is the value of the <data> element.

    \sa Utils::PersistentSettingsWriter
*/

namespace Utils {

struct Context // Basic context containing element name string constants.
{
    Context();

    const QString qtCreatorElement;
    const QString dataElement;
    const QString variableElement;
    const QString typeAttribute;
    const QString valueElement;
    const QString valueListElement;
    const QString valueMapElement;
    const QString keyAttribute;
};

Context::Context() :
    qtCreatorElement(QLatin1String("qtcreator")),
    dataElement(QLatin1String("data")),
    variableElement(QLatin1String("variable")),
    typeAttribute(QLatin1String("type")),
    valueElement(QLatin1String("value")),
    valueListElement(QLatin1String("valuelist")),
    valueMapElement(QLatin1String("valuemap")),
    keyAttribute(QLatin1String("key"))
{
}

struct ParseValueStackEntry
{
    explicit ParseValueStackEntry(QVariant::Type t = QVariant::Invalid, const QString &k = QString()) : type(t), key(k) {}
    explicit ParseValueStackEntry(const QVariant &aSimpleValue, const QString &k);

    QVariant value() const;
    void addChild(const QString &key, const QVariant &v);

    QVariant::Type type;
    QString key;
    QVariant simpleValue;
    QVariantList listValue;
    QVariantMap mapValue;
};

ParseValueStackEntry::ParseValueStackEntry(const QVariant &aSimpleValue, const QString &k) :
    type(aSimpleValue.type()), key(k), simpleValue(aSimpleValue)
{
    QTC_ASSERT(simpleValue.isValid(), return);
}

QVariant ParseValueStackEntry::value() const
{
    switch (type) {
    case QVariant::Invalid:
        return QVariant();
    case QVariant::Map:
        return QVariant(mapValue);
    case QVariant::List:
        return QVariant(listValue);
    default:
        break;
    }
    return simpleValue;
}

void ParseValueStackEntry::addChild(const QString &key, const QVariant &v)
{
    switch (type) {
    case QVariant::Map:
        mapValue.insert(key, v);
        break;
    case QVariant::List:
        listValue.push_back(v);
        break;
    default:
        qWarning() << "ParseValueStackEntry::Internal error adding " << key << v << " to "
                 << QVariant::typeToName(type) << value();
        break;
    }
}

class ParseContext : public Context
{
public:
    QVariantMap parse(QFile &file);

private:
    enum Element { QtCreatorElement, DataElement, VariableElement,
                   SimpleValueElement, ListValueElement, MapValueElement, UnknownElement };

    Element element(const QStringRef &r) const;
    static inline bool isValueElement(Element e)
        { return e == SimpleValueElement || e == ListValueElement || e == MapValueElement; }
    QVariant readSimpleValue(QXmlStreamReader &r, const QXmlStreamAttributes &attributes) const;

    bool handleStartElement(QXmlStreamReader &r);
    bool handleEndElement(const QStringRef &name);

    QStack<ParseValueStackEntry> m_valueStack;
    QVariantMap m_result;
    QString m_currentVariableName;
};

QVariantMap ParseContext::parse(QFile &file)
{
    QXmlStreamReader r(&file);

    m_result.clear();
    m_currentVariableName.clear();

    while (!r.atEnd()) {
        switch (r.readNext()) {
        case QXmlStreamReader::StartElement:
            if (handleStartElement(r))
                return m_result;
            break;
        case QXmlStreamReader::EndElement:
            if (handleEndElement(r.name()))
                return m_result;
            break;
        case QXmlStreamReader::Invalid:
            qWarning("Error reading %s:%d: %s", qPrintable(file.fileName()),
                     int(r.lineNumber()), qPrintable(r.errorString()));
            return QVariantMap();
            break;
        default:
            break;
        } // switch token
    } // while (!r.atEnd())
    return m_result;
}

bool ParseContext::handleStartElement(QXmlStreamReader &r)
{
    const QStringRef name = r.name();
    const Element e = element(name);
    if (e == VariableElement) {
        m_currentVariableName = r.readElementText();
        return false;
    }
    if (!ParseContext::isValueElement(e))
        return false;

    const QXmlStreamAttributes attributes = r.attributes();
    const QString key = attributes.hasAttribute(keyAttribute) ?
                attributes.value(keyAttribute).toString() : QString();
    switch (e) {
    case SimpleValueElement:
        // This reads away the end element, so, handle end element right here.
        m_valueStack.push_back(ParseValueStackEntry(readSimpleValue(r, attributes), key));
        return handleEndElement(name);
    case ListValueElement:
        m_valueStack.push_back(ParseValueStackEntry(QVariant::List, key));
        break;
    case MapValueElement:
        m_valueStack.push_back(ParseValueStackEntry(QVariant::Map, key));
        break;
    default:
        break;
    }
    return false;
}

bool ParseContext::handleEndElement(const QStringRef &name)
{
    const Element e = element(name);
    if (ParseContext::isValueElement(e)) {
        QTC_ASSERT(!m_valueStack.isEmpty(), return true);
        const ParseValueStackEntry top = m_valueStack.pop();
        if (m_valueStack.isEmpty()) { // Last element? -> Done with that variable.
            QTC_ASSERT(!m_currentVariableName.isEmpty(), return true);
            m_result.insert(m_currentVariableName, top.value());
            m_currentVariableName.clear();
            return false;
        }
        m_valueStack.top().addChild(top.key, top.value());
    }
    return e == QtCreatorElement;
}

ParseContext::Element ParseContext::element(const QStringRef &r) const
{
    if (r == valueElement)
        return SimpleValueElement;
    if (r == valueListElement)
        return ListValueElement;
    if (r == valueMapElement)
        return MapValueElement;
    if (r == qtCreatorElement)
        return QtCreatorElement;
    if (r == dataElement)
        return DataElement;
    if (r == variableElement)
        return VariableElement;
    return UnknownElement;
}

QVariant ParseContext::readSimpleValue(QXmlStreamReader &r, const QXmlStreamAttributes &attributes) const
{
    // Simple value
    const QString type = attributes.value(typeAttribute).toString();
    const QString text = r.readElementText();
    if (type == QLatin1String("QChar")) { // Workaround: QTBUG-12345
        QTC_ASSERT(text.size() == 1, return QVariant());
        return QVariant(QChar(text.at(0)));
    }
    QVariant value;
    value.setValue(text);
    value.convert(QVariant::nameToType(type.toLatin1().data()));
    return value;
}

// =================================== PersistentSettingsReader

PersistentSettingsReader::PersistentSettingsReader()
{
}

QVariant PersistentSettingsReader::restoreValue(const QString &variable) const
{
    if (m_valueMap.contains(variable))
        return m_valueMap.value(variable);
    return QVariant();
}

QVariantMap PersistentSettingsReader::restoreValues() const
{
    return m_valueMap;
}

bool PersistentSettingsReader::load(const QString &fileName)
{
    m_valueMap.clear();

    QFile file(fileName);
    if (!file.open(QIODevice::ReadOnly|QIODevice::Text))
        return false;
    ParseContext ctx;
    m_valueMap = ctx.parse(file);
    file.close();
    return true;
}

/*!
    \class Utils::PersistentSettingsWriter

    \brief Serializes a QVariantMap of arbitrary, nested data structures to a XML file.
    \sa Utils::PersistentSettingsReader
*/

PersistentSettingsWriter::PersistentSettingsWriter()
{
}

static void writeVariantValue(QXmlStreamWriter &w, const Context &ctx,
                              const QVariant &variant, const QString &key = QString())
{
    switch (static_cast<int>(variant.type())) {
    case static_cast<int>(QVariant::StringList):
    case static_cast<int>(QVariant::List):
        w.writeStartElement(ctx.valueListElement);
        w.writeAttribute(ctx.typeAttribute, QLatin1String(QVariant::typeToName(QVariant::List)));
        if (!key.isEmpty())
            w.writeAttribute(ctx.keyAttribute, key);
        foreach (const QVariant &var, variant.toList())
            writeVariantValue(w, ctx, var);
        w.writeEndElement();
        break;
    case static_cast<int>(QVariant::Map): {
        w.writeStartElement(ctx.valueMapElement);
        w.writeAttribute(ctx.typeAttribute, QLatin1String(QVariant::typeToName(QVariant::Map)));
        if (!key.isEmpty())
            w.writeAttribute(ctx.keyAttribute, key);
        const QVariantMap varMap = variant.toMap();
        const QVariantMap::const_iterator cend = varMap.constEnd();
        for (QVariantMap::const_iterator i = varMap.constBegin(); i != cend; ++i)
            writeVariantValue(w, ctx, i.value(), i.key());
        w.writeEndElement();
    }
    break;
    case static_cast<int>(QMetaType::QObjectStar): // ignore QObjects!
    case static_cast<int>(QMetaType::VoidStar): // ignore void pointers!
        break;
    default:
        w.writeStartElement(ctx.valueElement);
        w.writeAttribute(ctx.typeAttribute, QLatin1String(variant.typeName()));
        if (!key.isEmpty())
            w.writeAttribute(ctx.keyAttribute, key);
        w.writeCharacters(variant.toString());
        w.writeEndElement();
        break;
    }
}

void PersistentSettingsWriter::saveValue(const QString &variable, const QVariant &value)
{
    m_valueMap.insert(variable, value);
}

bool PersistentSettingsWriter::save(const QString &fileName, const QString &docType,
                                    QWidget *parent) const
{
    QDir tmp;
    tmp.mkpath(QFileInfo(fileName).path());
    Utils::FileSaver saver(fileName, QIODevice::Text);
    if (!saver.hasError()) {
        const Context ctx;
        QXmlStreamWriter w(saver.file());
        w.setAutoFormatting(true);
        w.setAutoFormattingIndent(1); // Historical, used to be QDom.
        w.writeStartDocument();
        w.writeDTD(QLatin1String("<!DOCTYPE ") + docType + QLatin1Char('>'));
        w.writeComment(QString::fromAscii(" Written by Qt Creator %1, %2. ").
                       arg(QLatin1String(Core::Constants::IDE_VERSION_LONG),
                           QDateTime::currentDateTime().toString(Qt::ISODate)));
        w.writeStartElement(ctx.qtCreatorElement);
        const QVariantMap::const_iterator cend = m_valueMap.constEnd();
        for (QVariantMap::const_iterator it =  m_valueMap.constBegin(); it != cend; ++it) {
            w.writeStartElement(ctx.dataElement);
            w.writeTextElement(ctx.variableElement, it.key());
            writeVariantValue(w, ctx, it.value());
            w.writeEndElement();
        }
        w.writeEndDocument();

        saver.setResult(&w);
    }
    return saver.finalize(parent);
}
} // namespace Utils
<|endoftext|>


<commit_before>//---------------------------------------------------------
// Copyright 2015 Ontario Institute for Cancer Research
// Written by Jared Simpson (jared.simpson@oicr.on.ca)
//---------------------------------------------------------
//
// nanopolish.cpp -- main driver program
//
#include <string>
#include <map>
#include <functional>
#include "logsum.h"
#include "nanopolish_extract.h"
#include "nanopolish_call_variants.h"
#include "nanopolish_consensus.h"
#include "nanopolish_eventalign.h"
#include "nanopolish_getmodel.h"
#include "nanopolish_methyltrain.h"
#include "nanopolish_call_methylation.h"
#include "nanopolish_scorereads.h"
#include "nanopolish_phase_reads.h"
#include "nanopolish_train_poremodel_from_basecalls.h"

int print_usage(int argc, char **argv);
int print_version(int argc, char **argv);

static std::map< std::string, std::function<int(int, char**)> > programs = {
    {"help",        print_usage},
    {"--help",      print_usage},
    {"--version",   print_version},
    {"extract",     extract_main},
    {"consensus",   consensus_main},
    {"eventalign",  eventalign_main},
    {"getmodel",    getmodel_main},
    {"variants",    call_variants_main},
    {"methyltrain", methyltrain_main},
    {"scorereads",  scorereads_main} ,
    {"phase-reads",  phase_reads_main} ,
    {"call-methylation",  call_methylation_main},
    {"train-poremodel-from-basecalls",  train_poremodel_from_basecalls_main}
};

int print_usage(int, char **)
{
    std::cout << "usage: nanopolish [command] [options]" << std::endl;
    std::cout << "  valid commands: " << std::endl;
    for (const auto &item : programs){
        std::cout << "    " << item.first << std::endl;
    }
    std::cout << "  for help on given command, type nanopolish command --help" << std::endl;
    return 0;
}

int print_version(int, char **)
{
    static const char *VERSION_MESSAGE =
    "nanopolish version " PACKAGE_VERSION "\n"
    "Written by Jared Simpson.\n"
    "\n"
    "Copyright 2015-2017 Ontario Institute for Cancer Research\n";
    std::cout << VERSION_MESSAGE << std::endl;
    return 0;
}

int main(int argc, char** argv)
{
    int ret = 0;
    if(argc <= 1) {
        printf("error: no command provided\n");
        print_usage(argc - 1 , argv + 1);
        return 0;
    } else {
        std::string command(argv[1]);
        auto iter = programs.find(command);
        if (iter != programs.end())
            ret = iter->second( argc - 1, argv + 1);
        else
            ret = print_usage( argc - 1, argv + 1);
    }

    // Emit a warning when some reads had to be skipped
    extern int g_total_reads;
    extern int g_unparseable_reads;
    if(g_unparseable_reads > 0) {
        fprintf(stderr, "warning: nanopolish could not parse %d read out of %d\n", g_unparseable_reads, g_total_reads);
    }
    return ret;
}
<commit_msg>update warning<commit_after>//---------------------------------------------------------
// Copyright 2015 Ontario Institute for Cancer Research
// Written by Jared Simpson (jared.simpson@oicr.on.ca)
//---------------------------------------------------------
//
// nanopolish.cpp -- main driver program
//
#include <string>
#include <map>
#include <functional>
#include "logsum.h"
#include "nanopolish_extract.h"
#include "nanopolish_call_variants.h"
#include "nanopolish_consensus.h"
#include "nanopolish_eventalign.h"
#include "nanopolish_getmodel.h"
#include "nanopolish_methyltrain.h"
#include "nanopolish_call_methylation.h"
#include "nanopolish_scorereads.h"
#include "nanopolish_phase_reads.h"
#include "nanopolish_train_poremodel_from_basecalls.h"

int print_usage(int argc, char **argv);
int print_version(int argc, char **argv);

static std::map< std::string, std::function<int(int, char**)> > programs = {
    {"help",        print_usage},
    {"--help",      print_usage},
    {"--version",   print_version},
    {"extract",     extract_main},
    {"consensus",   consensus_main},
    {"eventalign",  eventalign_main},
    {"getmodel",    getmodel_main},
    {"variants",    call_variants_main},
    {"methyltrain", methyltrain_main},
    {"scorereads",  scorereads_main} ,
    {"phase-reads",  phase_reads_main} ,
    {"call-methylation",  call_methylation_main},
    {"train-poremodel-from-basecalls",  train_poremodel_from_basecalls_main}
};

int print_usage(int, char **)
{
    std::cout << "usage: nanopolish [command] [options]" << std::endl;
    std::cout << "  valid commands: " << std::endl;
    for (const auto &item : programs){
        std::cout << "    " << item.first << std::endl;
    }
    std::cout << "  for help on given command, type nanopolish command --help" << std::endl;
    return 0;
}

int print_version(int, char **)
{
    static const char *VERSION_MESSAGE =
    "nanopolish version " PACKAGE_VERSION "\n"
    "Written by Jared Simpson.\n"
    "\n"
    "Copyright 2015-2017 Ontario Institute for Cancer Research\n";
    std::cout << VERSION_MESSAGE << std::endl;
    return 0;
}

int main(int argc, char** argv)
{
    int ret = 0;
    if(argc <= 1) {
        printf("error: no command provided\n");
        print_usage(argc - 1 , argv + 1);
        return 0;
    } else {
        std::string command(argv[1]);
        auto iter = programs.find(command);
        if (iter != programs.end())
            ret = iter->second( argc - 1, argv + 1);
        else
            ret = print_usage( argc - 1, argv + 1);
    }

    // Emit a warning when some reads had to be skipped
    extern int g_total_reads;
    extern int g_unparseable_reads;
    if(g_unparseable_reads > 0) {
        fprintf(stderr, "warning: nanopolish could not parse %d reads out of %d\n", g_unparseable_reads, g_total_reads);
    }
    return ret;
}
<|endoftext|>


<commit_before>#pragma once

#define randf() (rand() / (float)RAND_MAX)

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wshadow"
#define GLM_ENABLE_EXPERIMENTAL
#define GLM_FORCE_RADIANS
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtx/string_cast.hpp>
#include <glm/gtc/quaternion.hpp>
#pragma GCC diagnostic pop

#include <core/json.hpp>

namespace glm {

    inline void to_json( nlohmann::json &j, const glm::vec3 &p ) {
        j.array( {p.x, p.y, p.z} );
    }

    inline void from_json( const nlohmann::json &j, glm::vec3 &p ) {
        int ix = 0;
        for ( auto it = j.begin( ); it != j.end( ); ++it, ix++ ) {
            p[ix] = *it;
        }
    }

} // namespace glm
<commit_msg>Fix warnings<commit_after>#pragma once

#define randf() (rand() / (float)RAND_MAX)

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wshadow"
#define GLM_ENABLE_EXPERIMENTAL
#define GLM_FORCE_RADIANS
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtx/string_cast.hpp>
#include <glm/gtc/quaternion.hpp>
#pragma GCC diagnostic pop

#include <core/json.hpp>

namespace glm {

    static inline void to_json( nlohmann::json &j, const glm::vec3 &p ) {
        j.array( {p.x, p.y, p.z} );
    }

    static inline void from_json( const nlohmann::json &j, glm::vec3 &p ) {
        int ix = 0;
        for ( auto it = j.begin( ); it != j.end( ); ++it, ix++ ) {
            p[ix] = *it;
        }
    }

} // namespace glm
<|endoftext|>


<commit_before>//
// Created by David on 25-Dec-15.
//

#include "nova_renderer.h"
#include "../utils/utils.h"
#include "../data_loading/loaders/loaders.h"

#include <easylogging++.h>

INITIALIZE_EASYLOGGINGPP

namespace nova {
    std::unique_ptr<nova_renderer> nova_renderer::instance;

    nova_renderer::nova_renderer(){
		enable_debug();
		render_settings->register_change_listener(&ubo_manager);
		render_settings->register_change_listener(&game_window);
        render_settings->register_change_listener(this);

        render_settings->update_config_loaded();
		render_settings->update_config_changed();

        init_opengl_state();
    }

    void nova_renderer::init_opengl_state() const {
        glClearColor(0.0, 0.0, 0.0, 1.0);

    }

    nova_renderer::~nova_renderer() {
        game_window.destroy();
    }

    void nova_renderer::render_frame() {
        // Clear to the clear color
        glClear(GL_COLOR_BUFFER_BIT);

        render_shadow_pass();

        render_gbuffers();

        render_composite_passes();

        render_final_pass();

        // We want to draw the GUI on top of the other things, so we'll render it last
        // Additionally, I could use the stencil buffer to not draw MC underneath the GUI. Could be a fun
        // optimization - I'd have to watch out for when the user hides the GUI, though. I can just re-render the
        // stencil buffer when the GUI screen changes
        render_gui();

        game_window.end_frame();
    }

    void nova_renderer::render_shadow_pass() {

    }

    void nova_renderer::render_gbuffers() {

    }

    void nova_renderer::render_composite_passes() {

    }

    void nova_renderer::render_final_pass() {

    }

    void nova_renderer::render_gui() {
        // Bind all the GUI data
        gl_shader_program &gui_shader = (*loaded_shaderpack)["gui"];
        gui_shader.bind();

        // Render GUI objects
        std::vector<render_object *> gui_geometry = meshes.get_meshes_for_shader("gui");
        for(const auto *geom : gui_geometry) {
            geom->geometry->draw();
        }
    }

    bool nova_renderer::should_end() {
        // If the window wants to close, the user probably clicked on the "X" button
        return game_window.should_close();
    }

	std::unique_ptr<settings> nova_renderer::render_settings;

    void nova_renderer::init() {
		render_settings = std::make_unique<settings>("config/config.json");

		instance = std::make_unique<nova_renderer>();
    }

    std::string translate_debug_source(GLenum source) {
        switch(source) {
            case GL_DEBUG_SOURCE_API:
                return "API";
            case GL_DEBUG_SOURCE_WINDOW_SYSTEM:
                return "window system";
            case GL_DEBUG_SOURCE_SHADER_COMPILER:
                return "shader compiler";
            case GL_DEBUG_SOURCE_THIRD_PARTY:
                return "third party";
            case GL_DEBUG_SOURCE_APPLICATION:
                return "application";
            case GL_DEBUG_SOURCE_OTHER:
                return "other";
            default:
                return "something else somehow";
        }
    }

    std::string translate_debug_type(GLenum type) {
        switch(type) {
            case GL_DEBUG_TYPE_ERROR:
                return "error";
            case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR:
                return "some behavior marked deprecated has been used";
            case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR:
                return "something has invoked undefined behavior";
            case GL_DEBUG_TYPE_PORTABILITY:
                return "some functionality the user relies upon is not portable";
            case GL_DEBUG_TYPE_PERFORMANCE:
                return "code has triggered possible performance issues";
            case GL_DEBUG_TYPE_MARKER:
                return "command stream annotation";
            case GL_DEBUG_TYPE_PUSH_GROUP:
                return "group pushing";
            case GL_DEBUG_TYPE_POP_GROUP:
                return "group popping";
            case GL_DEBUG_TYPE_OTHER:
                return "other";
            default:
                return "something else somwhow";
        }
    }

    void APIENTRY
    debug_logger(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *message,
                 const void *user_param) {
        std::string source_name = translate_debug_source(source);
        std::string type_name = translate_debug_type(type);

        switch(severity) {
            case GL_DEBUG_SEVERITY_HIGH:
                LOG(ERROR) << id << " - Message from " << source_name << " of type " << type_name << ": "
                           << message;
                break;

            case GL_DEBUG_SEVERITY_MEDIUM:
                LOG(INFO) << id << " - Message from " << source_name << " of type " << type_name << ": " << message;
                break;

            case GL_DEBUG_SEVERITY_LOW:
                LOG(DEBUG) << id << " - Message from " << source_name << " of type " << type_name << ": "
                           << message;
                break;

            case GL_DEBUG_SEVERITY_NOTIFICATION:
                LOG(TRACE) << id << " - Message from " << source_name << " of type " << type_name << ": "
                           << message;
                break;

            default:
                LOG(INFO) << id << " - Message from " << source_name << " of type " << type_name << ": " << message;
        }
    }

    void nova_renderer::enable_debug() {
        glEnable(GL_DEBUG_OUTPUT);
        glDebugMessageCallback(debug_logger, NULL);
    }

    void nova_renderer::on_config_change(nlohmann::json &new_config) {

		auto& shaderpack_name = new_config["loadedShaderpack"];
        load_new_shaderpack(shaderpack_name);
    }

    void nova_renderer::on_config_loaded(nlohmann::json &config) {
        // TODO: Probably want to do some setup here, don't need to do that now
    }

    settings &nova_renderer::get_render_settings() {
        return *render_settings;
    }

    texture_manager &nova_renderer::get_texture_manager() {
        return textures;
    }

	glfw_gl_window &nova_renderer::get_game_window() {
		return game_window;
	}

	input_handler &nova_renderer::get_input_handler() {
		return input_handler;
	}

    mesh_store &nova_renderer::get_mesh_store() {
        return meshes;
    }

    void nova_renderer::load_new_shaderpack(const std::string &new_shaderpack_name) {

        LOG(INFO) << "Loading shaderpack " << new_shaderpack_name;
        loaded_shaderpack = std::experimental::make_optional<shaderpack>(load_shaderpack(new_shaderpack_name));
        meshes.set_shaderpack(*loaded_shaderpack);
        LOG(INFO) << "Loading complete";

        link_up_uniform_buffers(loaded_shaderpack->get_loaded_shaders(), ubo_manager);
        LOG(DEBUG) << "Linked up UBOs";
    }

    void nova_renderer::deinit() {
        instance.release();
    }

    void link_up_uniform_buffers(std::unordered_map<std::string, gl_shader_program> &shaders, uniform_buffer_store &ubos) {
        nova::foreach(shaders, [&](auto shader) { ubos.register_all_buffers_with_shader(shader.second); });
    }
}

<commit_msg>fix geometry->draw();<commit_after>//
// Created by David on 25-Dec-15.
//

#include "nova_renderer.h"
#include "../utils/utils.h"
#include "../data_loading/loaders/loaders.h"

#include <easylogging++.h>

INITIALIZE_EASYLOGGINGPP

namespace nova {
    std::unique_ptr<nova_renderer> nova_renderer::instance;

    nova_renderer::nova_renderer(){
		enable_debug();
		render_settings->register_change_listener(&ubo_manager);
		render_settings->register_change_listener(&game_window);
        render_settings->register_change_listener(this);

        render_settings->update_config_loaded();
		render_settings->update_config_changed();

        init_opengl_state();
    }

    void nova_renderer::init_opengl_state() const {
        glClearColor(0.0, 0.0, 0.0, 1.0);

    }

    nova_renderer::~nova_renderer() {
        game_window.destroy();
    }

    void nova_renderer::render_frame() {
        // Clear to the clear color
        glClear(GL_COLOR_BUFFER_BIT);

        render_shadow_pass();

        render_gbuffers();

        render_composite_passes();

        render_final_pass();

        // We want to draw the GUI on top of the other things, so we'll render it last
        // Additionally, I could use the stencil buffer to not draw MC underneath the GUI. Could be a fun
        // optimization - I'd have to watch out for when the user hides the GUI, though. I can just re-render the
        // stencil buffer when the GUI screen changes
        render_gui();

        game_window.end_frame();
    }

    void nova_renderer::render_shadow_pass() {

    }

    void nova_renderer::render_gbuffers() {

    }

    void nova_renderer::render_composite_passes() {

    }

    void nova_renderer::render_final_pass() {

    }

    void nova_renderer::render_gui() {
        // Bind all the GUI data
        gl_shader_program &gui_shader = (*loaded_shaderpack)["gui"];
        gui_shader.bind();

        // Render GUI objects
        std::vector<render_object *> gui_geometry = meshes.get_meshes_for_shader("gui");
        for(const auto *geom : gui_geometry) {
            geom->geometry->set_active();
            geom->geometry->draw();
        }
    }

    bool nova_renderer::should_end() {
        // If the window wants to close, the user probably clicked on the "X" button
        return game_window.should_close();
    }

	std::unique_ptr<settings> nova_renderer::render_settings;

    void nova_renderer::init() {
		render_settings = std::make_unique<settings>("config/config.json");

		instance = std::make_unique<nova_renderer>();
    }

    std::string translate_debug_source(GLenum source) {
        switch(source) {
            case GL_DEBUG_SOURCE_API:
                return "API";
            case GL_DEBUG_SOURCE_WINDOW_SYSTEM:
                return "window system";
            case GL_DEBUG_SOURCE_SHADER_COMPILER:
                return "shader compiler";
            case GL_DEBUG_SOURCE_THIRD_PARTY:
                return "third party";
            case GL_DEBUG_SOURCE_APPLICATION:
                return "application";
            case GL_DEBUG_SOURCE_OTHER:
                return "other";
            default:
                return "something else somehow";
        }
    }

    std::string translate_debug_type(GLenum type) {
        switch(type) {
            case GL_DEBUG_TYPE_ERROR:
                return "error";
            case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR:
                return "some behavior marked deprecated has been used";
            case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR:
                return "something has invoked undefined behavior";
            case GL_DEBUG_TYPE_PORTABILITY:
                return "some functionality the user relies upon is not portable";
            case GL_DEBUG_TYPE_PERFORMANCE:
                return "code has triggered possible performance issues";
            case GL_DEBUG_TYPE_MARKER:
                return "command stream annotation";
            case GL_DEBUG_TYPE_PUSH_GROUP:
                return "group pushing";
            case GL_DEBUG_TYPE_POP_GROUP:
                return "group popping";
            case GL_DEBUG_TYPE_OTHER:
                return "other";
            default:
                return "something else somwhow";
        }
    }

    void APIENTRY
    debug_logger(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *message,
                 const void *user_param) {
        std::string source_name = translate_debug_source(source);
        std::string type_name = translate_debug_type(type);

        switch(severity) {
            case GL_DEBUG_SEVERITY_HIGH:
                LOG(ERROR) << id << " - Message from " << source_name << " of type " << type_name << ": "
                           << message;
                break;

            case GL_DEBUG_SEVERITY_MEDIUM:
                LOG(INFO) << id << " - Message from " << source_name << " of type " << type_name << ": " << message;
                break;

            case GL_DEBUG_SEVERITY_LOW:
                LOG(DEBUG) << id << " - Message from " << source_name << " of type " << type_name << ": "
                           << message;
                break;

            case GL_DEBUG_SEVERITY_NOTIFICATION:
                LOG(TRACE) << id << " - Message from " << source_name << " of type " << type_name << ": "
                           << message;
                break;

            default:
                LOG(INFO) << id << " - Message from " << source_name << " of type " << type_name << ": " << message;
        }
    }

    void nova_renderer::enable_debug() {
        glEnable(GL_DEBUG_OUTPUT);
        glDebugMessageCallback(debug_logger, NULL);
    }

    void nova_renderer::on_config_change(nlohmann::json &new_config) {

		auto& shaderpack_name = new_config["loadedShaderpack"];
        load_new_shaderpack(shaderpack_name);
    }

    void nova_renderer::on_config_loaded(nlohmann::json &config) {
        // TODO: Probably want to do some setup here, don't need to do that now
    }

    settings &nova_renderer::get_render_settings() {
        return *render_settings;
    }

    texture_manager &nova_renderer::get_texture_manager() {
        return textures;
    }

	glfw_gl_window &nova_renderer::get_game_window() {
		return game_window;
	}

	input_handler &nova_renderer::get_input_handler() {
		return input_handler;
	}

    mesh_store &nova_renderer::get_mesh_store() {
        return meshes;
    }

    void nova_renderer::load_new_shaderpack(const std::string &new_shaderpack_name) {

        LOG(INFO) << "Loading shaderpack " << new_shaderpack_name;
        loaded_shaderpack = std::experimental::make_optional<shaderpack>(load_shaderpack(new_shaderpack_name));
        meshes.set_shaderpack(*loaded_shaderpack);
        LOG(INFO) << "Loading complete";

        link_up_uniform_buffers(loaded_shaderpack->get_loaded_shaders(), ubo_manager);
        LOG(DEBUG) << "Linked up UBOs";
    }

    void nova_renderer::deinit() {
        instance.release();
    }

    void link_up_uniform_buffers(std::unordered_map<std::string, gl_shader_program> &shaders, uniform_buffer_store &ubos) {
        nova::foreach(shaders, [&](auto shader) { ubos.register_all_buffers_with_shader(shader.second); });
    }
}

<|endoftext|>


<commit_before>#include <iostream>
#include <fstream>
//#include <boost/archive/text_oarchive.hpp>
//#include <boost/archive/text_iarchive.hpp>

#include "generator.h"
#include "type_generator.h"
//#include "serialize_tuple.h"

#ifndef RANDOM_SEED
  #define RANDOM_SEED 0xAC0
#endif

// Clang requires forward declarations for overloaded < operators.
// g++5 does not. Who's correct?

template <class... Args>
std::ostream & operator << (std::ostream & o, const std::tuple<Args...> & tuple);

template <class T>
std::ostream & operator << (std::ostream & o, const std::vector<T> & vector);

template <class T>
std::ostream & operator << (std::ostream & o, const boost::optional<T> & opt);

template <class T, class U>
std::ostream & operator << (std::ostream & o, const std::pair<T, U> & pair);

template <class T, size_t N>
std::ostream & operator << (std::ostream & o, const std::array<T, N> & arr)
{
  for (auto & elem : arr)
    o << elem;

  return o << "\n";
}

template <class T>
std::ostream & operator << (std::ostream & o, const std::vector<T> & vector)
{
  for (const auto & elem : vector)
    o << elem << " ";

  return o;
}

template <class T>
std::ostream & operator << (std::ostream & o, const boost::optional<T> & opt)
{
  if (opt)
    o << opt.get();

  return o;
}

template <class T, class U>
std::ostream & operator << (std::ostream & o, const std::pair<T, U> & pair)
{
  o << "pair.first = " << pair.first << "\n"
    << "pair.second = " << pair.second;

  return o;
}

template <class Tuple, size_t Size>
struct TuplePrinter
{
  static void print(std::ostream & o, const Tuple & tuple)
  {
    TuplePrinter<Tuple, Size-1>::print(o, tuple);
    o << std::get<Size-1>(tuple) << " ";
  }
};

template <class Tuple>
struct TuplePrinter<Tuple, 1>
{
  static void print(std::ostream & o, const Tuple & tuple)
  {
    o << std::get<0>(tuple) << " ";
  }
};

template <class Tuple>
struct TuplePrinter<Tuple, 0>
{
  static void print(std::ostream &, const Tuple &)
  {
    // no-op
  }
};

template <class... Args>
std::ostream & operator << (std::ostream & o, const std::tuple<Args...> & tuple)
{
  TuplePrinter<std::tuple<Args...>, sizeof...(Args)>::print(o, tuple);
  return o;
}

struct ShapeType
{
  int x, y, shapesize;
  std::string color;
};

std::ostream & operator << (std::ostream & o, const ShapeType & shape)
{
  o << "shape.x = "         << shape.x << "\n"
    << "shape.y = "         << shape.y << "\n"
    << "shape.shapesize = " << shape.shapesize << "\n"
    << "shape.color = "     << shape.color << "\n";

  return o;
}

auto test_shape_gen()
{
  auto xgen = gen::make_range_gen(0, 200);
  auto ygen = gen::make_range_gen(0, 200);
  auto sizegen = gen::make_constant_gen(30);
  auto colorgen = gen::make_oneof_gen({ "RED", "GREEN", "BLUE" });

  auto shapegen =
    gen::make_zip_gen(
      [](int x, int y, int size, const char * color) {
          return ShapeType { x, y, size, color };
      }, xgen, ygen, sizegen, colorgen);

  std::cout << shapegen.generate() << "\n";

  return shapegen;
}

void test_generators(void)
{
  gen::initialize();

  auto strgen =
    gen::make_string_gen(gen::make_printable_gen());

  std::cout << "size of strgen = " << sizeof(strgen) << "\n"
            << "string = " << strgen.generate() << "\n";

  auto vecgen =
    //gen::make_seq_gen<std::vector>(gen::GenFactory<int>::make(), 5, true);
    gen::GenFactory<std::vector<int>>::make(gen::GenFactory<int>::make(), 5, true);

  std::cout << "vector = " << vecgen.generate() << "\n";

  auto optgen = gen::make_optional_gen(strgen);
  std::cout << "optional string = " << optgen.generate() << "\n";

  auto pairgen = gen::make_pair_gen(strgen, vecgen);
  std::cout << pairgen.generate() << "\n";

  auto tuplegen = gen::make_composed_gen(strgen, vecgen);
  std::cout << tuplegen.generate() << "\n";

  auto shapegen = test_shape_gen();

  auto arraygen = gen::make_array_gen(shapegen, gen::dim_list<2, 2>());
  std::cout << arraygen.generate() << "\n";

  auto inordergen =
    gen::make_inorder_gen({ 10, 20 });

  assert(inordergen.generate() == 10);
  assert(inordergen.generate() == 20);

  auto concatgen =
    gen::make_inorder_gen({ 10, 20 })
       .concat(gen::make_inorder_gen({ 30 }));

  assert(concatgen.generate() == 10);
  assert(concatgen.generate() == 20);
  assert(concatgen.generate() == 30);

  auto v1 = gen::make_stepper_gen().take(5).to_vector();
  std::vector<int> v2 { 0, 1, 2, 3, 4 };
  assert(v1 == v2);

  std::cout << "All assertions satisfied\n";
}

void triangle()
{
  auto triangle_gen =
    gen::make_inorder_gen({1,2,3,4,5,6,7,8,9,10,9,8,7,6,5,4,3,2,1})
        .concat_map([](int i) {
              std::cout << "\n";
              return gen::make_stepper_gen(1, i);
            });

  try {
    while(true)
      std::cout << triangle_gen.generate();
  }
  catch(std::out_of_range &) {
  }
}

int main(void)
{
  test_generators();
  triangle();
}
<commit_msg>monad laws<commit_after>#include <iostream>
#include <fstream>
//#include <boost/archive/text_oarchive.hpp>
//#include <boost/archive/text_iarchive.hpp>

#include "generator.h"
#include "type_generator.h"
//#include "serialize_tuple.h"

#ifndef RANDOM_SEED
  #define RANDOM_SEED 0xAC0
#endif

// Clang requires forward declarations for overloaded < operators.
// g++5 does not. Who's correct?

template <class... Args>
std::ostream & operator << (std::ostream & o, const std::tuple<Args...> & tuple);

template <class T>
std::ostream & operator << (std::ostream & o, const std::vector<T> & vector);

template <class T>
std::ostream & operator << (std::ostream & o, const boost::optional<T> & opt);

template <class T, class U>
std::ostream & operator << (std::ostream & o, const std::pair<T, U> & pair);

template <class T, size_t N>
std::ostream & operator << (std::ostream & o, const std::array<T, N> & arr)
{
  for (auto & elem : arr)
    o << elem;

  return o << "\n";
}

template <class T>
std::ostream & operator << (std::ostream & o, const std::vector<T> & vector)
{
  for (const auto & elem : vector)
    o << elem << " ";

  return o;
}

template <class T>
std::ostream & operator << (std::ostream & o, const boost::optional<T> & opt)
{
  if (opt)
    o << opt.get();

  return o;
}

template <class T, class U>
std::ostream & operator << (std::ostream & o, const std::pair<T, U> & pair)
{
  o << "pair.first = " << pair.first << "\n"
    << "pair.second = " << pair.second;

  return o;
}

template <class Tuple, size_t Size>
struct TuplePrinter
{
  static void print(std::ostream & o, const Tuple & tuple)
  {
    TuplePrinter<Tuple, Size-1>::print(o, tuple);
    o << std::get<Size-1>(tuple) << " ";
  }
};

template <class Tuple>
struct TuplePrinter<Tuple, 1>
{
  static void print(std::ostream & o, const Tuple & tuple)
  {
    o << std::get<0>(tuple) << " ";
  }
};

template <class Tuple>
struct TuplePrinter<Tuple, 0>
{
  static void print(std::ostream &, const Tuple &)
  {
    // no-op
  }
};

template <class... Args>
std::ostream & operator << (std::ostream & o, const std::tuple<Args...> & tuple)
{
  TuplePrinter<std::tuple<Args...>, sizeof...(Args)>::print(o, tuple);
  return o;
}

struct ShapeType
{
  int x, y, shapesize;
  std::string color;
};

std::ostream & operator << (std::ostream & o, const ShapeType & shape)
{
  o << "shape.x = "         << shape.x << "\n"
    << "shape.y = "         << shape.y << "\n"
    << "shape.shapesize = " << shape.shapesize << "\n"
    << "shape.color = "     << shape.color << "\n";

  return o;
}

auto test_shape_gen()
{
  auto xgen = gen::make_range_gen(0, 200);
  auto ygen = gen::make_range_gen(0, 200);
  auto sizegen = gen::make_constant_gen(30);
  auto colorgen = gen::make_oneof_gen({ "RED", "GREEN", "BLUE" });

  auto shapegen =
    gen::make_zip_gen(
      [](int x, int y, int size, const char * color) {
          return ShapeType { x, y, size, color };
      }, xgen, ygen, sizegen, colorgen);

  std::cout << shapegen.generate() << "\n";

  return shapegen;
}

void test_generators(void)
{
  gen::initialize();

  auto strgen =
    gen::make_string_gen(gen::make_printable_gen());

  std::cout << "size of strgen = " << sizeof(strgen) << "\n"
            << "string = " << strgen.generate() << "\n";

  auto vecgen =
    //gen::make_seq_gen<std::vector>(gen::GenFactory<int>::make(), 5, true);
    gen::GenFactory<std::vector<int>>::make(gen::GenFactory<int>::make(), 5, true);

  std::cout << "vector = " << vecgen.generate() << "\n";

  auto optgen = gen::make_optional_gen(strgen);
  std::cout << "optional string = " << optgen.generate() << "\n";

  auto pairgen = gen::make_pair_gen(strgen, vecgen);
  std::cout << pairgen.generate() << "\n";

  auto tuplegen = gen::make_composed_gen(strgen, vecgen);
  std::cout << tuplegen.generate() << "\n";

  auto shapegen = test_shape_gen();

  auto arraygen = gen::make_array_gen(shapegen, gen::dim_list<2, 2>());
  std::cout << arraygen.generate() << "\n";

  auto inordergen =
    gen::make_inorder_gen({ 10, 20 });

  assert(inordergen.generate() == 10);
  assert(inordergen.generate() == 20);

  auto concatgen =
    gen::make_inorder_gen({ 10, 20 })
       .concat(gen::make_inorder_gen({ 30 }));

  assert(concatgen.generate() == 10);
  assert(concatgen.generate() == 20);
  assert(concatgen.generate() == 30);

  auto v1 = gen::make_stepper_gen().take(5).to_vector();
  std::vector<int> v2 { 0, 1, 2, 3, 4 };
  assert(v1 == v2);

  std::cout << "All assertions satisfied\n";
}

void triangle()
{
  auto triangle_gen =
    gen::make_inorder_gen({1,2,3,4,5,6,7,8,9,10,9,8,7,6,5,4,3,2,1})
        .concat_map([](int i) {
              std::cout << "\n";
              return gen::make_stepper_gen(1, i);
            });

  try {
    while(true)
      std::cout << triangle_gen.generate();
  }
  catch(std::out_of_range &) {
  }
}

template<class Gen1, class Gen2>
void is_same(Gen1 g1, Gen2 g2)
{
  assert(g1.to_vector() == g2.to_vector());
}

void monad_laws()
{
  auto f = [](int i) { return gen::make_stepper_gen(1, i); };
  auto g = [](int i) { return gen::make_stepper_gen(i, 1, -1); };
  auto M = gen::make_single_gen(300);

  // left identity
  is_same(M.concat_map(f), f(300));

  // right identity
  is_same(M.concat_map([](int i) {
            return gen::make_single_gen(i);
          }), M);

  // associativity
  is_same(M.concat_map(f).concat_map(g),
          M.concat_map([f,g](int i) mutable {
            return f(i).concat_map(g);
          }));
}

int main(void)
{
  test_generators();
  monad_laws();
  triangle();

  std::cout << "\n";
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2011-2013 ARM Limited
 * All rights reserved
 *
 * The license below extends only to copyright in the software and shall
 * not be construed as granting a license to any other intellectual
 * property including but not limited to intellectual property relating
 * to a hardware implementation of the functionality of the software
 * licensed hereunder.  You may use the software subject to the license
 * terms below provided that you ensure that this notice is replicated
 * unmodified and in its entirety in all distributions of the software,
 * modified or unmodified, in source code or in binary form.
 *
 * Copyright (c) 2002-2005 The Regents of The University of Michigan
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met: redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer;
 * redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution;
 * neither the name of the copyright holders nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * Authors: Ron Dreslinski
 *          Ali Saidi
 *          Andreas Hansson
 *          William Wang
 */

/**
 * @file
 * Declaration of a coherent bus.
 */

#ifndef __MEM_COHERENT_BUS_HH__
#define __MEM_COHERENT_BUS_HH__

#include "base/hashmap.hh"
#include "mem/bus.hh"
#include "params/CoherentBus.hh"

/**
 * A coherent bus connects a number of (potentially) snooping masters
 * and slaves, and routes the request and response packets based on
 * the address, and also forwards all requests to the snoopers and
 * deals with the snoop responses.
 *
 * The coherent bus can be used as a template for modelling QPI,
* HyperTransport, ACE and coherent OCP buses, and is typically used
 * for the L1-to-L2 buses and as the main system interconnect.
 * @sa  \ref gem5MemorySystem "gem5 Memory System"
 */
class CoherentBus : public BaseBus
{

  protected:

    /**
     * Declare the layers of this bus, one vector for requests, one
     * for responses, and one for snoop responses
     */
    typedef Layer<SlavePort,MasterPort> ReqLayer;
    typedef Layer<MasterPort,SlavePort> RespLayer;
    typedef Layer<SlavePort,MasterPort> SnoopLayer;
    std::vector<ReqLayer*> reqLayers;
    std::vector<RespLayer*> respLayers;
    std::vector<SnoopLayer*> snoopLayers;

    /**
     * Declaration of the coherent bus slave port type, one will be
     * instantiated for each of the master ports connecting to the
     * bus.
     */
    class CoherentBusSlavePort : public SlavePort
    {

      private:

        /** A reference to the bus to which this port belongs. */
        CoherentBus &bus;

      public:

        CoherentBusSlavePort(const std::string &_name,
                             CoherentBus &_bus, PortID _id)
            : SlavePort(_name, &_bus, _id), bus(_bus)
        { }

      protected:

        /**
         * When receiving a timing request, pass it to the bus.
         */
        virtual bool recvTimingReq(PacketPtr pkt)
        { return bus.recvTimingReq(pkt, id); }

        /**
         * When receiving a timing snoop response, pass it to the bus.
         */
        virtual bool recvTimingSnoopResp(PacketPtr pkt)
        { return bus.recvTimingSnoopResp(pkt, id); }

        /**
         * When receiving an atomic request, pass it to the bus.
         */
        virtual Tick recvAtomic(PacketPtr pkt)
        { return bus.recvAtomic(pkt, id); }

        /**
         * When receiving a functional request, pass it to the bus.
         */
        virtual void recvFunctional(PacketPtr pkt)
        { bus.recvFunctional(pkt, id); }

        /**
         * When receiving a retry, pass it to the bus.
         */
        virtual void recvRetry()
        { panic("Bus slave ports always succeed and should never retry.\n"); }

        /**
         * Return the union of all adress ranges seen by this bus.
         */
        virtual AddrRangeList getAddrRanges() const
        { return bus.getAddrRanges(); }

        /**
         * Get the maximum block size as seen by the bus.
         */
        virtual unsigned deviceBlockSize() const
        { return bus.deviceBlockSize(); }

    };

    /**
     * Declaration of the coherent bus master port type, one will be
     * instantiated for each of the slave interfaces connecting to the
     * bus.
     */
    class CoherentBusMasterPort : public MasterPort
    {
      private:
        /** A reference to the bus to which this port belongs. */
        CoherentBus &bus;

      public:

        CoherentBusMasterPort(const std::string &_name,
                              CoherentBus &_bus, PortID _id)
            : MasterPort(_name, &_bus, _id), bus(_bus)
        { }

      protected:

        /**
         * Determine if this port should be considered a snooper. For
         * a coherent bus master port this is always true.
         *
         * @return a boolean that is true if this port is snooping
         */
        virtual bool isSnooping() const
        { return true; }

        /**
         * When receiving a timing response, pass it to the bus.
         */
        virtual bool recvTimingResp(PacketPtr pkt)
        { return bus.recvTimingResp(pkt, id); }

        /**
         * When receiving a timing snoop request, pass it to the bus.
         */
        virtual void recvTimingSnoopReq(PacketPtr pkt)
        { return bus.recvTimingSnoopReq(pkt, id); }

        /**
         * When receiving an atomic snoop request, pass it to the bus.
         */
        virtual Tick recvAtomicSnoop(PacketPtr pkt)
        { return bus.recvAtomicSnoop(pkt, id); }

        /**
         * When receiving a functional snoop request, pass it to the bus.
         */
        virtual void recvFunctionalSnoop(PacketPtr pkt)
        { bus.recvFunctionalSnoop(pkt, id); }

        /** When reciving a range change from the peer port (at id),
            pass it to the bus. */
        virtual void recvRangeChange()
        { bus.recvRangeChange(id); }

        /** When reciving a retry from the peer port (at id),
            pass it to the bus. */
        virtual void recvRetry()
        { bus.recvRetry(id); }

        // Ask the bus to ask everyone on the bus what their block size is and
        // take the max of it. This might need to be changed a bit if we ever
        // support multiple block sizes.
        virtual unsigned deviceBlockSize() const
        { return bus.deviceBlockSize(); }

    };

    /**
     * Internal class to bridge between an incoming snoop response
     * from a slave port and forwarding it through an outgoing slave
     * port. It is effectively a dangling master port.
     */
    class SnoopRespPort : public MasterPort
    {

      private:

        /** The port which we mirror internally. */
        SlavePort& slavePort;

        /** The bus to which this port belongs. */
        CoherentBus &bus;

      public:

        /**
         * Create a snoop response port that mirrors a given slave port.
         */
        SnoopRespPort(SlavePort& slave_port, CoherentBus& _bus) :
            MasterPort(slave_port.name() + ".snoopRespPort", &_bus),
            slavePort(slave_port), bus(_bus) { }

        /**
         * Override the sending of retries and pass them on through
         * the mirrored slave port.
         */
        void sendRetry() {
            slavePort.sendRetry();
        }

        /**
         * Provided as necessary.
         */
        void recvRetry() { panic("SnoopRespPort should never see retry\n"); }

        /**
         * Provided as necessary.
         */
        bool recvTimingResp(PacketPtr pkt)
        {
            panic("SnoopRespPort should never see timing response\n");
            return false;
        }

    };

    std::vector<SnoopRespPort*> snoopRespPorts;

    std::vector<SlavePort*> snoopPorts;

    /**
     * Store the outstanding requests so we can determine which ones
     * we generated and which ones were merely forwarded. This is used
     * in the coherent bus when coherency responses come back.
     */
    m5::hash_set<RequestPtr> outstandingReq;

    /**
     * Keep a pointer to the system to be allow to querying memory system
     * properties.
     */
    System *system;

    /** Function called by the port when the bus is recieving a Timing
      request packet.*/
    virtual bool recvTimingReq(PacketPtr pkt, PortID slave_port_id);

    /** Function called by the port when the bus is recieving a Timing
      response packet.*/
    virtual bool recvTimingResp(PacketPtr pkt, PortID master_port_id);

    /** Function called by the port when the bus is recieving a timing
        snoop request.*/
    virtual void recvTimingSnoopReq(PacketPtr pkt, PortID master_port_id);

    /** Function called by the port when the bus is recieving a timing
        snoop response.*/
    virtual bool recvTimingSnoopResp(PacketPtr pkt, PortID slave_port_id);

    /** Timing function called by port when it is once again able to process
     * requests. */
    void recvRetry(PortID master_port_id);

    /**
     * Forward a timing packet to our snoopers, potentially excluding
     * one of the connected coherent masters to avoid sending a packet
     * back to where it came from.
     *
     * @param pkt Packet to forward
     * @param exclude_slave_port_id Id of slave port to exclude
     */
    void forwardTiming(PacketPtr pkt, PortID exclude_slave_port_id);

    /** Function called by the port when the bus is recieving a Atomic
      transaction.*/
    Tick recvAtomic(PacketPtr pkt, PortID slave_port_id);

    /** Function called by the port when the bus is recieving an
        atomic snoop transaction.*/
    Tick recvAtomicSnoop(PacketPtr pkt, PortID master_port_id);

    /**
     * Forward an atomic packet to our snoopers, potentially excluding
     * one of the connected coherent masters to avoid sending a packet
     * back to where it came from.
     *
     * @param pkt Packet to forward
     * @param exclude_slave_port_id Id of slave port to exclude
     *
     * @return a pair containing the snoop response and snoop latency
     */
    std::pair<MemCmd, Tick> forwardAtomic(PacketPtr pkt,
                                          PortID exclude_slave_port_id);

    /** Function called by the port when the bus is recieving a Functional
        transaction.*/
    void recvFunctional(PacketPtr pkt, PortID slave_port_id);

    /** Function called by the port when the bus is recieving a functional
        snoop transaction.*/
    void recvFunctionalSnoop(PacketPtr pkt, PortID master_port_id);

    /**
     * Forward a functional packet to our snoopers, potentially
     * excluding one of the connected coherent masters to avoid
     * sending a packet back to where it came from.
     *
     * @param pkt Packet to forward
     * @param exclude_slave_port_id Id of slave port to exclude
     */
    void forwardFunctional(PacketPtr pkt, PortID exclude_slave_port_id);

    Stats::Scalar dataThroughBus;
    Stats::Scalar snoopDataThroughBus;

  public:

    virtual void init();

    CoherentBus(const CoherentBusParams *p);

    virtual ~CoherentBus();

    unsigned int drain(DrainManager *dm);

    virtual void regStats();
};

#endif //__MEM_COHERENT_BUS_HH__
<commit_msg>mem: Remove CoherentBus snoop port unused private member<commit_after>/*
 * Copyright (c) 2011-2013 ARM Limited
 * All rights reserved
 *
 * The license below extends only to copyright in the software and shall
 * not be construed as granting a license to any other intellectual
 * property including but not limited to intellectual property relating
 * to a hardware implementation of the functionality of the software
 * licensed hereunder.  You may use the software subject to the license
 * terms below provided that you ensure that this notice is replicated
 * unmodified and in its entirety in all distributions of the software,
 * modified or unmodified, in source code or in binary form.
 *
 * Copyright (c) 2002-2005 The Regents of The University of Michigan
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met: redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer;
 * redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution;
 * neither the name of the copyright holders nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * Authors: Ron Dreslinski
 *          Ali Saidi
 *          Andreas Hansson
 *          William Wang
 */

/**
 * @file
 * Declaration of a coherent bus.
 */

#ifndef __MEM_COHERENT_BUS_HH__
#define __MEM_COHERENT_BUS_HH__

#include "base/hashmap.hh"
#include "mem/bus.hh"
#include "params/CoherentBus.hh"

/**
 * A coherent bus connects a number of (potentially) snooping masters
 * and slaves, and routes the request and response packets based on
 * the address, and also forwards all requests to the snoopers and
 * deals with the snoop responses.
 *
 * The coherent bus can be used as a template for modelling QPI,
* HyperTransport, ACE and coherent OCP buses, and is typically used
 * for the L1-to-L2 buses and as the main system interconnect.
 * @sa  \ref gem5MemorySystem "gem5 Memory System"
 */
class CoherentBus : public BaseBus
{

  protected:

    /**
     * Declare the layers of this bus, one vector for requests, one
     * for responses, and one for snoop responses
     */
    typedef Layer<SlavePort,MasterPort> ReqLayer;
    typedef Layer<MasterPort,SlavePort> RespLayer;
    typedef Layer<SlavePort,MasterPort> SnoopLayer;
    std::vector<ReqLayer*> reqLayers;
    std::vector<RespLayer*> respLayers;
    std::vector<SnoopLayer*> snoopLayers;

    /**
     * Declaration of the coherent bus slave port type, one will be
     * instantiated for each of the master ports connecting to the
     * bus.
     */
    class CoherentBusSlavePort : public SlavePort
    {

      private:

        /** A reference to the bus to which this port belongs. */
        CoherentBus &bus;

      public:

        CoherentBusSlavePort(const std::string &_name,
                             CoherentBus &_bus, PortID _id)
            : SlavePort(_name, &_bus, _id), bus(_bus)
        { }

      protected:

        /**
         * When receiving a timing request, pass it to the bus.
         */
        virtual bool recvTimingReq(PacketPtr pkt)
        { return bus.recvTimingReq(pkt, id); }

        /**
         * When receiving a timing snoop response, pass it to the bus.
         */
        virtual bool recvTimingSnoopResp(PacketPtr pkt)
        { return bus.recvTimingSnoopResp(pkt, id); }

        /**
         * When receiving an atomic request, pass it to the bus.
         */
        virtual Tick recvAtomic(PacketPtr pkt)
        { return bus.recvAtomic(pkt, id); }

        /**
         * When receiving a functional request, pass it to the bus.
         */
        virtual void recvFunctional(PacketPtr pkt)
        { bus.recvFunctional(pkt, id); }

        /**
         * When receiving a retry, pass it to the bus.
         */
        virtual void recvRetry()
        { panic("Bus slave ports always succeed and should never retry.\n"); }

        /**
         * Return the union of all adress ranges seen by this bus.
         */
        virtual AddrRangeList getAddrRanges() const
        { return bus.getAddrRanges(); }

        /**
         * Get the maximum block size as seen by the bus.
         */
        virtual unsigned deviceBlockSize() const
        { return bus.deviceBlockSize(); }

    };

    /**
     * Declaration of the coherent bus master port type, one will be
     * instantiated for each of the slave interfaces connecting to the
     * bus.
     */
    class CoherentBusMasterPort : public MasterPort
    {
      private:
        /** A reference to the bus to which this port belongs. */
        CoherentBus &bus;

      public:

        CoherentBusMasterPort(const std::string &_name,
                              CoherentBus &_bus, PortID _id)
            : MasterPort(_name, &_bus, _id), bus(_bus)
        { }

      protected:

        /**
         * Determine if this port should be considered a snooper. For
         * a coherent bus master port this is always true.
         *
         * @return a boolean that is true if this port is snooping
         */
        virtual bool isSnooping() const
        { return true; }

        /**
         * When receiving a timing response, pass it to the bus.
         */
        virtual bool recvTimingResp(PacketPtr pkt)
        { return bus.recvTimingResp(pkt, id); }

        /**
         * When receiving a timing snoop request, pass it to the bus.
         */
        virtual void recvTimingSnoopReq(PacketPtr pkt)
        { return bus.recvTimingSnoopReq(pkt, id); }

        /**
         * When receiving an atomic snoop request, pass it to the bus.
         */
        virtual Tick recvAtomicSnoop(PacketPtr pkt)
        { return bus.recvAtomicSnoop(pkt, id); }

        /**
         * When receiving a functional snoop request, pass it to the bus.
         */
        virtual void recvFunctionalSnoop(PacketPtr pkt)
        { bus.recvFunctionalSnoop(pkt, id); }

        /** When reciving a range change from the peer port (at id),
            pass it to the bus. */
        virtual void recvRangeChange()
        { bus.recvRangeChange(id); }

        /** When reciving a retry from the peer port (at id),
            pass it to the bus. */
        virtual void recvRetry()
        { bus.recvRetry(id); }

        // Ask the bus to ask everyone on the bus what their block size is and
        // take the max of it. This might need to be changed a bit if we ever
        // support multiple block sizes.
        virtual unsigned deviceBlockSize() const
        { return bus.deviceBlockSize(); }

    };

    /**
     * Internal class to bridge between an incoming snoop response
     * from a slave port and forwarding it through an outgoing slave
     * port. It is effectively a dangling master port.
     */
    class SnoopRespPort : public MasterPort
    {

      private:

        /** The port which we mirror internally. */
        SlavePort& slavePort;

      public:

        /**
         * Create a snoop response port that mirrors a given slave port.
         */
        SnoopRespPort(SlavePort& slave_port, CoherentBus& _bus) :
            MasterPort(slave_port.name() + ".snoopRespPort", &_bus),
            slavePort(slave_port) { }

        /**
         * Override the sending of retries and pass them on through
         * the mirrored slave port.
         */
        void sendRetry() {
            slavePort.sendRetry();
        }

        /**
         * Provided as necessary.
         */
        void recvRetry() { panic("SnoopRespPort should never see retry\n"); }

        /**
         * Provided as necessary.
         */
        bool recvTimingResp(PacketPtr pkt)
        {
            panic("SnoopRespPort should never see timing response\n");
            return false;
        }

    };

    std::vector<SnoopRespPort*> snoopRespPorts;

    std::vector<SlavePort*> snoopPorts;

    /**
     * Store the outstanding requests so we can determine which ones
     * we generated and which ones were merely forwarded. This is used
     * in the coherent bus when coherency responses come back.
     */
    m5::hash_set<RequestPtr> outstandingReq;

    /**
     * Keep a pointer to the system to be allow to querying memory system
     * properties.
     */
    System *system;

    /** Function called by the port when the bus is recieving a Timing
      request packet.*/
    virtual bool recvTimingReq(PacketPtr pkt, PortID slave_port_id);

    /** Function called by the port when the bus is recieving a Timing
      response packet.*/
    virtual bool recvTimingResp(PacketPtr pkt, PortID master_port_id);

    /** Function called by the port when the bus is recieving a timing
        snoop request.*/
    virtual void recvTimingSnoopReq(PacketPtr pkt, PortID master_port_id);

    /** Function called by the port when the bus is recieving a timing
        snoop response.*/
    virtual bool recvTimingSnoopResp(PacketPtr pkt, PortID slave_port_id);

    /** Timing function called by port when it is once again able to process
     * requests. */
    void recvRetry(PortID master_port_id);

    /**
     * Forward a timing packet to our snoopers, potentially excluding
     * one of the connected coherent masters to avoid sending a packet
     * back to where it came from.
     *
     * @param pkt Packet to forward
     * @param exclude_slave_port_id Id of slave port to exclude
     */
    void forwardTiming(PacketPtr pkt, PortID exclude_slave_port_id);

    /** Function called by the port when the bus is recieving a Atomic
      transaction.*/
    Tick recvAtomic(PacketPtr pkt, PortID slave_port_id);

    /** Function called by the port when the bus is recieving an
        atomic snoop transaction.*/
    Tick recvAtomicSnoop(PacketPtr pkt, PortID master_port_id);

    /**
     * Forward an atomic packet to our snoopers, potentially excluding
     * one of the connected coherent masters to avoid sending a packet
     * back to where it came from.
     *
     * @param pkt Packet to forward
     * @param exclude_slave_port_id Id of slave port to exclude
     *
     * @return a pair containing the snoop response and snoop latency
     */
    std::pair<MemCmd, Tick> forwardAtomic(PacketPtr pkt,
                                          PortID exclude_slave_port_id);

    /** Function called by the port when the bus is recieving a Functional
        transaction.*/
    void recvFunctional(PacketPtr pkt, PortID slave_port_id);

    /** Function called by the port when the bus is recieving a functional
        snoop transaction.*/
    void recvFunctionalSnoop(PacketPtr pkt, PortID master_port_id);

    /**
     * Forward a functional packet to our snoopers, potentially
     * excluding one of the connected coherent masters to avoid
     * sending a packet back to where it came from.
     *
     * @param pkt Packet to forward
     * @param exclude_slave_port_id Id of slave port to exclude
     */
    void forwardFunctional(PacketPtr pkt, PortID exclude_slave_port_id);

    Stats::Scalar dataThroughBus;
    Stats::Scalar snoopDataThroughBus;

  public:

    virtual void init();

    CoherentBus(const CoherentBusParams *p);

    virtual ~CoherentBus();

    unsigned int drain(DrainManager *dm);

    virtual void regStats();
};

#endif //__MEM_COHERENT_BUS_HH__
<|endoftext|>